diff options
Diffstat (limited to 'proto/wireguard/config.Y')
-rw-r--r-- | proto/wireguard/config.Y | 191 |
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 |