summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMikael Magnusson <mikma@users.sourceforge.net>2019-09-27 22:14:05 +0200
committerMikael Magnusson <mikma@users.sourceforge.net>2020-09-13 18:05:34 +0200
commit23d260237241ed082d5f1a6fceccba8a704bc838 (patch)
treecf0b2e2bc5c5a59357a6ddcb91506eb9b71eb85e
parent6dde73086f934fe6c3f859fc6df7f93d13f2c5f8 (diff)
Wireguard: Refactor tunnel encaps decoding
-rw-r--r--lib/Makefile2
-rw-r--r--lib/tunnel_encaps.c180
-rw-r--r--lib/tunnel_encaps.h19
-rw-r--r--proto/wireguard/wireguard.c191
4 files changed, 201 insertions, 191 deletions
diff --git a/lib/Makefile b/lib/Makefile
index 5c78b2a9..300ccc85 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -1,4 +1,4 @@
-src := bitmap.c bitops.c checksum.c event.c flowspec.c idm.c ip.c lists.c mac.c md5.c mempool.c net.c patmatch.c printf.c resource.c sha1.c sha256.c sha512.c slab.c slists.c strtoul.c tbf.c timer.c xmalloc.c
+src := bitmap.c bitops.c checksum.c event.c flowspec.c idm.c ip.c lists.c mac.c md5.c mempool.c net.c patmatch.c printf.c resource.c sha1.c sha256.c sha512.c slab.c slists.c strtoul.c tbf.c timer.c xmalloc.c tunnel_encaps.c
obj := $(src-o-files)
$(all-daemon)
diff --git a/lib/tunnel_encaps.c b/lib/tunnel_encaps.c
new file mode 100644
index 00000000..43fcdbcb
--- /dev/null
+++ b/lib/tunnel_encaps.c
@@ -0,0 +1,180 @@
+#include "lib/tunnel_encaps.h"
+
+static
+int decode_wireguard(const void *p, size_t sub_tlv_len, wg_key *pubkey, u16 *flags)
+{
+ if (sub_tlv_len != sizeof(wg_key)) {
+ log(L_TRACE "WG: wireguard len error %d", sub_tlv_len);
+ return -1;
+ }
+
+ memcpy(pubkey, p, sizeof(wg_key));
+ *flags |= FLAG_BGP_TUNNEL_ENCAP_A_SUB_TLV_ENCAP;
+ return 0;
+}
+
+static
+int decode_color(const void *p, size_t sub_tlv_len, u32 *color, u16 *flags)
+{
+ if (sub_tlv_len != 8) {
+ log(L_TRACE "WG: color len error %d", sub_tlv_len);
+ return -1;
+ }
+
+ if (get_u16(p) != 0x030b) {
+ log(L_TRACE "WG: color error %04x", get_u16(p));
+ return -1;
+ }
+
+ *color = get_u32(p+2);
+ *flags |= FLAG_BGP_TUNNEL_ENCAP_A_SUB_TLV_COLOR;
+ return 0;
+}
+
+static
+int decode_udp_dest_port(const void *p, size_t sub_tlv_len, u16 *udp_dest_port, u16 *flags)
+{
+ if (sub_tlv_len != 2) {
+ log(L_TRACE "WG: udp dest port len error %d", sub_tlv_len);
+ return -1;
+ }
+
+ *udp_dest_port = get_u16(p);
+ *flags |= FLAG_BGP_TUNNEL_ENCAP_A_SUB_TLV_UDP_DEST_PORT;
+ return 0;
+}
+
+static
+int decode_tunnel_ep(const void *p, size_t sub_tlv_len, u32 *as4, ip_addr *tunnel_ep, u16 *flags)
+{
+ if (sub_tlv_len < 6) {
+ log(L_TRACE "WG: tunnel ep len error");
+ return -1;
+ }
+
+ *as4 = get_u32(p);
+ u16 af = get_u16(p + 4);
+ switch (af) {
+ case NET_IP4:
+ if (sub_tlv_len != 10) {
+ log(L_TRACE "WG: IPv4 len error %d", sub_tlv_len);
+ return -1;
+ }
+ *tunnel_ep = ipa_from_ip4(get_ip4(p + 6));
+ *flags |= FLAG_BGP_TUNNEL_ENCAP_A_SUB_TLV_TUNNEL_EP;
+ return 0;
+ case NET_IP6:
+ if (sub_tlv_len != 22) {
+ log(L_TRACE "WG: IPv6 len error %d", sub_tlv_len);
+ return -1;
+ }
+ *tunnel_ep = ipa_from_ip6(get_ip6(p + 6));
+ *flags |= FLAG_BGP_TUNNEL_ENCAP_A_SUB_TLV_TUNNEL_EP;
+ return 0;
+ default:
+ log(L_TRACE "WG: Address family error %d", af);
+ return -1;
+ }
+}
+
+static
+int decode_sub_tlv(const u8 *p, size_t len, wg_key *pubkey,
+ u32 *tunnel_ep_as, ip_addr *tunnel_ep_addr,
+ u32 *color, u16 *udp_dest_port, u16 *flags)
+{
+ if (len < 3) {
+ log(L_TRACE "WG: sub_tlv len error %d", len);
+ return -1;
+ }
+
+ const u8 *first = p;
+ const u8 *last = p + len;
+ int type = get_u8(p++);
+ u16 sub_tlv_len = 0;
+
+ log(L_TRACE "WG: sub tlv type %d", type);
+ if (type >= 0 && type <= 127) {
+ sub_tlv_len = get_u8(p);
+ p++;
+ } else if (type >= 128 && type <= 255) {
+ sub_tlv_len = get_u16(p);
+ p += 2;
+ } else {
+ log(L_TRACE "WG: sub_tlv type error %d", type);
+ return -1;
+ }
+
+ log(L_TRACE "WG: sub tlv len %d", sub_tlv_len);
+ if (p + sub_tlv_len > last) {
+ log(L_TRACE "WG: sub_tlv value len error %d", sub_tlv_len);
+ return -1;
+ }
+
+ int res = 0;
+
+ switch (type) {
+ case BGP_TUNNEL_ENCAP_A_SUB_TLV_ENCAP:
+ res = decode_wireguard(p, sub_tlv_len, pubkey, flags);
+ break;
+ case BGP_TUNNEL_ENCAP_A_SUB_TLV_TUNNEL_EP:
+ res = decode_tunnel_ep(p, sub_tlv_len, tunnel_ep_as, tunnel_ep_addr, flags);
+ break;
+ case BGP_TUNNEL_ENCAP_A_SUB_TLV_COLOR:
+ res = decode_color(p, sub_tlv_len, color, flags);
+ break;
+ case BGP_TUNNEL_ENCAP_A_SUB_TLV_UDP_DEST_PORT:
+ res = decode_udp_dest_port(p, sub_tlv_len, udp_dest_port, flags);
+ break;
+ default:
+ /* Skip unsupported sub-TLV. */
+ res = 0;
+ break;
+ }
+
+ if (res < 0)
+ return res;
+
+ return p - first + sub_tlv_len;
+}
+
+int decode_tunnel_encap(const eattr *e, u16 wg_tunnel_type, wg_key *pubkey, u32 *as4, ip_addr *tunnel_ep, u32 *color, u16 *udp_port, u16 *flags)
+{
+ const u8 *p = e->u.ptr->data;
+ int len = e->u.ptr->length;
+
+ if (len < 4) {
+ log(L_TRACE "WG: tunnel_encap len error %d", len);
+ return -1;
+ }
+
+ u16 tunnel_type = get_u16(p);
+
+ log(L_DEBUG "WG: tunnel type %d", tunnel_type);
+
+ if (tunnel_type != wg_tunnel_type) {
+ log(L_TRACE "WG: tunnel type error %d", tunnel_type);
+ return -1;
+ }
+
+ u16 value_length = get_u16(p + 2);
+
+ log(L_TRACE "WG: tunnel encap value len %d", value_length);
+
+ if (len < value_length + 4) {
+ log(L_TRACE "WG: tunnel encap len error %d", value_length);
+ return -1;
+ }
+
+ for (const u8 *cur = p + 4; cur < p + 4 + value_length;) {
+ int res = decode_sub_tlv(cur, value_length, pubkey, as4, tunnel_ep, color, udp_port, flags);
+
+ if (res < 0) {
+ log(L_TRACE "WG: decode error %d", res);
+ return res;
+ }
+
+ cur += res;
+ }
+
+ return 0;
+}
diff --git a/lib/tunnel_encaps.h b/lib/tunnel_encaps.h
new file mode 100644
index 00000000..6c85a883
--- /dev/null
+++ b/lib/tunnel_encaps.h
@@ -0,0 +1,19 @@
+#ifndef _BIRD_TUNNEL_ENCAPS_
+#define _BIRD_TUNNEL_ENCAPS_
+
+#include "nest/route.h"
+#include "sysdep/linux/wireguard.h"
+
+#define BGP_TUNNEL_ENCAP_A_SUB_TLV_ENCAP 1
+#define BGP_TUNNEL_ENCAP_A_SUB_TLV_COLOR 4
+#define BGP_TUNNEL_ENCAP_A_SUB_TLV_TUNNEL_EP 6
+#define BGP_TUNNEL_ENCAP_A_SUB_TLV_UDP_DEST_PORT 8
+
+#define FLAG_BGP_TUNNEL_ENCAP_A_SUB_TLV_ENCAP (1<<BGP_TUNNEL_ENCAP_A_SUB_TLV_ENCAP)
+#define FLAG_BGP_TUNNEL_ENCAP_A_SUB_TLV_COLOR (1<<BGP_TUNNEL_ENCAP_A_SUB_TLV_COLOR)
+#define FLAG_BGP_TUNNEL_ENCAP_A_SUB_TLV_TUNNEL_EP (1<<BGP_TUNNEL_ENCAP_A_SUB_TLV_TUNNEL_EP)
+#define FLAG_BGP_TUNNEL_ENCAP_A_SUB_TLV_UDP_DEST_PORT (1<<BGP_TUNNEL_ENCAP_A_SUB_TLV_UDP_DEST_PORT)
+
+int decode_tunnel_encap(const eattr *e, u16 wg_tunnel_type, wg_key *pubkey, u32 *as4, ip_addr *tunnel_ep, u32 *color, u16 *udp_port, u16 *flags);
+
+#endif /* _BIRD_TUNNEL_ENCAPS_ */
diff --git a/proto/wireguard/wireguard.c b/proto/wireguard/wireguard.c
index fa6ccb0e..212fc779 100644
--- a/proto/wireguard/wireguard.c
+++ b/proto/wireguard/wireguard.c
@@ -8,6 +8,7 @@
#include <unistd.h>
#include "lib/lists.h"
#include "lib/ip.h"
+#include "lib/tunnel_encaps.h"
#include "nest/protocol.h"
#include "nest/iface.h"
#include "sysdep/linux/wireguard.h"
@@ -156,196 +157,6 @@ dump(void *ptr, size_t len)
fprintf(stderr, "\n");
}
-#define BGP_TUNNEL_ENCAP_A_SUB_TLV_ENCAP 1
-#define BGP_TUNNEL_ENCAP_A_SUB_TLV_COLOR 4
-#define BGP_TUNNEL_ENCAP_A_SUB_TLV_TUNNEL_EP 6
-#define BGP_TUNNEL_ENCAP_A_SUB_TLV_UDP_DEST_PORT 8
-
-#define FLAG_BGP_TUNNEL_ENCAP_A_SUB_TLV_ENCAP (1<<BGP_TUNNEL_ENCAP_A_SUB_TLV_ENCAP)
-#define FLAG_BGP_TUNNEL_ENCAP_A_SUB_TLV_COLOR (1<<BGP_TUNNEL_ENCAP_A_SUB_TLV_COLOR)
-#define FLAG_BGP_TUNNEL_ENCAP_A_SUB_TLV_TUNNEL_EP (1<<BGP_TUNNEL_ENCAP_A_SUB_TLV_TUNNEL_EP)
-#define FLAG_BGP_TUNNEL_ENCAP_A_SUB_TLV_UDP_DEST_PORT (1<<BGP_TUNNEL_ENCAP_A_SUB_TLV_UDP_DEST_PORT)
-
-static
-int decode_wireguard(const void *p, size_t sub_tlv_len, wg_key *pubkey, u16 *flags)
-{
- if (sub_tlv_len != sizeof(wg_key)) {
- log(L_TRACE "WG: wireguard len error %d", sub_tlv_len);
- return -1;
- }
-
- memcpy(pubkey, p, sizeof(wg_key));
- *flags |= FLAG_BGP_TUNNEL_ENCAP_A_SUB_TLV_ENCAP;
- return 0;
-}
-
-static
-int decode_color(const void *p, size_t sub_tlv_len, u32 *color, u16 *flags)
-{
- if (sub_tlv_len != 8) {
- log(L_TRACE "WG: color len error %d", sub_tlv_len);
- return -1;
- }
-
- if (get_u16(p) != 0x030b) {
- log(L_TRACE "WG: color error %04x", get_u16(p));
- return -1;
- }
-
- *color = get_u32(p+2);
- *flags |= FLAG_BGP_TUNNEL_ENCAP_A_SUB_TLV_COLOR;
- return 0;
-}
-
-static
-int decode_udp_dest_port(const void *p, size_t sub_tlv_len, u16 *udp_dest_port, u16 *flags)
-{
- if (sub_tlv_len != 2) {
- log(L_TRACE "WG: udp dest port len error %d", sub_tlv_len);
- return -1;
- }
-
- *udp_dest_port = get_u16(p);
- *flags |= FLAG_BGP_TUNNEL_ENCAP_A_SUB_TLV_UDP_DEST_PORT;
- return 0;
-}
-
-static
-int decode_tunnel_ep(const void *p, size_t sub_tlv_len, u32 *as4, ip_addr *tunnel_ep, u16 *flags)
-{
- if (sub_tlv_len < 6) {
- log(L_TRACE "WG: tunnel ep len error");
- return -1;
- }
-
- *as4 = get_u32(p);
- u16 af = get_u16(p + 4);
- switch (af) {
- case NET_IP4:
- if (sub_tlv_len != 10) {
- log(L_TRACE "WG: IPv4 len error %d", sub_tlv_len);
- return -1;
- }
- *tunnel_ep = ipa_from_ip4(get_ip4(p + 6));
- *flags |= FLAG_BGP_TUNNEL_ENCAP_A_SUB_TLV_TUNNEL_EP;
- return 0;
- case NET_IP6:
- if (sub_tlv_len != 22) {
- log(L_TRACE "WG: IPv6 len error %d", sub_tlv_len);
- return -1;
- }
- *tunnel_ep = ipa_from_ip6(get_ip6(p + 6));
- *flags |= FLAG_BGP_TUNNEL_ENCAP_A_SUB_TLV_TUNNEL_EP;
- return 0;
- default:
- log(L_TRACE "WG: Address family error %d", af);
- return -1;
- }
-}
-
-static
-int decode_sub_tlv(const u8 *p, size_t len, wg_key *pubkey,
- u32 *tunnel_ep_as, ip_addr *tunnel_ep_addr,
- u32 *color, u16 *udp_dest_port, u16 *flags)
-{
- if (len < 3) {
- log(L_TRACE "WG: sub_tlv len error %d", len);
- return -1;
- }
-
- const u8 *first = p;
- const u8 *last = p + len;
- int type = get_u8(p++);
- u16 sub_tlv_len = 0;
-
- log(L_TRACE "WG: sub tlv type %d", type);
- if (type >= 0 && type <= 127) {
- sub_tlv_len = get_u8(p);
- p++;
- } else if (type >= 128 && type <= 255) {
- sub_tlv_len = get_u16(p);
- p += 2;
- } else {
- log(L_TRACE "WG: sub_tlv type error %d", type);
- return -1;
- }
-
- log(L_TRACE "WG: sub tlv len %d", sub_tlv_len);
- if (p + sub_tlv_len > last) {
- log(L_TRACE "WG: sub_tlv value len error %d", sub_tlv_len);
- return -1;
- }
-
- int res = 0;
-
- switch (type) {
- case BGP_TUNNEL_ENCAP_A_SUB_TLV_ENCAP:
- res = decode_wireguard(p, sub_tlv_len, pubkey, flags);
- break;
- case BGP_TUNNEL_ENCAP_A_SUB_TLV_TUNNEL_EP:
- res = decode_tunnel_ep(p, sub_tlv_len, tunnel_ep_as, tunnel_ep_addr, flags);
- break;
- case BGP_TUNNEL_ENCAP_A_SUB_TLV_COLOR:
- res = decode_color(p, sub_tlv_len, color, flags);
- break;
- case BGP_TUNNEL_ENCAP_A_SUB_TLV_UDP_DEST_PORT:
- res = decode_udp_dest_port(p, sub_tlv_len, udp_dest_port, flags);
- break;
- default:
- /* Skip unsupported sub-TLV. */
- res = 0;
- break;
- }
-
- if (res < 0)
- return res;
-
- return p - first + sub_tlv_len;
-}
-
-static
-int decode_tunnel_encap(const eattr *e, u16 wg_tunnel_type, wg_key *pubkey, u32 *as4, ip_addr *tunnel_ep, u32 *color, u16 *udp_port, u16 *flags)
-{
- const u8 *p = e->u.ptr->data;
- int len = e->u.ptr->length;
-
- if (len < 4) {
- log(L_TRACE "WG: tunnel_encap len error %d", len);
- return -1;
- }
-
- u16 tunnel_type = get_u16(p);
-
- log(L_DEBUG "WG: tunnel type %d", tunnel_type);
-
- if (tunnel_type != wg_tunnel_type) {
- log(L_TRACE "WG: tunnel type error %d", tunnel_type);
- return -1;
- }
-
- u16 value_length = get_u16(p + 2);
-
- log(L_TRACE "WG: tunnel encap value len %d", value_length);
-
- if (len < value_length + 4) {
- log(L_TRACE "WG: tunnel encap len error %d", value_length);
- return -1;
- }
-
- for (const u8 *cur = p + 4; cur < p + 4 + value_length;) {
- int res = decode_sub_tlv(cur, value_length, pubkey, as4, tunnel_ep, color, udp_port, flags);
-
- if (res < 0) {
- log(L_TRACE "WG: decode error %d", res);
- return res;
- }
-
- cur += res;
- }
-
- return 0;
-}
-
static wg_peer *
add_peer(wg_device *dev, wg_key pubkey)
{