summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--proto/wireguard/wireguard.c96
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) {