summaryrefslogtreecommitdiff
path: root/proto/wireguard/config.Y
diff options
context:
space:
mode:
Diffstat (limited to 'proto/wireguard/config.Y')
-rw-r--r--proto/wireguard/config.Y191
1 files changed, 191 insertions, 0 deletions
diff --git a/proto/wireguard/config.Y b/proto/wireguard/config.Y
new file mode 100644
index 00000000..0fae832a
--- /dev/null
+++ b/proto/wireguard/config.Y
@@ -0,0 +1,191 @@
+/*
+ * BIRD -- Wireguard Protocol Configuration
+ *
+ * (c) 1999 Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+CF_HDR
+
+#define LOCAL_DEBUG
+#include "proto/wireguard/wireguard.h"
+
+CF_DEFINES
+
+#define WG_DEFAULT_TUNNEL_TYPE 51820
+
+#define WG_CFG ((struct wg_config *) this_proto)
+
+static struct peer_config *this_peer = NULL;
+
+typedef char wg_key_b64_string[45];
+int wg_key_from_base64(u8 key[32], const wg_key_b64_string base64);
+
+static struct f_tree *
+f_new_sub_tlv_wg(u32 type, const struct adata *bs)
+{
+ struct f_tree *t = f_new_tree();
+ t->right = t;
+ t->from.type = t->to.type = T_SUBTLV;
+ struct te_subtlv v;
+ v.type = TLV_ENCAPSULATION;
+ v.u.tunnel_encap.type = type;
+ v.u.tunnel_encap.data = NULL;
+ v.u.tunnel_encap.length = 0;
+ if (bs && bs->length == sizeof(wg_key))
+ {
+#if 1
+ // encap type 0
+ v.u.tunnel_encap.data = bs->data;
+ v.u.tunnel_encap.length = bs->length;
+#else
+ // encap type 1
+ v.u.tunnel_encap.length = 4 + bs->length;
+ void *data = cfg_alloc(v.u.tunnel_encap.length);
+ memset(data, 0, 4);
+ memcpy(data + 4, bs->data, bs->length);
+ v.u.tunnel_encap.data = data;
+#endif
+ }
+ else if (bs)
+ {
+ cf_error( "Invalid WireGuard key" );
+ }
+ t->from.val.st = v;
+ t->to.val.st = v;
+ return t;
+}
+
+CF_DECLS
+
+%type <g> allowed_ip allowed_ips
+%type <bs> wg_key
+
+CF_KEYWORDS(WIREGUARD, TUNNEL_TYPE, PRIVATE_KEY, LISTEN_PORT, PUBLIC_KEY, ENDPOINT, ALLOWED_IPS)
+
+CF_GRAMMAR
+
+proto: wireguard_proto '}' ;
+
+sub_tlv_item:
+ '(' WIREGUARD ',' wg_key ')' { $$ = f_new_sub_tlv_wg(WG_DEFAULT_TUNNEL_TYPE, $4); }
+ | '(' WIREGUARD ',' cnum ',' wg_key ')' { $$ = f_new_sub_tlv_wg($4, $6); }
+ ;
+
+wireguard_proto_start: proto_start WIREGUARD {
+ this_proto = proto_config_new(&proto_wireguard, $1);
+ init_list(&WG_CFG->peers);
+ WG_CFG->tunnel_type = WG_DEFAULT_TUNNEL_TYPE;
+ }
+ ;
+
+wireguard_proto:
+ wireguard_proto_start proto_name '{'
+ | wireguard_proto wg_proto_channel ';'
+ | wireguard_proto proto_item ';'
+ | wireguard_proto TUNNEL_TYPE tunnel_type ';'
+ | wireguard_proto INTERFACE TEXT ';' { WG_CFG->ifname = $3; }
+ | wireguard_proto PRIVATE_KEY private_key ';'
+ | wireguard_proto LISTEN_PORT listen_port ';'
+ | wireguard_proto wg_peer ';'
+ ;
+
+wg_peer: wg_peer_start wg_peer_opt_list wg_peer_end;
+
+wg_peer_start: PEER { this_peer = peer_new(WG_CFG); }
+
+wg_peer_end: {
+ this_peer = NULL;
+}
+ ;
+
+wg_peer_item:
+ PUBLIC_KEY public_key
+ | ENDPOINT endpoint
+ | PORT port
+ | ALLOWED_IPS allowed_ips { this_peer->allowedips = $2; }
+ ;
+
+wg_peer_opts:
+ /* empty */
+ | wg_peer_opts wg_peer_item ';'
+ ;
+
+wg_peer_opt_list:
+ '{' wg_peer_opts '}'
+ ;
+
+tunnel_type: expr { WG_CFG->tunnel_type = $1; }
+
+private_key: wg_key { WG_CFG->private_key = $1->data; }
+
+listen_port: expr { WG_CFG->listen_port = $1; }
+
+public_key: wg_key { this_peer->public_key = $1->data; }
+
+endpoint: ipa { this_peer->endpoint = $1; }
+
+port: expr { this_peer->remote_port = $1; }
+
+allowed_ips: allowed_ip {
+ struct wg_allowedips *aips = cfg_alloc(sizeof(struct wg_allowedips));
+ aips->first_allowedip = $1;
+ aips->last_allowedip = $1;
+ $$ = aips;
+ }
+ | allowed_ips ',' allowed_ip {
+ struct wg_allowedips *aips = $1;
+ struct wg_allowedip *aip = $3;
+ aips->last_allowedip->next_allowedip = aip;
+ aips->last_allowedip = aip;
+ $$ = aips;
+ }
+ ;
+
+allowed_ip:
+ net_or_ipa {
+ struct wg_allowedip *aip = cfg_alloc(sizeof(struct wg_allowedip));
+ switch ($1.type)
+ {
+ case NET_IP4:
+ aip->family = AF_INET;
+ aip->ip4 = ipa_to_in4(net_prefix(&($1)));
+ aip->cidr = net_pxlen(&($1));
+ break;
+ case NET_IP6:
+ aip->family = AF_INET6;
+ aip->ip6 = ipa_to_in6(net_prefix(&($1)));
+ aip->cidr = net_pxlen(&($1));
+ break;
+ default:
+ cf_error( "Unknown net type: %d", $1.type );
+ }
+
+ aip->next_allowedip = NULL;
+ $$ = aip;
+ }
+ ;
+
+wg_proto_channel: wg_channel_start channel_opt_list wg_channel_end;
+
+wg_channel_start: net_type
+{
+ this_channel = channel_config_get(&channel_wg, net_label[$1], $1, this_proto);
+}
+
+wg_channel_end:
+{
+ this_channel = NULL;
+}
+
+wg_key: bytestring
+{
+ if ($1->length != sizeof(wg_key))
+ cf_error( "Invalid WireGuard key" );
+ $$ = $1;
+}
+
+CF_CODE
+
+CF_END