diff --git a/filter/config.Y b/filter/config.Y index 6efc14f5..3bb00c13 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -278,6 +278,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN, TRUE, FALSE, RT, RO, UNKNOWN, GENERIC, FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, CAST, DEST, IFNAME, IFINDEX, PREFERENCE, + ROA_CHECK, LEN, DEFINED, ADD, DELETE, CONTAINS, RESET, @@ -759,10 +760,8 @@ term: | DELETE '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'd'; } | FILTER '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'f'; } -/* - | ROA_CHECK '(' SYM ')' { $$ = f_generate_roa_check($3, NULL, NULL); } - | ROA_CHECK '(' SYM ',' term ',' term ')' { $$ = f_generate_roa_check($3, $5, $7); } -*/ + | ROA_CHECK '(' rtable ')' { $$ = f_generate_roa_check($3, NULL, NULL); } + | ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_generate_roa_check($3, $5, $7); } /* | term '.' LEN { $$->code = P('P','l'); } */ diff --git a/filter/f-util.c b/filter/f-util.c index 7311a56e..661941ec 100644 --- a/filter/f-util.c +++ b/filter/f-util.c @@ -54,9 +54,8 @@ f_generate_complex(int operation, int operation_aux, struct f_inst *dyn, struct return set_dyn; } -#if 0 struct f_inst * -f_generate_roa_check(struct symbol *sym, struct f_inst *prefix, struct f_inst *asn) +f_generate_roa_check(struct rtable_config *table, struct f_inst *prefix, struct f_inst *asn) { struct f_inst_roa_check *ret = cfg_allocz(sizeof(struct f_inst_roa_check)); ret->i.code = P('R','C'); @@ -65,13 +64,12 @@ f_generate_roa_check(struct symbol *sym, struct f_inst *prefix, struct f_inst *a ret->i.arg2 = asn; /* prefix == NULL <-> asn == NULL */ - if ((sym->class != SYM_ROA) || ! sym->def) - cf_error("%s is not a ROA table", sym->name); - ret->rtc = sym->def; + if (table->addr_type != NET_ROA4 && table->addr_type != NET_ROA6) + cf_error("%s is not a ROA table", table->name); + ret->rtc = table; return &ret->i; } -#endif char * filter_name(struct filter *filter) diff --git a/filter/filter.c b/filter/filter.c index 7a5ba5b9..6ab0cc93 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -39,6 +39,8 @@ #include "lib/socket.h" #include "lib/string.h" #include "lib/unaligned.h" +#include "lib/net.h" +#include "lib/ip.h" #include "nest/route.h" #include "nest/protocol.h" #include "nest/iface.h" @@ -1241,7 +1243,7 @@ interpret(struct f_inst *what) break; -#if 0 + case P('R','C'): /* ROA Check */ if (what->arg1) { @@ -1266,15 +1268,15 @@ interpret(struct f_inst *what) as_path_get_last(e->u.ptr, &as); } - struct roa_table_config *rtc = ((struct f_inst_roa_check *) what)->rtc; - if (!rtc->table) + struct rtable *table = ((struct f_inst_roa_check *) what)->rtc->table; + if (!table || table->addr_type != (v1.val.net->type == NET_IP4 ? NET_ROA4 : NET_ROA6)) runtime("Missing ROA table"); res.type = T_ENUM_ROA; - res.val.i = ROA_UNKNOWN; - // XXXX res.val.i = roa_check_net(rtc->table, &v1.val.net, as); + res.val.i = net_roa_check(table, v1.val.net, as); + break; -#endif + default: bug( "Unknown instruction %d (%c)", what->code, what->code & 0xff); diff --git a/filter/filter.h b/filter/filter.h index 1875f314..af490121 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -35,7 +35,7 @@ struct f_inst { /* Instruction */ /* Not enough fields in f_inst for three args used by roa_check() */ struct f_inst_roa_check { struct f_inst i; - struct roa_table_config *rtc; + struct rtable_config *rtc; }; struct f_prefix { @@ -67,7 +67,7 @@ struct f_inst *f_new_inst(void); struct f_inst *f_new_dynamic_attr(int type, int f_type, int code); /* Type as core knows it, type as filters know it, and code of dynamic attribute */ struct f_tree *f_new_tree(void); struct f_inst *f_generate_complex(int operation, int operation_aux, struct f_inst *dyn, struct f_inst *argument); -// struct f_inst *f_generate_roa_check(struct symbol *sym, struct f_inst *prefix, struct f_inst *asn); +struct f_inst *f_generate_roa_check(struct rtable_config *table, struct f_inst *prefix, struct f_inst *asn); struct f_tree *build_tree(struct f_tree *); diff --git a/nest/route.h b/nest/route.h index c6e9cb41..1cce3c01 100644 --- a/nest/route.h +++ b/nest/route.h @@ -72,6 +72,7 @@ static inline struct fib_node * fib_user_to_node(struct fib *f, void *e) void fib_init(struct fib *f, pool *p, uint addr_type, uint node_size, uint node_offset, uint hash_order, fib_init_fn init); void *fib_find(struct fib *, const net_addr *); /* Find or return NULL if doesn't exist */ +void *fib_get_chain(struct fib *f, const net_addr *a); /* Find first node in linked list from hash table */ void *fib_get(struct fib *, const net_addr *); /* Find or create new if nonexistent */ void *fib_route(struct fib *, const net_addr *); /* Longest-match routing lookup */ void fib_delete(struct fib *, void *); /* Remove fib entry */ @@ -273,8 +274,9 @@ void rt_commit(struct config *new, struct config *old); void rt_lock_table(rtable *); void rt_unlock_table(rtable *); void rt_setup(pool *, rtable *, char *, struct rtable_config *); -static inline net *net_find(rtable *tab, net_addr *addr) { return (net *) fib_find(&tab->fib, addr); } -static inline net *net_get(rtable *tab, net_addr *addr) { return (net *) fib_get(&tab->fib, addr); } +static inline net *net_find(rtable *tab, const net_addr *addr) { return (net *) fib_find(&tab->fib, addr); } +static inline net *net_get(rtable *tab, const net_addr *addr) { return (net *) fib_get(&tab->fib, addr); } +byte net_roa_check(rtable *tab, const net_addr *n, u32 asn); rte *rte_find(net *net, struct rte_src *src); rte *rte_get_temp(struct rta *); diff --git a/nest/rt-fib.c b/nest/rt-fib.c index 8bf67f8d..55387c5e 100644 --- a/nest/rt-fib.c +++ b/nest/rt-fib.c @@ -195,6 +195,15 @@ fib_hash(struct fib *f, const net_addr *a) } } +void * +fib_get_chain(struct fib *f, const net_addr *a) +{ + ASSERT(f->addr_type == a->type); + + struct fib_node *e = f->hash_table[fib_hash(f, a)]; + return e; +} + /** * fib_find - search for FIB node by prefix * @f: FIB to search in diff --git a/nest/rt-table.c b/nest/rt-table.c index 400b9d9c..f164ecd9 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -100,6 +100,77 @@ net_route_ip6(struct fib *f, net_addr_ip6 *n) return r; } +static byte +net_roa4_check(rtable *tab, const net_addr_ip4 *px, u32 asn) +{ + struct net_addr_roa4 n = NET_ADDR_ROA4(px->prefix, px->pxlen, 0, 0); + byte anything = 0; + + struct fib_node *fn; + while (1) + { + for (fn = fib_get_chain(&tab->fib, (net_addr *) &n); fn; fn = fn->next) + { + net *r = fib_node_to_user(&tab->fib, fn); + if (rte_is_valid(r->routes) && ipa_in_netX(ipa_from_ip4(px->prefix), r->n.addr)) + { + net_addr_roa4 *roa = (void *) r->n.addr; + anything = 1; + if (asn && (roa->asn == asn) && (roa->max_pxlen >= px->pxlen)) + return ROA_VALID; + } + } + + if (n.pxlen == 0) + break; + + n.pxlen--; + ip4_clrbit(&n.prefix, n.pxlen); + } + + return anything ? ROA_INVALID : ROA_UNKNOWN; +} + +static byte +net_roa6_check(rtable *tab, const net_addr_ip6 *px, u32 asn) +{ + struct net_addr_roa6 n = NET_ADDR_ROA6(px->prefix, px->pxlen, 0, 0); + byte anything = 0; + + struct fib_node *fn; + while (1) + { + for (fn = fib_get_chain(&tab->fib, (net_addr *) &n); fn; fn = fn->next) + { + net *r = fib_node_to_user(&tab->fib, fn); + if (rte_is_valid(r->routes) && ipa_in_netX(ipa_from_ip6(px->prefix), r->n.addr)) + { + net_addr_roa6 *roa = (void *) r->n.addr; + anything = 1; + if (asn && (roa->asn == asn) && (roa->max_pxlen >= px->pxlen)) + return ROA_VALID; + } + } + + if (n.pxlen == 0) + break; + + n.pxlen--; + ip6_clrbit(&n.prefix, n.pxlen); + } + + return anything ? ROA_INVALID : ROA_UNKNOWN; +} + +byte +net_roa_check(rtable *tab, const net_addr *n, u32 asn) +{ + if (tab->addr_type == NET_ROA4) + return net_roa4_check(tab, (const net_addr_ip4 *) n, asn); + else + return net_roa6_check(tab, (const net_addr_ip6 *) n, asn); +} + void * net_route(rtable *tab, const net_addr *n) {