From 7b42938143dc02a085a5a63c7d4aa310a6695895 Mon Sep 17 00:00:00 2001 From: Mikael Magnusson Date: Thu, 28 Feb 2019 00:44:40 +0100 Subject: Wireguard: Initial commit --- configure.ac | 3 +- nest/proto.c | 3 + nest/protocol.h | 4 +- nest/route.h | 11 +++ proto/wireguard/Makefile | 8 ++ proto/wireguard/config.Y | 48 ++++++++++ proto/wireguard/wireguard.c | 222 ++++++++++++++++++++++++++++++++++++++++++++ proto/wireguard/wireguard.h | 22 +++++ 8 files changed, 319 insertions(+), 2 deletions(-) create mode 100644 proto/wireguard/Makefile create mode 100644 proto/wireguard/config.Y create mode 100644 proto/wireguard/wireguard.c create mode 100644 proto/wireguard/wireguard.h diff --git a/configure.ac b/configure.ac index da1a8f44..d219b274 100644 --- a/configure.ac +++ b/configure.ac @@ -271,7 +271,7 @@ if test "$enable_mpls_kernel" != no ; then fi fi -all_protocols="$proto_bfd babel bgp mrt ospf perf pipe radv rip $proto_rpki static" +all_protocols="$proto_bfd babel bgp mrt ospf perf pipe radv rip $proto_rpki static wireguard" all_protocols=`echo $all_protocols | sed 's/ /,/g'` @@ -289,6 +289,7 @@ AH_TEMPLATE([CONFIG_RADV], [RAdv protocol]) AH_TEMPLATE([CONFIG_RIP], [RIP protocol]) AH_TEMPLATE([CONFIG_RPKI], [RPKI protocol]) AH_TEMPLATE([CONFIG_STATIC], [Static protocol]) +AH_TEMPLATE([CONFIG_WIREGUARD], [Wireguard protocol]) AC_MSG_CHECKING([protocols]) protocols=`echo "$with_protocols" | sed 's/,/ /g'` diff --git a/nest/proto.c b/nest/proto.c index d4a333d0..ccde5d9d 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -1382,6 +1382,9 @@ protos_build(void) #ifdef CONFIG_PERF proto_build(&proto_perf); #endif +#ifdef CONFIG_WIREGUARD + proto_build(&proto_wireguard); +#endif proto_pool = rp_new(&root_pool, "Protocols"); proto_shutdown_timer = tm_new(proto_pool); diff --git a/nest/protocol.h b/nest/protocol.h index 6c04071b..1fdfb380 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -53,6 +53,7 @@ enum protocol_class { PROTOCOL_RIP, PROTOCOL_RPKI, PROTOCOL_STATIC, + PROTOCOL_WG, PROTOCOL__MAX }; @@ -102,7 +103,8 @@ void protos_dump_all(void); extern struct protocol proto_device, proto_radv, proto_rip, proto_static, proto_mrt, proto_ospf, proto_perf, - proto_pipe, proto_bgp, proto_bfd, proto_babel, proto_rpki; + proto_pipe, proto_bgp, proto_bfd, proto_babel, proto_rpki, + proto_wireguard; /* * Routing Protocol Instance diff --git a/nest/route.h b/nest/route.h index 8dfbb376..ad89e4b2 100644 --- a/nest/route.h +++ b/nest/route.h @@ -13,6 +13,10 @@ #include "lib/resource.h" #include "lib/net.h" +#ifdef CONFIG_WIREGUARD +# include "sysdep/linux/wireguard.h" +#endif /* CONFIG_WIREGUARD */ + struct ea_list; struct protocol; struct proto; @@ -203,6 +207,13 @@ struct hostentry { byte dest; /* Chosen route destination type (RTD_...) */ byte nexthop_linkable; /* Nexthop list is completely non-device */ u32 igp_metric; /* Chosen route IGP metric */ +#ifdef CONFIG_WIREGUARD + union { + struct { + wg_key pub_key; + } wg; + } u; +#endif }; typedef struct rte { diff --git a/proto/wireguard/Makefile b/proto/wireguard/Makefile new file mode 100644 index 00000000..26a7970f --- /dev/null +++ b/proto/wireguard/Makefile @@ -0,0 +1,8 @@ +WG := $(srcdir)/../WireGuard/contrib/examples/embeddable-wg-library + +src := wireguard.c +obj := $(src-o-files) +$(all-daemon) +$(cf-local) + +tests_objs := $(tests_objs) $(src-o-files) diff --git a/proto/wireguard/config.Y b/proto/wireguard/config.Y new file mode 100644 index 00000000..dfe621bd --- /dev/null +++ b/proto/wireguard/config.Y @@ -0,0 +1,48 @@ +/* + * BIRD -- Wireguard Protocol Configuration + * + * (c) 1999 Martin Mares + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +CF_HDR + +#include "proto/wireguard/wireguard.h" + +CF_DEFINES + +#define WG_CFG ((struct wg_config *) this_proto) + +CF_DECLS + +CF_KEYWORDS(WIREGUARD, PEERS) + +CF_GRAMMAR + +proto: wireguard_proto '}' ; + +wireguard_proto_start: proto_start WIREGUARD { + this_proto = proto_config_new(&proto_wireguard, $1); + } + ; + +wireguard_proto: + wireguard_proto_start proto_name '{' + | wireguard_proto proto_channel ';' { this_proto->net_type = $2->net_type; } + | wireguard_proto proto_item ';' + | wireguard_proto INTERFACE TEXT ';' { WG_CFG->ifname = $3; } + | wireguard_proto PEERS '{' peers '}' + ; + +peers: + /* empty */ + | peers peer + +peer: ipa pubkey ';' + +pubkey: TEXT + +CF_CODE + +CF_END diff --git a/proto/wireguard/wireguard.c b/proto/wireguard/wireguard.c new file mode 100644 index 00000000..f45796d5 --- /dev/null +++ b/proto/wireguard/wireguard.c @@ -0,0 +1,222 @@ +// Based on proto/rip/rip.c + +#include +#include "nest/protocol.h" +#include "nest/iface.h" +#include "sysdep/linux/wireguard.h" +#include "wireguard.h" +#include "proto/bgp/bgp.h" + +static void +wg_init_entry(void *e_) +{ + struct wg_entry *e = e_; +// debug("wg_init_entry\n"); +} + +static void +wg_postconfig(struct proto_config *C) +{ + C; + debug("postconfig\n"); +} + +static void +wg_if_notify(struct proto *P, unsigned flags, struct iface *i) +{ + struct wg_proto *p = (struct wg_proto *) P; + struct wg_config *c = P->cf; + + debug("WG: if_notify %p %s %d %s\n", i, i->name, flags, c->ifname); + if (c->ifname && !strcmp(i->name, c->ifname)) { + debug("WG: found ifname\n"); + p->iface = i; + } +} + +static void +wg_rt_notify(struct proto *P, rtable *src_table, net *n, + rte *new, rte *old, ea_list *attrs) +{ + struct wg_proto *p = (struct wg_proto *) P; + struct wg_entry *en; + struct iface *iface = NULL; + const char *ifname = NULL; + +// debug("WG: notify\n"); + + if (new) { + iface = new->attrs->nh.iface; + ifname = iface ? iface->name : NULL; + + if (iface && iface == p->iface) { + struct eattr *t; + + debug("WG: found iface\n"); + en = fib_get(&p->rtable, n->n.addr); + + debug("WG: notify new %d %N\n", + new->attrs->dest, n->n.addr); + + t = ea_find(new->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_TUNNEL_ENCAP)); + if (t) { + log(L_TRACE "WG: Attr %x %x", t->flags, t->type); +/* + struct sub_tlv_remove_endpoint { + u32 asn; + u8 address_family; + union { + ip4_addr ip4; + ip6_addr ip6; + }; + }; + + struct sub_tlv_udp_dest_port { + u16 port; + }; + + struct sub_tlv_wireguard { + u8 pubkey[32]; + }; + + struct sub_tlv { + u8 type; + union { + struct { + u8 length; + struct sub_tlv_value value[]; + } s8; + struct { + u16 length; + struct sub_tlv_value value[]; + } s16; + } u; + }; + + struct bgp_tunnel_encap_attr { + u16 type; + u16 length; + struct sub_tlv stlv[]; + }; +*/ + } else { + log(L_TRACE "WG: No Attr"); + } + + // old_metric = en->valid ? en->metric : -1; + +// en->valid = RIP_ENTRY_VALID; +// en->metric = rt_metric; +// en->tag = rt_tag; +// en->from = (new->attrs->src->proto == P) ? new->u.rip.from : NULL; +// en->iface = new->attrs->iface; +// en->next_hop = new->attrs->gw; + } + + } else { + debug("WG: notify withdraw\n"); + + /* Withdraw */ + en = fib_find(&p->rtable, n->n.addr); + + if (!en) // || en->valid != RIP_ENTRY_VALID) + return; + +/* + old_metric = en->metric; + + en->valid = RIP_ENTRY_STALE; + en->metric = p->infinity; + en->tag = 0; + en->from = NULL; + en->iface = NULL; + en->next_hop = IPA_NONE; +*/ + } + +// TRACE(D_EVENTS, "wg notify %s %s", src_table->name, ifname?ifname:"(null)"); +} + +static int +wg_reload_routes(struct proto *P) +{ + struct wg_proto *p = (struct wg_proto *) P; + + debug("reload routes\n"); + +// TODO +// WALK_LIST(c, p->channels) +// channel_request_feeding(c); + + return 1; +} + + +static struct proto * +wg_init(struct proto_config *C) +{ + struct wg_config *c = (struct pipe_config *) C; + struct proto *P = proto_new(C); + struct wg_proto *p = (struct wg_proto *) P; + + debug("init\n"); + + P->main_channel = proto_add_channel(P, proto_cf_main_channel(C)); + + P->if_notify = wg_if_notify; + P->rt_notify = wg_rt_notify; + P->reload_routes = wg_reload_routes; +// P->accept_ra_types = RA_ANY; + + return P; +} + + +static int +wg_start(struct proto *P) +{ + struct wg_config *cf = (struct wg_config *) P->cf; + struct wg_proto *p = (struct wg_proto *) P; + + debug("start\n"); + fib_init(&p->rtable, P->pool, P->net_type, sizeof(struct wg_entry), + OFFSETOF(struct wg_entry, n), 0, wg_init_entry); + return PS_UP; +} + +static void +wg_dump(struct proto *P) +{ + struct wg_proto *p = (struct wg_proto *) P; + int i; + + i = 0; + FIB_WALK(&p->rtable, struct wg_entry, en) + { +// struct wg_entry *en = (struct wg_entry *) e; + debug("WG: entry #%d:\n", + i++); + } + FIB_WALK_END; +} + + +struct protocol proto_wireguard = { + .name = "Wireguard", + .template = "wg%d", + .class = PROTOCOL_WG, + .channel_mask = NB_ANY, + .proto_size = sizeof(struct wg_proto), + .config_size = sizeof(struct wg_config), + .postconfig = wg_postconfig, + .init = wg_init, + .start = wg_start, + .dump = wg_dump, +/* .multitable = 1, + .preference = DEF_PREF_PIPE, + .cleanup = wg_cleanup, + .reconfigure = wg_reconfigure, + .copy_config = wg_copy_config, + .get_status = wg_get_status, + .show_proto_info = wg_show_proto_info*/ +}; diff --git a/proto/wireguard/wireguard.h b/proto/wireguard/wireguard.h new file mode 100644 index 00000000..992bb12b --- /dev/null +++ b/proto/wireguard/wireguard.h @@ -0,0 +1,22 @@ +#ifndef _BIRD_WIREGUARD_H +#define _BIRD_WIREGUARD_H + +#include "nest/protocol.h" + +struct wg_config { + struct proto_config c; + const char *ifname; +}; + +struct wg_proto { + struct proto p; + struct fib rtable; + struct iface *iface; +}; + +struct wg_entry { + struct fib_node n; +}; + + +#endif /* _BIRD_WIREGUARD_H */ -- cgit v1.2.3