diff --git a/client/Makefile b/client/Makefile index 9bdcb815..fccb8346 100644 --- a/client/Makefile +++ b/client/Makefile @@ -3,7 +3,7 @@ obj := $(src-o-files) $(all-client) -$(o)commands.c.dep: $(objdir)/conf/commands.h +$(o)commands.o: $(objdir)/conf/commands.h $(exedir)/birdc: $(o)birdc.o $(exedir)/birdc: LIBS += $(CLIENT_LIBS) diff --git a/conf/Makefile b/conf/Makefile index c4121805..76fd496a 100644 --- a/conf/Makefile +++ b/conf/Makefile @@ -8,12 +8,6 @@ BISON_DEBUG=-t #FLEX_DEBUG=-d endif -$(o)cf-parse.tab.h: $(o)cf-parse.tab.c - -$(o)cf-parse.tab.c: $(o)cf-parse.y - echo $< $@ $(o) - $(BISON) -b$(@:.tab.c=) -dv -pcf_ $(BISON_DEBUG) $< - $(conf-y-targets): $(s)confbase.Y $(M4) -P $| $^ >$@ @@ -21,9 +15,16 @@ $(o)cf-parse.y: | $(s)gen_parser.m4 $(o)keywords.h: | $(s)gen_keywords.m4 $(o)commands.h: | $(s)gen_commands.m4 $(srcdir)/client/cmds.m4 -$(o)cf-lex.c: $(s)cf-lex.l $(o)cf-parse.tab.h $(o)keywords.h $(o)commands.h - $(FLEX) $(FLEX_DEBUG) -s -B -8 -o$@ -Pcf_ $< +$(o)cf-parse.tab.h: $(o)cf-parse.tab.c -$(addprefix $(o),cf-parse.tab.h cf-parse.tab.c cf-parse.y keywords.h commands.h cf-lex.c): $(objdir)/.dir-stamp +$(o)cf-parse.tab.c: $(o)cf-parse.y + $(BISON) $(BISON_DEBUG) -dv -pcf_ -b $(@:.tab.c=) $< + +$(o)cf-lex.c: $(s)cf-lex.l + $(FLEX) $(FLEX_DEBUG) -s -B -8 -Pcf_ -o $@ $< + +$(o)cf-lex.o: $(o)cf-parse.tab.h $(o)keywords.h + +$(addprefix $(o), cf-parse.y keywords.h commands.h cf-parse.tab.h cf-parse.tab.c cf-lex.c): $(objdir)/.dir-stamp $(call clean,cf-parse.tab.h cf-parse.tab.c cf-parse.y keywords.h commands.h cf-lex.c cf-parse.output) diff --git a/conf/confbase.Y b/conf/confbase.Y index d5fd2133..e64d7593 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -201,21 +201,17 @@ net_ip6_: IP6 '/' NUM net_roa4_: net_ip4_ MAX NUM AS NUM { $$ = cfg_alloc(sizeof(net_addr_roa4)); - net_fill_roa4($$, ((net_addr_ip4 *)&$1)->prefix, $1.pxlen, $3, $5); - if ($3 < 0 || $3 > IP4_MAX_PREFIX_LENGTH) + net_fill_roa4($$, net4_prefix(&$1), net4_pxlen(&$1), $3, $5); + if ($3 < net4_pxlen(&$1) || $3 > IP4_MAX_PREFIX_LENGTH) cf_error("Invalid max prefix length %d", $3); - if (((net_addr_roa4 *) $$)->max_pxlen < ($$)->pxlen) - cf_error("Maximum prefix length %d must be >= prefix length %d", ((net_addr_roa4 *) $$)->max_pxlen, ($$)->pxlen); }; net_roa6_: net_ip6_ MAX NUM AS NUM { $$ = cfg_alloc(sizeof(net_addr_roa6)); - net_fill_roa6($$, ((net_addr_ip6 *)&$1)->prefix, $1.pxlen, $3, $5); - if ($3 < 0 || $3 > IP6_MAX_PREFIX_LENGTH) + net_fill_roa6($$, net6_prefix(&$1), net6_pxlen(&$1), $3, $5); + if ($3 < net6_pxlen(&$1) || $3 > IP6_MAX_PREFIX_LENGTH) cf_error("Invalid max prefix length %d", $3); - if (((net_addr_roa6 *) $$)->max_pxlen < ($$)->pxlen) - cf_error("Maximum prefix length %d must be >= prefix length %d", ((net_addr_roa6 *) $$)->max_pxlen, ($$)->pxlen); }; net_ip_: net_ip4_ | net_ip6_ ; diff --git a/filter/filter.c b/filter/filter.c index cc1bb3dc..7b3e550f 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -1277,9 +1277,13 @@ interpret(struct f_inst *what) } 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)) + if (!table) runtime("Missing ROA table"); + /* Table type is either NET_ROA4 or NET_ROA6, checked in parser */ + if (v1.val.net->type != ((table->addr_type == NET_ROA4) ? NET_IP4 : NET_IP6)) + runtime("Incompatible net type"); + res.type = T_ENUM_ROA; res.val.i = net_roa_check(table, v1.val.net, as); diff --git a/lib/net.c b/lib/net.c index 71fbe6ff..55eec4b5 100644 --- a/lib/net.c +++ b/lib/net.c @@ -8,7 +8,9 @@ const char * const net_label[] = { [NET_IP4] = "ipv4", [NET_IP6] = "ipv6", [NET_VPN4] = "vpn4", - [NET_VPN6] = "vpn6" + [NET_VPN6] = "vpn6", + [NET_ROA4] = "roa4", + [NET_ROA6] = "roa6", }; const u16 net_addr_length[] = { @@ -34,8 +36,8 @@ const u16 net_max_text_length[] = { [NET_IP6] = 43, /* "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128" */ [NET_VPN4] = 40, /* "4294967296:4294967296 255.255.255.255/32" */ [NET_VPN6] = 65, /* "4294967296:4294967296 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128" */ - [NET_ROA4] = 30, /* "255.255.255.255/32 AS4294967295" */ - [NET_ROA6] = 56, /* "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128 AS4294967295" */ + [NET_ROA4] = 34, /* "255.255.255.255/32-32 AS4294967295" */ + [NET_ROA6] = 60, /* "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128-128 AS4294967295" */ }; diff --git a/lib/net.h b/lib/net.h index fbce2811..d9137c4a 100644 --- a/lib/net.h +++ b/lib/net.h @@ -25,6 +25,8 @@ #define NB_IP6 (1 << NET_IP6) #define NB_VPN4 (1 << NET_VPN4) #define NB_VPN6 (1 << NET_VPN6) +#define NB_ROA4 (1 << NET_ROA4) +#define NB_ROA6 (1 << NET_ROA6) #define NB_IP (NB_IP4 | NB_IP6) #define NB_ANY 0xffffffff @@ -228,6 +230,12 @@ static inline int net_equal_roa4(const net_addr_roa4 *a, const net_addr_roa4 *b) static inline int net_equal_roa6(const net_addr_roa6 *a, const net_addr_roa6 *b) { return !memcmp(a, b, sizeof(net_addr_roa6)); } +static inline int net_equal_prefix_roa4(const net_addr_roa4 *a, const net_addr_roa4 *b) +{ return ip4_equal(a->prefix, b->prefix) && (a->pxlen == b->pxlen); } + +static inline int net_equal_prefix_roa6(const net_addr_roa6 *a, const net_addr_roa6 *b) +{ return ip6_equal(a->prefix, b->prefix) && (a->pxlen == b->pxlen); } + static inline int net_zero_ip4(const net_addr_ip4 *a) { return !a->pxlen && ip4_zero(a->prefix); } diff --git a/nest/config.Y b/nest/config.Y index 94a67670..890a6d09 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -447,13 +447,11 @@ password_item_begin: ; password_item_params: - /* empty */ { } + /* empty */ { } | GENERATE FROM datetime ';' password_item_params { this_p_item->genfrom = $3; } | GENERATE TO datetime ';' password_item_params { this_p_item->gento = $3; } - | GENERATE FROM datetime TO datetime ';' password_item_params { this_p_item->genfrom = $3; this_p_item->gento = $5; } | ACCEPT FROM datetime ';' password_item_params { this_p_item->accfrom = $3; } | ACCEPT TO datetime ';' password_item_params { this_p_item->accto = $3; } - | ACCEPT FROM datetime TO datetime ';' password_item_params { this_p_item->accfrom = $3; this_p_item->accto = $5; } | ID expr ';' password_item_params { this_p_item->id = $2; if ($2 <= 0) cf_error("Password ID has to be greated than zero."); } ; diff --git a/nest/proto.c b/nest/proto.c index df4952b7..ce859f13 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -39,12 +39,7 @@ static int graceful_restart_state; static u32 graceful_restart_locks; static char *p_states[] = { "DOWN", "START", "UP", "STOP" }; -static char *cs_states[] = { - [CS_DOWN] = "DOWN", - [CS_START] = "START", - [CS_UP] = "UP", - [CS_FLUSHING] = "FLUSHING" -}; +static char *c_states[] UNUSED = { "DOWN", "START", "UP", "FLUSHING" }; extern struct protocol proto_unix_iface; @@ -320,7 +315,7 @@ channel_set_state(struct channel *c, uint state) uint cs = c->channel_state; uint es = c->export_state; - DBG("%s reporting channel %s state transition %s -> %s\n", c->proto->name, c->name, cs_states[cs], cs_states[state]); + DBG("%s reporting channel %s state transition %s -> %s\n", c->proto->name, c->name, c_states[cs], c_states[state]); if (state == cs) return; @@ -1016,7 +1011,7 @@ proto_rethink_goal(struct proto *p) * enabled protocols are marked with @gr_recovery flag before start. Such * protocols then decide how to proceed with graceful restart, participation is * voluntary. Protocols could lock the recovery for each channel by function - * channel_graceful_restart_lock() (starte stored in @gr_lock flag), which means + * channel_graceful_restart_lock() (state stored in @gr_lock flag), which means * that they want to postpone the end of the recovery until they converge and * then unlock it. They also could set @gr_wait before advancing to %PS_UP, * which means that the core should defer route export to that channel until diff --git a/nest/route.h b/nest/route.h index 39475309..865b0907 100644 --- a/nest/route.h +++ b/nest/route.h @@ -273,7 +273,8 @@ void rt_unlock_table(rtable *); void rt_setup(pool *, rtable *, char *, struct rtable_config *); 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); } - +void *net_route(rtable *tab, const net_addr *n); +int 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 *); void rte_update2(struct channel *c, net_addr *n, rte *new, struct rte_src *src); @@ -561,6 +562,4 @@ extern struct protocol *attr_class_to_protocol[EAP_MAX]; #define ROA_VALID 1 #define ROA_INVALID 2 -byte net_roa_check(rtable *tab, const net_addr *n, u32 asn); - #endif diff --git a/nest/rt-table.c b/nest/rt-table.c index 9614d9ef..2329bb53 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -98,77 +98,6 @@ 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) { @@ -194,6 +123,97 @@ net_route(rtable *tab, const net_addr *n) } } + +static int +net_roa_check_ip4(rtable *tab, const net_addr_ip4 *px, u32 asn) +{ + struct net_addr_roa4 n = NET_ADDR_ROA4(px->prefix, px->pxlen, 0, 0); + struct fib_node *fn; + int anything = 0; + + while (1) + { + for (fn = fib_get_chain(&tab->fib, (net_addr *) &n); fn; fn = fn->next) + { + net_addr_roa4 *roa = (void *) fn->addr; + net *r = fib_node_to_user(&tab->fib, fn); + + if (net_equal_prefix_roa4(roa, &n) && rte_is_valid(r->routes)) + { + 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 int +net_roa_check_ip6(rtable *tab, const net_addr_ip6 *px, u32 asn) +{ + struct net_addr_roa6 n = NET_ADDR_ROA6(px->prefix, px->pxlen, 0, 0); + struct fib_node *fn; + int anything = 0; + + while (1) + { + for (fn = fib_get_chain(&tab->fib, (net_addr *) &n); fn; fn = fn->next) + { + net_addr_roa6 *roa = (void *) fn->addr; + net *r = fib_node_to_user(&tab->fib, fn); + + if (net_equal_prefix_roa6(roa, &n) && rte_is_valid(r->routes)) + { + 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; +} + +/** + * roa_check - check validity of route origination in a ROA table + * @tab: ROA table + * @n: network prefix to check + * @asn: AS number of network prefix + * + * Implements RFC 6483 route validation for the given network prefix. The + * procedure is to find all candidate ROAs - ROAs whose prefixes cover the given + * network prefix. If there is no candidate ROA, return ROA_UNKNOWN. If there is + * a candidate ROA with matching ASN and maxlen field greater than or equal to + * the given prefix length, return ROA_VALID. Otherwise, return ROA_INVALID. If + * caller cannot determine origin AS, 0 could be used (in that case ROA_VALID + * cannot happen). Table @tab must have type NET_ROA4 or NET_ROA6, network @n + * must have type NET_IP4 or NET_IP6, respectively. + */ +int +net_roa_check(rtable *tab, const net_addr *n, u32 asn) +{ + if ((tab->addr_type == NET_ROA4) && (n->type == NET_IP4)) + return net_roa_check_ip4(tab, (const net_addr_ip4 *) n, asn); + else if ((tab->addr_type == NET_ROA6) && (n->type == NET_IP6)) + return net_roa_check_ip6(tab, (const net_addr_ip6 *) n, asn); + else + return ROA_UNKNOWN; /* Should not happen */ +} + /** * rte_find - find a route * @net: network node @@ -1553,6 +1573,8 @@ rt_event(void *ptr) { rtable *tab = ptr; + rt_lock_table(tab); + if (tab->hcu_scheduled) rt_update_hostcache(tab); @@ -1561,6 +1583,8 @@ rt_event(void *ptr) if (tab->prune_state) rt_prune_table(tab); + + rt_unlock_table(tab); } void @@ -1693,10 +1717,7 @@ again: if (c->flush_active) { c->flush_active = 0; - struct rtable_config *rtab_cf = c->table->config; - channel_set_state(c, CS_DOWN); /* Can free (struct rtable *) c->table */ - if (rtab_cf->table == NULL) - break; + channel_set_state(c, CS_DOWN); } return; diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c index 4db6abb7..08521d75 100644 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@ -1547,8 +1547,7 @@ sk_sendmsg(sock *s) { struct iovec iov = {s->tbuf, s->tpos - s->tbuf}; byte cmsg_buf[CMSG_TX_SPACE]; - bzero(cmsg_buf, sizeof(cmsg_buf)); - sockaddr dst = {}; + sockaddr dst; sockaddr_fill(&dst, fam_to_af[s->fam], s->daddr, s->iface, s->dport);