diff options
-rw-r--r-- | proto/wireguard/wireguard.c | 96 |
1 files changed, 89 insertions, 7 deletions
diff --git a/proto/wireguard/wireguard.c b/proto/wireguard/wireguard.c index feea9682..92b1171b 100644 --- a/proto/wireguard/wireguard.c +++ b/proto/wireguard/wireguard.c @@ -1,5 +1,7 @@ // Based on proto/rip/rip.c +#define LOCAL_DEBUG + #include <stdio.h> #include <stdlib.h> #include <sys/stat.h> @@ -9,6 +11,7 @@ #include "lib/lists.h" #include "lib/ip.h" #include "lib/tunnel_encaps.h" +#include "nest/bfd.h" #include "nest/protocol.h" #include "nest/iface.h" #include "sysdep/linux/wireguard.h" @@ -16,6 +19,8 @@ #include "sysdep/unix/wg_user.h" #include "wireguard.h" +#define BA_NEXT_HOP 0x03 + static ip_addr allowedip_to_ipa(struct wg_allowedip *allowedip); static @@ -36,7 +41,7 @@ int get_device(struct wg_proto *p, wg_device **pdev, const char *device_name) wg_device *dev = calloc(1, sizeof(wg_device)); strncpy(dev->name, device_name, sizeof(dev->name)); - dev->flags = WGDEVICE_REPLACE_PEERS; +// dev->flags = WGDEVICE_REPLACE_PEERS; if (c->private_key) { dev->flags |= WGDEVICE_HAS_PRIVATE_KEY | WGDEVICE_HAS_PUBLIC_KEY; @@ -278,13 +283,42 @@ init_allowed_ip(struct wg_allowedip *allowedip, u8 net_type, struct network *n) allowedip->cidr = net_pxlen(n->n.addr); } -static int -add_allowed_ip(u8 net_type, struct network *n, wg_peer *peer) +static struct wg_allowedip * +create_allowed_ip_network(u8 net_type, struct network *n) { - // Add allowed ip struct wg_allowedip *allowedip = malloc(sizeof(struct wg_allowedip)); init_allowed_ip(allowedip, net_type, n); + return allowedip; +} + +static void +init_allowed_ip_addr(struct wg_allowedip *allowedip, ip_addr addr) +{ + memset(allowedip, 0, sizeof(struct wg_allowedip)); + if (ipa_is_ip4(addr)) { + allowedip->family = AF_INET; + allowedip->ip4.s_addr = ip4_to_u32(ip4_hton(ipa_to_ip4(addr))); + allowedip->cidr = IP4_MAX_PREFIX_LENGTH; + } else { + allowedip->family = AF_INET6; + ip6_addr netaddr = ip6_hton(ipa_to_ip6(addr)); + memcpy(allowedip->ip6.s6_addr, &netaddr, 16); + allowedip->cidr = IP6_MAX_PREFIX_LENGTH; + } +} + +static struct wg_allowedip * +create_allowed_ip_addr(ip_addr addr) +{ + struct wg_allowedip *allowedip = malloc(sizeof(struct wg_allowedip)); + init_allowed_ip_addr(allowedip, addr); + return allowedip; +} + +static int +add_allowed_ip(struct wg_allowedip *allowedip, wg_peer *peer) +{ if (peer->first_allowedip && peer->last_allowedip) peer->last_allowedip->next_allowedip = allowedip; else @@ -349,6 +383,18 @@ remove_allowed_ip(wg_peer *peer, struct wg_allowedip *allowedip) } static void +wg_bfd_notify(struct bfd_request *req) +{ + log(L_WARN "wg_bfd_notify"); +} + +static bool +ipa_subprefix(ip_addr addr, ip_addr net, ip_addr mask) +{ + return ipa_equal(ipa_and(addr, mask), net); +} + +static void wg_rt_notify(struct proto *P, struct channel *CH, struct network *n, struct rte *new, struct rte *old UNUSED) { @@ -368,7 +414,7 @@ wg_rt_notify(struct proto *P, struct channel *CH, struct network *n, if (iface && iface == p->iface) { struct eattr *t; - DBG("WG: found %p iface %I %p\n", new->attrs, nh->gw, nh->next); + DBG("WG: found %p iface %s %I %p\n", new->attrs, ifname, nh->gw, nh->next); struct hostentry *he = new->attrs->hostentry; @@ -395,6 +441,7 @@ wg_rt_notify(struct proto *P, struct channel *CH, struct network *n, t = ea_find(he->src->eattrs, EA_CODE(PROTOCOL_BGP, BA_TUNNEL_ENCAP)); } if (t && t->u.ptr && decode_tunnel_encap(t, &encap, P->pool) == 0 && encap.type == c->tunnel_type && encap.encap_len == sizeof(wg_key)) { + ip_addr *nh_ip = NULL; const wg_key *pubkey = encap.encap; bool add_ip = true; struct wg_entry *en = fib_find(&ch->rtable, n->n.addr); @@ -411,6 +458,31 @@ wg_rt_notify(struct proto *P, struct channel *CH, struct network *n, WG_TRACE(D_EVENTS, "WG: Attr %x %x %d %04x", t->flags, t->type, t->u.ptr->length, encap.flags); + { + struct eattr *ea = + ea_find(new->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_NEXT_HOP)); + + nh_ip = (void *) ea->u.ptr->data; + + struct neighbor *ne = neigh_find(P, *nh_ip, iface, NEF_STICKY); + if (!ne || (!ne->ifa)) { + log(L_WARN "Invalid next hop %I of wireguard", *nh_ip); + } else { + struct bfd_request *req; + void *data = NULL; + log(L_WARN "Add bfd request session %I %I", *nh_ip, ne->ifa->ip); + req = bfd_request_session(P->pool, *nh_ip, ne->ifa->ip, + NULL, //iface, + P->vrf, + wg_bfd_notify, data); + if (!req) { + log(L_WARN "bfd_request_session failed"); + } + } + /* } else { */ + /* log(L_WARN "Invalid hostentry"); */ + } + struct wg_device *dev = p->dev; if (dev != NULL) { @@ -439,8 +511,18 @@ wg_rt_notify(struct proto *P, struct channel *CH, struct network *n, dump_peer(peer); if (is_tunnel_ep) set_peer_tunnel_ep(p, peer, encap.ep.ip, encap.udp_dest_port); - if (add_ip) - add_allowed_ip(ch->c.net_type, n, peer); + if (add_ip) { + struct wg_allowedip *allowed_n = + create_allowed_ip_network(ch->c.net_type, n); + add_allowed_ip(allowed_n, peer); +#if 0 + if (nh_ip) { + struct wg_allowedip *allowed_ip = + create_allowed_ip_addr(*nh_ip); + add_allowed_ip(allowed_ip, peer); + } +#endif + } dirty = true; if (dirty) { |