diff options
author | Mikael Magnusson <mikma@users.sourceforge.net> | 2018-09-28 01:03:42 +0200 |
---|---|---|
committer | Mikael Magnusson <mikma@users.sourceforge.net> | 2021-01-12 23:34:17 +0100 |
commit | 7936ba1d97303af6853d858e6fc022abbca090ad (patch) | |
tree | d2b9e8e08b1fc99b86d79c07b1b332f50d7781e8 | |
parent | 513729bbab3faacfa4eb48b1572fce8ae413179e (diff) |
Filter: TLV
-rw-r--r-- | filter/config.Y | 81 | ||||
-rw-r--r-- | filter/data.c | 3 | ||||
-rw-r--r-- | filter/data.h | 5 | ||||
-rw-r--r-- | filter/f-inst.c | 25 | ||||
-rw-r--r-- | filter/filter.c | 172 | ||||
-rw-r--r-- | filter/filter.h | 3 | ||||
-rw-r--r-- | nest/attrs.h | 25 | ||||
-rw-r--r-- | nest/config.Y | 2 | ||||
-rw-r--r-- | nest/route.h | 1 |
9 files changed, 313 insertions, 4 deletions
diff --git a/filter/config.Y b/filter/config.Y index 5cd52e40..9f3faba0 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -112,6 +112,69 @@ f_new_pair_set(int fa, int ta, int fb, int tb) #define LC_ALL 0xFFFFFFFF static struct f_tree * +f_new_sub_tlv_item(u32 type, u32 v1) +{ + struct f_tree *t = f_new_tree(); + t->right = t; + t->from.type = t->to.type = T_SUB_TLV; + struct tlv v; + v.type = type; + switch (type) { + case TLV_COLOR: + v.u.color = v1; + break; + case TLV_UDP_DEST_PORT: + v.u.udp_dest_port = v1; + break; + default: + // FIXME error + break; + } + t->from.val.tlv = v; + t->to.val.tlv = v; + return t; +} + +static struct f_tree * +f_new_sub_tlv_tunnel_ep(u32 asn, ip_addr ip) +{ + struct f_tree *t = f_new_tree(); + t->right = t; + t->from.type = t->to.type = T_SUB_TLV; + struct tlv v; + v.type = TLV_TUNNEL_ENDPOINT; + v.u.tunnel_endpoint.asn = asn; + v.u.tunnel_endpoint.ip = ip; + t->from.val.tlv = v; + t->to.val.tlv = v; + return t; +} + +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_encap(u32 type, const char *v1) +{ + struct f_tree *t = f_new_tree(); + t->right = t; + t->from.type = t->to.type = T_SUB_TLV; + struct tlv v; + v.type = TLV_ENCAPSULATION; + v.u.tunnel_encap.type = type; + // FIXME base64 decode v1 + int len = 32; + v.u.tunnel_encap.data = cfg_alloc(len); + v.u.tunnel_encap.length = len; + // FIXME + wg_key_from_base64(v.u.tunnel_encap.data, v1); +// memcpy(v.u.tunnel_encap.data, v1, len); + t->from.val.tlv = v; + t->to.val.tlv = v; + return t; +} + +static struct f_tree * f_new_ec_item(u32 kind, u32 ipv4_used, u32 key, u32 vf, u32 vt) { u64 fm, to; @@ -178,6 +241,9 @@ f_generate_empty(struct f_dynamic_attr dyn) case EAF_TYPE_LC_SET: empty = f_const_empty_lclist; break; + case EAF_TYPE_TUNNEL_ENCAP: + empty = f_const_empty_set; + break; default: cf_error("Can't empty that attribute"); } @@ -288,7 +354,8 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN, PREPEND, FIRST, LAST, LAST_NONAGGREGATED, MATCH, EMPTY, FILTER, WHERE, EVAL, ATTRIBUTE, - BT_ASSERT, BT_TEST_SUITE, BT_CHECK_ASSIGN, BT_TEST_SAME, FORMAT) + BT_ASSERT, BT_TEST_SUITE, BT_CHECK_ASSIGN, BT_TEST_SAME, + TLV, TUNNEL_ENCAP, TUNNEL_ENDPOINT, UDP_DEST_PORT, COLOR, FORMAT) %nonassoc THEN %nonassoc ELSE @@ -304,7 +371,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN, %type <ecs> ec_kind %type <fret> break_command %type <i32> cnum -%type <e> pair_item ec_item lc_item set_item switch_item set_items switch_items switch_body +%type <e> pair_item ec_item lc_item set_item switch_item set_items switch_items switch_body sub_tlv_item %type <trie> fprefix_set %type <v> set_atom switch_atom fipa %type <px> fprefix @@ -378,6 +445,7 @@ type: | CLIST { $$ = T_CLIST; } | ECLIST { $$ = T_ECLIST; } | LCLIST { $$ = T_LCLIST; } + | TLV { $$ = T_TLV; } | type SET { switch ($1) { case T_INT: @@ -387,6 +455,7 @@ type: case T_LC: case T_RD: case T_IP: + case T_TLV: $$ = T_SET; break; @@ -584,10 +653,17 @@ lc_item: { $$ = f_new_lc_item($2, $10, $4, $12, $6, $14); } ; +sub_tlv_item: + '(' TUNNEL_ENCAP ',' cnum ',' text ')' { $$ = f_new_sub_tlv_encap($4, $6); } + | '(' UDP_DEST_PORT ',' cnum ')' { $$ = f_new_sub_tlv_item(TLV_UDP_DEST_PORT, $4); } + | '(' COLOR ',' cnum ')' { $$ = f_new_sub_tlv_item(TLV_COLOR, $4); } + | '(' TUNNEL_ENDPOINT ',' NUM ',' ipa ')' { $$ = f_new_sub_tlv_tunnel_ep($4, $6); } + set_item: pair_item | ec_item | lc_item + | sub_tlv_item | set_atom { $$ = f_new_item($1, $1); } | set_atom DDOT set_atom { $$ = f_new_item($1, $3); } ; @@ -596,6 +672,7 @@ switch_item: pair_item | ec_item | lc_item + | sub_tlv_item | switch_atom { $$ = f_new_item($1, $1); } | switch_atom DDOT switch_atom { $$ = f_new_item($1, $3); } ; diff --git a/filter/data.c b/filter/data.c index 7c33d2cb..5a98380e 100644 --- a/filter/data.c +++ b/filter/data.c @@ -80,6 +80,9 @@ const struct f_val f_const_empty_path = { }, f_const_empty_lclist = { .type = T_LCLIST, .val.ad = &null_adata, +}, f_const_empty_set = { + .type = T_SET, + .val.t = NULL, }; static struct adata * diff --git a/filter/data.h b/filter/data.h index a0ec3819..9f281c3b 100644 --- a/filter/data.h +++ b/filter/data.h @@ -58,6 +58,8 @@ enum f_type { T_LCLIST = 0x29, /* Large community list */ T_RD = 0x2a, /* Route distinguisher for VPN addresses */ T_PATH_MASK_ITEM = 0x2b, /* Path mask item for path mask constructors */ + T_TLV = 0x2c, /* Tunnel encapsulation TLV */ + T_SUB_TLV = 0x2d, /* Tunnel encapsulation sub-TLV */ T_SET = 0x80, T_PREFIX_SET = 0x81, @@ -78,6 +80,7 @@ struct f_val { const struct adata *ad; const struct f_path_mask *path_mask; struct f_path_mask_item pmi; + struct tlv tlv; } val; }; @@ -216,7 +219,7 @@ undef_value(struct f_val v) (v.val.ad == &null_adata); } -extern const struct f_val f_const_empty_path, f_const_empty_clist, f_const_empty_eclist, f_const_empty_lclist; +extern const struct f_val f_const_empty_path, f_const_empty_clist, f_const_empty_eclist, f_const_empty_lclist, f_const_empty_set; enum filter_return f_eval(const struct f_line *expr, struct linpool *tmp_pool, struct f_val *pres); diff --git a/filter/f-inst.c b/filter/f-inst.c index b6bc81f7..4d095dbd 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -676,6 +676,10 @@ case EAF_TYPE_UNDEF: RESULT_VOID; break; + case EAF_TYPE_TUNNEL_ENCAP: + RESULT_(T_TLV, ad, e->u.ptr); + runtime( "Getting tunnel encap attribute is not supported" ); + break; default: bug("Unknown dynamic attribute type"); } @@ -736,6 +740,27 @@ } break; + case EAF_TYPE_TUNNEL_ENCAP: + { + /* TODO remove type check? Refer to 26194bd - Filter: Improved parse-time typechecks */ + if (v1.type != T_SET) + runtime( "Setting tunnel encap attribute to non-tlv value %d", v1.type ); + int type = 0; + int len = calc_tunnel_encap(v1.val.t, &type); + if (len < 0) + runtime( "Error tunnel encapsulation" ); + else if (len == 0) { + struct adata *ad = lp_alloc(fpool, sizeof(struct adata) + len); + ad->length = len; + l->attrs[0].u.ptr = ad; + } + else if (type <= 0 || type > 65535) + runtime( "Invalid tunnel encapsulation type: %d (0 < type <= 65535)", type ); + else + l->attrs[0].u.ptr = build_tunnel_encap(fpool, v1.val.t, type, len); + break; + } + default: bug("Unknown dynamic attribute type"); } diff --git a/filter/filter.c b/filter/filter.c index e505d570..90673865 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -141,6 +141,178 @@ f_rta_cow(struct filter_state *fs) static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS; +int +calc_tunnel_encap(const struct f_tree *t, int *type) +{ + if (t == NULL) + return 0; + + if (t->from.type == 0) { + return 0; + } + + if (t->from.type != T_SUB_TLV) { + DBG("Not tlv %d\n", t->from.type); + return -1; + } + + const struct tlv *tlv = &t->from.val.tlv; + int len = 0; + switch (tlv->type) { + case TLV_ENCAPSULATION: + /* + Header: + Tunnel Type (2 Octets) + Length (2 Octets) + Value (Variable) + + TLV: + Sub-TLV Type (1 Octet) + Sub-TLV Length (1 Octet) + Sub-TLV Value (Variable) + */ + if (tlv->u.tunnel_encap.length > 0) + len = 4 + 2 + tlv->u.tunnel_encap.length; + else + len = 0; + *type = tlv->u.tunnel_encap.type; + break; + case TLV_COLOR: + /* + Sub-TLV Type (1 Octet) + Sub-TLV Length (1 Octet) + Sub-TLV Value (8 Octets) + */ + len = 10; + break; + case TLV_UDP_DEST_PORT: + /* + Sub-TLV Type (1 Octet) + Sub-TLV Length (1 Octet) + Sub-TLV Value (2 Octets) + */ + len = 4; + break; + case TLV_TUNNEL_ENDPOINT: + /* + Sub-TLV Type (1 Octet) + Sub-TLV Length (1 Octet) + Sub-TLV Value (10 or 22 Octets) + */ + if (ipa_is_ip4(tlv->u.tunnel_endpoint.ip)) + len = 2 + 10; + else + len = 2 + 22; + break; + default: + /* Ignore unknown */ + len = 0; + break; + } + + return len + calc_tunnel_encap(t->left, type) + calc_tunnel_encap(t->right, type); +} + +static void * +build_tunnel_encap_rec(void *p, const struct f_tree *t) +{ + if (t == NULL) + return p; + + if (t->from.type != T_SUB_TLV) { + DBG("Not tlv %d\n", t->from.type); + return p; + } + + const struct tlv *tlv = &t->from.val.tlv; + switch (tlv->type) { + case TLV_ENCAPSULATION: + { + /* + TLV: + Sub-TLV Type (1 Octet) + Sub-TLV Length (1 Octet) + Sub-TLV Value (Variable) + */ + int len = tlv->u.tunnel_encap.length; + if (len <= 0) + break; + put_u8(p, tlv->type); p++; + put_u8(p, len); p++; + memcpy(p, tlv->u.tunnel_encap.data, len); p+=len; + break; + } + case TLV_COLOR: + /* + Sub-TLV Type (1 Octet) + Sub-TLV Length (1 Octet) + Sub-TLV Value (8 Octets) + */ + put_u8(p, tlv->type); p++; + put_u8(p, 8); p++; + put_u8(p, 0x03); p++; + put_u8(p, 0x0b); p++; + put_u16(p, 0x0); p+=2; + put_u32(p, tlv->u.color); p+=4; + break; + case TLV_UDP_DEST_PORT: + /* + Sub-TLV Type (1 Octet) + Sub-TLV Length (1 Octet) + Sub-TLV Value (2 Octets) + */ + put_u8(p, tlv->type); p++; + put_u8(p, 2); p++; + put_u16(p, tlv->u.udp_dest_port); p+=2; + break; + case TLV_TUNNEL_ENDPOINT: + /* + Sub-TLV Type (1 Octet) + Sub-TLV Length (1 Octet) + Sub-TLV Value (10 or 22 Octets) + */ + put_u8(p, tlv->type); p++; + if (ipa_is_ip4(tlv->u.tunnel_endpoint.ip)) { + put_u8(p, 10); p++; + put_u32(p, tlv->u.tunnel_endpoint.asn); p+=4; + put_u16(p, NET_IP4); p+=2; + put_ip4(p, ipa_to_ip4(tlv->u.tunnel_endpoint.ip)); p+=4; + } else { + put_u8(p, 22); p++; + put_u32(p, tlv->u.tunnel_endpoint.asn); p+=4; + put_u16(p, NET_IP6); p+=2; + put_ip6(p, ipa_to_ip6(tlv->u.tunnel_endpoint.ip)); p+=16; + } + break; + default: + /* Ignore unknown */ + break; + } + + return build_tunnel_encap_rec(build_tunnel_encap_rec(p, t->left), t->right); +} + +struct adata * +build_tunnel_encap(struct linpool *pool, const struct f_tree *t, int type, int len) +{ + struct adata *ad = lp_alloc(pool, sizeof(struct adata) + len); + ad->length = len; + void *p = ad->data; + + /* + Header: + Tunnel Type (2 Octets) + Length (2 Octets) + Value (Variable) + */ + + put_u16(p, type); p += 2; + put_u16(p, len - 4); p += 2; + build_tunnel_encap_rec(p, t); + return ad; +} + + /** * interpret * @fs: filter state diff --git a/filter/filter.h b/filter/filter.h index 26c1037b..dbd17e1d 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -64,6 +64,9 @@ void filter_commit(struct config *new, struct config *old); void filters_dump_all(void); +int calc_tunnel_encap(const struct f_tree *t, int *type); +struct adata *build_tunnel_encap(struct linpool *pool, const struct f_tree *t, int type, int len); + #define FILTER_ACCEPT NULL #define FILTER_REJECT ((struct filter *) 1) #define FILTER_UNDEF ((struct filter *) 2) /* Used in BGP */ diff --git a/nest/attrs.h b/nest/attrs.h index 50da817b..317094e8 100644 --- a/nest/attrs.h +++ b/nest/attrs.h @@ -221,4 +221,29 @@ struct adata *lc_set_sort(struct linpool *pool, const struct adata *src); void ec_set_sort_x(struct adata *set); /* Sort in place */ +/* Tunnel Encapsulation TLV types */ +#define TLV_TUNNEL_TYPE 0x00 /* Reserved. Used internally only. */ +#define TLV_ENCAPSULATION 0x01 +#define TLV_COLOR 0x04 +#define TLV_TUNNEL_ENDPOINT 0x06 +#define TLV_UDP_DEST_PORT 0x08 + +/* Tunnel Encapsulation TLV */ +struct tlv { + int type; + union { + struct { + int type; + int length; + void *data; + } tunnel_encap; + struct { + u32 asn; + ip_addr ip; + } tunnel_endpoint; + u32 color; + u16 udp_dest_port; + } u; +}; + #endif diff --git a/nest/config.Y b/nest/config.Y index 0bb8ca51..fe1b9fcd 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -359,7 +359,7 @@ iface_patt_node_init: ; iface_patt_node_body: - TEXT { this_ipn->pattern = $1; /* this_ipn->prefix stays zero */ } + text { this_ipn->pattern = $1; /* this_ipn->prefix stays zero */ } | opttext net_or_ipa { this_ipn->pattern = $1; this_ipn->prefix = $2; } ; diff --git a/nest/route.h b/nest/route.h index 1b4f2866..96159dab 100644 --- a/nest/route.h +++ b/nest/route.h @@ -517,6 +517,7 @@ const char *ea_custom_name(uint ea); #define EAF_TYPE_INT_SET 0x0a /* Set of u32's (e.g., a community list) */ #define EAF_TYPE_EC_SET 0x0e /* Set of pairs of u32's - ext. community list */ #define EAF_TYPE_LC_SET 0x12 /* Set of triplets of u32's - large community list */ +#define EAF_TYPE_TUNNEL_ENCAP 0x16 /* Tunnel Encapsulation (encoding per draft-ietf-idr-tunnel-encaps-13) */ #define EAF_TYPE_UNDEF 0x1f /* `force undefined' entry */ #define EAF_EMBEDDED 0x01 /* Data stored in eattr.u.data (part of type spec) */ #define EAF_VAR_LENGTH 0x02 /* Attribute length is variable (part of type spec) */ |