diff options
author | Ondrej Filip <feela@network.cz> | 2012-08-07 11:15:23 +0200 |
---|---|---|
committer | Ondrej Filip <feela@network.cz> | 2012-08-07 11:15:23 +0200 |
commit | 60c412b9368fd7c3b0a8df2200f02140adcb0cf3 (patch) | |
tree | 237d3c0b8aa86c6f3a88a76141ab51ca94b1fcd7 /proto | |
parent | 3fe1d9e4a40663b93b59f5b6f9d61af9dc6a8ae6 (diff) | |
parent | 94e2f1c111721d6213ea65cac5c53036e38e3973 (diff) |
Merge branch 'master' of ssh://git.nic.cz/birdv1.3.8
Diffstat (limited to 'proto')
-rw-r--r-- | proto/bgp/attrs.c | 3 | ||||
-rw-r--r-- | proto/bgp/bgp.c | 15 | ||||
-rw-r--r-- | proto/bgp/bgp.h | 1 | ||||
-rw-r--r-- | proto/bgp/config.Y | 4 | ||||
-rw-r--r-- | proto/ospf/lsupd.c | 6 | ||||
-rw-r--r-- | proto/ospf/ospf.c | 2 | ||||
-rw-r--r-- | proto/ospf/rt.c | 4 | ||||
-rw-r--r-- | proto/ospf/topology.c | 15 | ||||
-rw-r--r-- | proto/ospf/topology.h | 2 | ||||
-rw-r--r-- | proto/radv/config.Y | 126 | ||||
-rw-r--r-- | proto/radv/packets.c | 181 | ||||
-rw-r--r-- | proto/radv/radv.c | 4 | ||||
-rw-r--r-- | proto/radv/radv.h | 31 |
13 files changed, 367 insertions, 27 deletions
diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index 4495c039..e5bc84dd 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -1258,7 +1258,8 @@ same_group(rte *r, u32 lpref, u32 lasn) static inline int use_deterministic_med(rte *r) { - return ((struct bgp_proto *) r->attrs->proto)->cf->deterministic_med; + struct proto *P = r->attrs->proto; + return (P->proto == &proto_bgp) && ((struct bgp_proto *) P)->cf->deterministic_med; } int diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index 3b9f7cc5..dbc59eea 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -870,6 +870,7 @@ bgp_shutdown(struct proto *P) break; case PDC_CMD_DISABLE: + case PDC_CMD_SHUTDOWN: subcode = 2; // Errcode 6, 2 - administrative shutdown break; @@ -923,7 +924,7 @@ bgp_init(struct proto_config *C) struct proto *P = proto_new(C, sizeof(struct bgp_proto)); struct bgp_proto *p = (struct bgp_proto *) P; - P->accept_ra_types = RA_OPTIMAL; + P->accept_ra_types = c->secondary ? RA_ACCEPTED : RA_OPTIMAL; P->rt_notify = bgp_rt_notify; P->rte_better = bgp_rte_better; P->import_control = bgp_import_control; @@ -969,6 +970,7 @@ bgp_check_config(struct bgp_config *c) if (internal && c->rs_client) cf_error("Only external neighbor can be RS client"); + if (c->multihop && (c->gw_mode == GW_DIRECT)) cf_error("Multihop BGP cannot use direct gateway mode"); @@ -976,6 +978,7 @@ bgp_check_config(struct bgp_config *c) ipa_has_link_scope(c->source_addr))) cf_error("Multihop BGP cannot be used with link-local addresses"); + /* Different default based on rs_client */ if (!c->missing_lladdr) c->missing_lladdr = c->rs_client ? MLL_IGNORE : MLL_SELF; @@ -987,6 +990,16 @@ bgp_check_config(struct bgp_config *c) /* Disable after error incompatible with restart limit action */ if (c->c.in_limit && (c->c.in_limit->action == PLA_RESTART) && c->disable_after_error) c->c.in_limit->action = PLA_DISABLE; + + + if ((c->gw_mode == GW_RECURSIVE) && c->c.table->sorted) + cf_error("BGP in recursive mode prohibits sorted table"); + + if (c->deterministic_med && c->c.table->sorted) + cf_error("BGP with deterministic MED prohibits sorted table"); + + if (c->secondary && !c->c.table->sorted) + cf_error("BGP with secondary option requires sorted table"); } static int diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index 1c16f485..c3adf254 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -42,6 +42,7 @@ struct bgp_config { int advertise_ipv4; /* Whether we should add IPv4 capability advertisement to OPEN message */ int passive; /* Do not initiate outgoing connection */ int interpret_communities; /* Hardwired handling of well-known communities */ + int secondary; /* Accept also non-best routes (i.e. RA_ACCEPTED) */ unsigned connect_retry_time; unsigned hold_time, initial_hold_time; unsigned keepalive_time; diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y index 5feaea0d..8b80d7fd 100644 --- a/proto/bgp/config.Y +++ b/proto/bgp/config.Y @@ -25,7 +25,8 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY, CLUSTER, ID, AS4, ADVERTISE, IPV4, CAPABILITIES, LIMIT, PASSIVE, PREFER, OLDER, MISSING, LLADDR, DROP, IGNORE, ROUTE, REFRESH, INTERPRET, COMMUNITIES, BGP_ORIGINATOR_ID, BGP_CLUSTER_LIST, IGP, - TABLE, GATEWAY, DIRECT, RECURSIVE, MED, TTL, SECURITY, DETERMINISTIC) + TABLE, GATEWAY, DIRECT, RECURSIVE, MED, TTL, SECURITY, DETERMINISTIC, + SECONDARY) CF_GRAMMAR @@ -105,6 +106,7 @@ bgp_proto: } | bgp_proto PASSIVE bool ';' { BGP_CFG->passive = $3; } | bgp_proto INTERPRET COMMUNITIES bool ';' { BGP_CFG->interpret_communities = $4; } + | bgp_proto SECONDARY bool ';' { BGP_CFG->secondary = $3; } | bgp_proto IGP TABLE rtable ';' { BGP_CFG->igp_table = $4; } | bgp_proto TTL SECURITY bool ';' { BGP_CFG->ttl_security = $4; } ; diff --git a/proto/ospf/lsupd.c b/proto/ospf/lsupd.c index f71c72d1..16967a7f 100644 --- a/proto/ospf/lsupd.c +++ b/proto/ospf/lsupd.c @@ -502,15 +502,17 @@ ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, continue; } #else /* OSPFv3 */ + u16 scope = ntoht(lsa->type) & LSA_SCOPE_MASK; + /* 4.5.1 (2) */ - if ((LSA_SCOPE(lsa) == LSA_SCOPE_AS) && !oa_is_ext(ifa->oa)) + if ((scope == LSA_SCOPE_AS) && !oa_is_ext(ifa->oa)) { log(L_WARN "Received LSA with AS scope in stub area from %I", n->ip); continue; } /* 4.5.1 (3) */ - if ((LSA_SCOPE(lsa) == LSA_SCOPE_RES)) + if (scope == LSA_SCOPE_RES) { log(L_WARN "Received LSA with invalid scope from %I", n->ip); continue; diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c index ef7b0363..aa62da14 100644 --- a/proto/ospf/ospf.c +++ b/proto/ospf/ospf.c @@ -575,7 +575,7 @@ ospf_rt_notify(struct proto *p, rtable *tbl UNUSED, net * n, rte * new, rte * ol if (fn->x1 != EXT_EXPORT) return; - flush_ext_lsa(oa, fn); + flush_ext_lsa(oa, fn, oa_is_nssa(oa)); /* Old external route might blocked some NSSA translation */ if (po->areano > 1) diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c index 42c54dfd..4b8de4b8 100644 --- a/proto/ospf/rt.c +++ b/proto/ospf/rt.c @@ -1066,7 +1066,7 @@ check_nssa_lsa(struct proto_ospf *po, ort *nf) originate_ext_lsa(po->backbone, fn, EXT_NSSA, rt_metric, rt_fwaddr, rt_tag, 0); else if (fn->x1 == EXT_NSSA) - flush_ext_lsa(po->backbone, fn); + flush_ext_lsa(po->backbone, fn, 0); } /* RFC 2328 16.7. p2 - find new/lost vlink endpoints */ @@ -1189,7 +1189,7 @@ ospf_rt_abr1(struct proto_ospf *po) if (oa_is_nssa(oa) && oa->ac->default_nssa) originate_ext_lsa(oa, &default_nf->fn, 0, oa->ac->default_cost, IPA_NONE, 0, 0); else - flush_ext_lsa(oa, &default_nf->fn); + flush_ext_lsa(oa, &default_nf->fn, 1); /* RFC 2328 16.4. (3) - precompute preferred ASBR entries */ diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c index 7e9bad50..ec012b22 100644 --- a/proto/ospf/topology.c +++ b/proto/ospf/topology.c @@ -862,6 +862,9 @@ flush_sum_lsa(struct ospf_area *oa, struct fib_node *fn, int type) if ((en = ospf_hash_find_header(po->gr, oa->areaid, &lsa)) != NULL) { + OSPF_TRACE(D_EVENTS, "Flushing summary-LSA (id=%R, type=%d)", + en->lsa.id, en->lsa.type); + if ((type == ORT_NET) && check_sum_net_lsaid_collision(fn, en)) { log(L_ERR "%s: LSAID collision for %I/%d", @@ -873,9 +876,6 @@ flush_sum_lsa(struct ospf_area *oa, struct fib_node *fn, int type) en->lsa.age = LSA_MAXAGE; en->lsa.sn = LSA_MAXSEQNO; lsasum_calculate(&en->lsa, sum); - - OSPF_TRACE(D_EVENTS, "Flushing summary-LSA (id=%R, type=%d)", - en->lsa.id, en->lsa.type); ospf_lsupd_flood(po, NULL, NULL, &en->lsa, oa->areaid, 1); if (can_flush_lsa(po)) flush_lsa(en, po); } @@ -1131,15 +1131,11 @@ originate_ext_lsa(struct ospf_area *oa, struct fib_node *fn, int src, } void -flush_ext_lsa(struct ospf_area *oa, struct fib_node *fn) +flush_ext_lsa(struct ospf_area *oa, struct fib_node *fn, int nssa) { struct proto_ospf *po = oa->po; struct proto *p = &po->proto; struct top_hash_entry *en; - int nssa = oa_is_nssa(oa); - - OSPF_TRACE(D_EVENTS, "Flushing %s-LSA for %I/%d", - nssa ? "NSSA" : "AS-external", fn->prefix, fn->pxlen); u32 dom = nssa ? oa->areaid : 0; u32 type = nssa ? LSA_T_NSSA : LSA_T_EXT; @@ -1147,6 +1143,9 @@ flush_ext_lsa(struct ospf_area *oa, struct fib_node *fn) if (en = ospf_hash_find(po->gr, dom, lsaid, po->router_id, type)) { + OSPF_TRACE(D_EVENTS, "Flushing %s-LSA for %I/%d", + nssa ? "NSSA" : "AS-external", fn->prefix, fn->pxlen); + if (check_ext_lsa(en, fn, 0, IPA_NONE, 0) < 0) { log(L_ERR "%s: LSAID collision for %I/%d", diff --git a/proto/ospf/topology.h b/proto/ospf/topology.h index b9bc9cf6..cb876487 100644 --- a/proto/ospf/topology.h +++ b/proto/ospf/topology.h @@ -72,7 +72,7 @@ void originate_sum_net_lsa(struct ospf_area *oa, struct fib_node *fn, int metric void originate_sum_rt_lsa(struct ospf_area *oa, struct fib_node *fn, int metric, u32 options UNUSED); void flush_sum_lsa(struct ospf_area *oa, struct fib_node *fn, int type); void originate_ext_lsa(struct ospf_area *oa, struct fib_node *fn, int src, u32 metric, ip_addr fwaddr, u32 tag, int pbit); -void flush_ext_lsa(struct ospf_area *oa, struct fib_node *fn); +void flush_ext_lsa(struct ospf_area *oa, struct fib_node *fn, int nssa); #ifdef OSPFv2 diff --git a/proto/radv/config.Y b/proto/radv/config.Y index 495d9a05..abccd2c7 100644 --- a/proto/radv/config.Y +++ b/proto/radv/config.Y @@ -14,32 +14,45 @@ CF_DEFINES #define RADV_CFG ((struct radv_config *) this_proto) #define RADV_IFACE ((struct radv_iface_config *) this_ipatt) #define RADV_PREFIX this_radv_prefix +#define RADV_RDNSS (&this_radv_rdnss) +#define RADV_DNSSL (&this_radv_dnssl) static struct radv_prefix_config *this_radv_prefix; +static struct radv_rdnss_config this_radv_rdnss; +static struct radv_dnssl_config this_radv_dnssl; +static list radv_dns_list; /* Used by radv_rdnss and radv_dnssl */ +static u8 radv_mult_val; /* Used by radv_mult for second return value */ + CF_DECLS CF_KEYWORDS(RADV, PREFIX, INTERFACE, MIN, MAX, RA, DELAY, INTERVAL, MANAGED, OTHER, CONFIG, LINK, MTU, REACHABLE, TIME, RETRANS, - TIMER, CURRENT, HOP, LIMIT, DEFAULT, VALID, PREFERRED, - LIFETIME, SKIP, ONLINK, AUTONOMOUS) + TIMER, CURRENT, HOP, LIMIT, DEFAULT, VALID, PREFERRED, MULT, + LIFETIME, SKIP, ONLINK, AUTONOMOUS, RDNSS, DNSSL, NS, DOMAIN, + LOCAL) +%type<i> radv_mult CF_GRAMMAR -CF_ADDTO(proto, radv_proto '}') +CF_ADDTO(proto, radv_proto) radv_proto_start: proto_start RADV { this_proto = proto_config_new(&proto_radv, sizeof(struct radv_config), $1); init_list(&RADV_CFG->patt_list); init_list(&RADV_CFG->pref_list); + init_list(&RADV_CFG->rdnss_list); + init_list(&RADV_CFG->dnssl_list); }; radv_proto_item: proto_item - | PREFIX radv_prefix { add_tail(&RADV_CFG->pref_list, NODE this_radv_prefix); } | INTERFACE radv_iface + | PREFIX radv_prefix { add_tail(&RADV_CFG->pref_list, NODE this_radv_prefix); } + | RDNSS { init_list(&radv_dns_list); } radv_rdnss { add_tail_list(&RADV_CFG->rdnss_list, &radv_dns_list); } + | DNSSL { init_list(&radv_dns_list); } radv_dnssl { add_tail_list(&RADV_CFG->dnssl_list, &radv_dns_list); } ; radv_proto_opts: @@ -48,7 +61,7 @@ radv_proto_opts: ; radv_proto: - radv_proto_start proto_name '{' radv_proto_opts; + radv_proto_start proto_name '{' radv_proto_opts '}'; radv_iface_start: @@ -57,6 +70,8 @@ radv_iface_start: add_tail(&RADV_CFG->patt_list, NODE this_ipatt); init_list(&this_ipatt->ipn_list); init_list(&RADV_IFACE->pref_list); + init_list(&RADV_IFACE->rdnss_list); + init_list(&RADV_IFACE->dnssl_list); RADV_IFACE->min_ra_int = -1; /* undefined */ RADV_IFACE->max_ra_int = DEFAULT_MAX_RA_INT; @@ -77,6 +92,10 @@ radv_iface_item: | CURRENT HOP LIMIT expr { RADV_IFACE->current_hop_limit = $4; if (($4 < 0) || ($4 > 255)) cf_error("Current hop limit must be in range 0-255"); } | DEFAULT LIFETIME expr { RADV_IFACE->default_lifetime = $3; if (($3 < 0) || ($3 > 9000)) cf_error("Default lifetime must be in range 0-9000"); } | PREFIX radv_prefix { add_tail(&RADV_IFACE->pref_list, NODE this_radv_prefix); } + | RDNSS { init_list(&radv_dns_list); } radv_rdnss { add_tail_list(&RADV_IFACE->rdnss_list, &radv_dns_list); } + | DNSSL { init_list(&radv_dns_list); } radv_dnssl { add_tail_list(&RADV_IFACE->dnssl_list, &radv_dns_list); } + | RDNSS LOCAL bool { RADV_IFACE->rdnss_local = $3; } + | DNSSL LOCAL bool { RADV_IFACE->dnssl_local = $3; } ; radv_iface_finish: @@ -152,6 +171,103 @@ radv_prefix: radv_prefix_start radv_prefix_opt_list radv_prefix_finish; + +radv_rdnss_node: ipa +{ + struct radv_rdnss_config *cf = cfg_allocz(sizeof(struct radv_rdnss_config)); + add_tail(&radv_dns_list, NODE cf); + + cf->server = $1; + cf->lifetime_mult = DEFAULT_DNS_LIFETIME_MULT; +}; + +radv_rdnss_start: +{ + RADV_RDNSS->lifetime = 0; + RADV_RDNSS->lifetime_mult = DEFAULT_DNS_LIFETIME_MULT; +}; + +radv_rdnss_item: + | NS radv_rdnss_node + | LIFETIME radv_mult { RADV_RDNSS->lifetime = $2; RADV_RDNSS->lifetime_mult = radv_mult_val; } + ; + +radv_rdnss_finish: +{ + if (EMPTY_LIST(radv_dns_list)) + cf_error("No nameserver in RDNSS section"); + + struct radv_rdnss_config *cf; + WALK_LIST(cf, radv_dns_list) + { + cf->lifetime = RADV_RDNSS->lifetime; + cf->lifetime_mult = RADV_RDNSS->lifetime_mult; + } +}; + +radv_rdnss_opts: + /* empty */ + | radv_rdnss_opts radv_rdnss_item ';' + ; + +radv_rdnss: + radv_rdnss_node + | '{' radv_rdnss_start radv_rdnss_opts '}' radv_rdnss_finish + ; + + +radv_dnssl_node: TEXT +{ + struct radv_dnssl_config *cf = cfg_allocz(sizeof(struct radv_dnssl_config)); + add_tail(&radv_dns_list, NODE cf); + + cf->domain = $1; + cf->lifetime_mult = DEFAULT_DNS_LIFETIME_MULT; + + if (radv_process_domain(cf) < 0) + cf_error("Invalid domain dame"); +}; + +radv_dnssl_start: +{ + RADV_DNSSL->lifetime = 0; + RADV_DNSSL->lifetime_mult = DEFAULT_DNS_LIFETIME_MULT; +}; + +radv_dnssl_item: + | DOMAIN radv_dnssl_node + | LIFETIME radv_mult { RADV_DNSSL->lifetime = $2; RADV_DNSSL->lifetime_mult = radv_mult_val; } + ; + +radv_dnssl_finish: +{ + if (EMPTY_LIST(radv_dns_list)) + cf_error("No domain in DNSSL section"); + + struct radv_dnssl_config *cf; + WALK_LIST(cf, radv_dns_list) + { + cf->lifetime = RADV_DNSSL->lifetime; + cf->lifetime_mult = RADV_DNSSL->lifetime_mult; + } +}; + +radv_dnssl_opts: + /* empty */ + | radv_dnssl_opts radv_dnssl_item ';' + ; + +radv_dnssl: + radv_dnssl_node + | '{' radv_dnssl_start radv_dnssl_opts '}' radv_dnssl_finish + ; + + +radv_mult: + expr { $$ = $1; radv_mult_val = 0; } + | MULT expr { $$ = 0; radv_mult_val = $2; if (($2 < 1) || ($2 > 254)) cf_error("Multiplier must be in range 1-254"); } + ; + CF_CODE CF_END diff --git a/proto/radv/packets.c b/proto/radv/packets.c index ac59ce94..6fdfcaa3 100644 --- a/proto/radv/packets.c +++ b/proto/radv/packets.c @@ -24,8 +24,10 @@ struct radv_ra_packet #define OPT_RA_MANAGED 0x80 #define OPT_RA_OTHER_CFG 0x40 -#define OPT_PREFIX 3 -#define OPT_MTU 5 +#define OPT_PREFIX 3 +#define OPT_MTU 5 +#define OPT_RDNSS 25 +#define OPT_DNSSL 31 struct radv_opt_prefix { @@ -50,6 +52,25 @@ struct radv_opt_mtu u32 mtu; }; +struct radv_opt_rdnss +{ + u8 type; + u8 length; + u16 reserved; + u32 lifetime; + ip_addr servers[]; +}; + +struct radv_opt_dnssl +{ + u8 type; + u8 length; + u16 reserved; + u32 lifetime; + char domain[]; +}; + + static struct radv_prefix_config default_prefix = { .onlink = 1, .autonomous = 1, @@ -57,6 +78,7 @@ static struct radv_prefix_config default_prefix = { .preferred_lifetime = DEFAULT_PREFERRED_LIFETIME }; + static struct radv_prefix_config * radv_prefix_match(struct radv_iface *ifa, struct ifa *a) { @@ -78,10 +100,146 @@ radv_prefix_match(struct radv_iface *ifa, struct ifa *a) return &default_prefix; } +static int +radv_prepare_rdnss(struct radv_iface *ifa, list *rdnss_list, char **buf, char *bufend) +{ + struct radv_rdnss_config *rcf = HEAD(*rdnss_list); + + while(NODE_VALID(rcf)) + { + struct radv_rdnss_config *rcf_base = rcf; + struct radv_opt_rdnss *op = (void *) *buf; + int max_i = (bufend - *buf - sizeof(struct radv_opt_rdnss)) / sizeof(ip_addr); + int i = 0; + + if (max_i < 1) + goto too_much; + + op->type = OPT_RDNSS; + op->reserved = 0; + + if (rcf->lifetime_mult) + op->lifetime = htonl(rcf->lifetime_mult * ifa->cf->max_ra_int); + else + op->lifetime = htonl(rcf->lifetime); + + while(NODE_VALID(rcf) && + (rcf->lifetime == rcf_base->lifetime) && + (rcf->lifetime_mult == rcf_base->lifetime_mult)) + { + if (i >= max_i) + goto too_much; + + op->servers[i] = rcf->server; + ipa_hton(op->servers[i]); + i++; + + rcf = NODE_NEXT(rcf); + } + + op->length = 1+2*i; + *buf += 8 * op->length; + } + + return 0; + + too_much: + log(L_WARN "%s: Too many RA options on interface %s", + ifa->ra->p.name, ifa->iface->name); + return -1; +} + +int +radv_process_domain(struct radv_dnssl_config *cf) +{ + /* Format of domain in search list is <size> <label> <size> <label> ... 0 */ + + char *dom = cf->domain; + char *dom_end = dom; /* Just to */ + u8 *dlen_save = &cf->dlen_first; + int len; + + while (dom_end) + { + dom_end = strchr(dom, '.'); + len = dom_end ? (dom_end - dom) : strlen(dom); + + if (len < 1 || len > 63) + return -1; + + *dlen_save = len; + dlen_save = (u8 *) dom_end; + + dom += len + 1; + } + + len = dom - cf->domain; + if (len > 254) + return -1; + + cf->dlen_all = len; + + return 0; +} + +static int +radv_prepare_dnssl(struct radv_iface *ifa, list *dnssl_list, char **buf, char *bufend) +{ + struct radv_dnssl_config *dcf = HEAD(*dnssl_list); + + while(NODE_VALID(dcf)) + { + struct radv_dnssl_config *dcf_base = dcf; + struct radv_opt_dnssl *op = (void *) *buf; + int bsize = bufend - *buf - sizeof(struct radv_opt_dnssl); + int bpos = 0; + + if (bsize < 0) + goto too_much; + + bsize = bsize & ~7; /* Round down to multiples of 8 */ + + op->type = OPT_DNSSL; + op->reserved = 0; + + if (dcf->lifetime_mult) + op->lifetime = htonl(dcf->lifetime_mult * ifa->cf->max_ra_int); + else + op->lifetime = htonl(dcf->lifetime); + + while(NODE_VALID(dcf) && + (dcf->lifetime == dcf_base->lifetime) && + (dcf->lifetime_mult == dcf_base->lifetime_mult)) + { + if (bpos + dcf->dlen_all + 1 > bsize) + goto too_much; + + op->domain[bpos++] = dcf->dlen_first; + memcpy(op->domain + bpos, dcf->domain, dcf->dlen_all); + bpos += dcf->dlen_all; + + dcf = NODE_NEXT(dcf); + } + + int blen = (bpos + 7) / 8; + bzero(op->domain + bpos, 8 * blen - bpos); + op->length = 1 + blen; + *buf += 8 * op->length; + } + + return 0; + + too_much: + log(L_WARN "%s: Too many RA options on interface %s", + ifa->ra->p.name, ifa->iface->name); + return -1; +} + static void radv_prepare_ra(struct radv_iface *ifa) { struct proto_radv *ra = ifa->ra; + struct radv_config *cf = (struct radv_config *) (ra->p.cf); char *buf = ifa->sk->tbuf; char *bufstart = buf; @@ -121,7 +279,7 @@ radv_prepare_ra(struct radv_iface *ifa) if (buf + sizeof(struct radv_opt_prefix) > bufend) { log(L_WARN "%s: Too many prefixes on interface %s", ra->p.name, ifa->iface->name); - break; + goto done; } struct radv_opt_prefix *op = (void *) buf; @@ -137,7 +295,22 @@ radv_prepare_ra(struct radv_iface *ifa) ipa_hton(op->prefix); buf += sizeof(*op); } - + + if (! ifa->cf->rdnss_local) + if (radv_prepare_rdnss(ifa, &cf->rdnss_list, &buf, bufend) < 0) + goto done; + + if (radv_prepare_rdnss(ifa, &ifa->cf->rdnss_list, &buf, bufend) < 0) + goto done; + + if (! ifa->cf->dnssl_local) + if (radv_prepare_dnssl(ifa, &cf->dnssl_list, &buf, bufend) < 0) + goto done; + + if (radv_prepare_dnssl(ifa, &ifa->cf->dnssl_list, &buf, bufend) < 0) + goto done; + + done: ifa->plen = buf - bufstart; } diff --git a/proto/radv/radv.c b/proto/radv/radv.c index d6fc8da5..5e7296a3 100644 --- a/proto/radv/radv.c +++ b/proto/radv/radv.c @@ -29,6 +29,10 @@ * radv_iface_notify(), which processes asynchronous events (specified * by RA_EV_* codes), and radv_timer(), which triggers sending RAs and * computes the next timeout. + * + * Supported standards: + * - RFC 4861 - main RA standard + * - RFC 6106 - DNS extensions (RDDNS, DNSSL) */ static void diff --git a/proto/radv/radv.h b/proto/radv/radv.h index 12bfe42e..48af8c00 100644 --- a/proto/radv/radv.h +++ b/proto/radv/radv.h @@ -42,24 +42,33 @@ #define DEFAULT_VALID_LIFETIME 86400 #define DEFAULT_PREFERRED_LIFETIME 14400 +#define DEFAULT_DNS_LIFETIME_MULT 3 + struct radv_config { struct proto_config c; list patt_list; /* List of iface configs (struct radv_iface_config) */ list pref_list; /* Global list of prefix configs (struct radv_prefix_config) */ + list rdnss_list; /* Global list of RDNSS configs (struct radv_rdnss_config) */ + list dnssl_list; /* Global list of DNSSL configs (struct radv_dnssl_config) */ }; struct radv_iface_config { struct iface_patt i; list pref_list; /* Local list of prefix configs (struct radv_prefix_config) */ + list rdnss_list; /* Local list of RDNSS configs (struct radv_rdnss_config) */ + list dnssl_list; /* Local list of DNSSL configs (struct radv_dnssl_config) */ u32 min_ra_int; /* Standard options from RFC 4261 */ u32 max_ra_int; u32 min_delay; - u8 managed; + u8 rdnss_local; /* Global list is not used for RDNSS */ + u8 dnssl_local; /* Global list is not used for DNSSL */ + + u8 managed; /* Standard options from RFC 4261 */ u8 other_config; u32 link_mtu; u32 reachable_time; @@ -81,6 +90,25 @@ struct radv_prefix_config u32 preferred_lifetime; }; +struct radv_rdnss_config +{ + node n; + u32 lifetime; /* Valid if lifetime_mult is 0 */ + u16 lifetime_mult; /* Lifetime specified as multiple of max_ra_int */ + ip_addr server; /* IP address of recursive DNS server */ +}; + +struct radv_dnssl_config +{ + node n; + u32 lifetime; /* Valid if lifetime_mult is 0 */ + u16 lifetime_mult; /* Lifetime specified as multiple of max_ra_int */ + u8 dlen_first; /* Length of first label in domain */ + u8 dlen_all; /* Both dlen_ filled in radv_process_domain() */ + char *domain; /* Domain for DNS search list, in processed form */ +}; + + struct proto_radv { struct proto p; @@ -123,6 +151,7 @@ struct radv_iface void radv_iface_notify(struct radv_iface *ifa, int event); /* packets.c */ +int radv_process_domain(struct radv_dnssl_config *cf); void radv_send_ra(struct radv_iface *ifa, int shutdown); int radv_sk_open(struct radv_iface *ifa); |