/* * BIRD -- Wireguard Protocol Configuration * * (c) 1999 Martin Mares * * 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 bytestring *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 allowed_ip allowed_ips %type 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