Return to packets.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / bird2 / proto / radv |
1.1 ! misho 1: /* ! 2: * BIRD -- RAdv Packet Processing ! 3: * ! 4: * (c) 2011--2019 Ondrej Zajicek <santiago@crfreenet.org> ! 5: * (c) 2011--2019 CZ.NIC z.s.p.o. ! 6: * ! 7: * Can be freely distributed and used under the terms of the GNU GPL. ! 8: */ ! 9: ! 10: ! 11: #include <stdlib.h> ! 12: #include "radv.h" ! 13: ! 14: struct radv_ra_packet ! 15: { ! 16: u8 type; ! 17: u8 code; ! 18: u16 checksum; ! 19: u8 current_hop_limit; ! 20: u8 flags; ! 21: u16 router_lifetime; ! 22: u32 reachable_time; ! 23: u32 retrans_timer; ! 24: }; ! 25: ! 26: #define OPT_RA_MANAGED 0x80 ! 27: #define OPT_RA_OTHER_CFG 0x40 ! 28: ! 29: #define OPT_PREFIX 3 ! 30: #define OPT_MTU 5 ! 31: #define OPT_ROUTE 24 ! 32: #define OPT_RDNSS 25 ! 33: #define OPT_DNSSL 31 ! 34: ! 35: struct radv_opt_prefix ! 36: { ! 37: u8 type; ! 38: u8 length; ! 39: u8 pxlen; ! 40: u8 flags; ! 41: u32 valid_lifetime; ! 42: u32 preferred_lifetime; ! 43: u32 reserved; ! 44: ip6_addr prefix; ! 45: }; ! 46: ! 47: #define OPT_PX_ONLINK 0x80 ! 48: #define OPT_PX_AUTONOMOUS 0x40 ! 49: ! 50: struct radv_opt_mtu ! 51: { ! 52: u8 type; ! 53: u8 length; ! 54: u16 reserved; ! 55: u32 mtu; ! 56: }; ! 57: ! 58: struct radv_opt_route { ! 59: u8 type; ! 60: u8 length; ! 61: u8 pxlen; ! 62: u8 flags; ! 63: u32 lifetime; ! 64: u8 prefix[]; ! 65: }; ! 66: ! 67: struct radv_opt_rdnss ! 68: { ! 69: u8 type; ! 70: u8 length; ! 71: u16 reserved; ! 72: u32 lifetime; ! 73: ip6_addr servers[]; ! 74: }; ! 75: ! 76: struct radv_opt_dnssl ! 77: { ! 78: u8 type; ! 79: u8 length; ! 80: u16 reserved; ! 81: u32 lifetime; ! 82: char domain[]; ! 83: }; ! 84: ! 85: static int ! 86: radv_prepare_route(struct radv_iface *ifa, struct radv_route *rt, ! 87: char **buf, char *bufend) ! 88: { ! 89: struct radv_proto *p = ifa->ra; ! 90: u8 px_blocks = (net6_pxlen(rt->n.addr) + 63) / 64; ! 91: u8 opt_len = 8 * (1 + px_blocks); ! 92: ! 93: if (*buf + opt_len > bufend) ! 94: { ! 95: log(L_WARN, "%s: Too many RA options on interface %s", ! 96: p->p.name, ifa->iface->name); ! 97: return -1; ! 98: } ! 99: ! 100: uint preference = rt->preference_set ? rt->preference : ifa->cf->route_preference; ! 101: uint lifetime = rt->lifetime_set ? rt->lifetime : ifa->cf->route_lifetime; ! 102: uint valid = rt->valid && p->valid && (p->active || !ifa->cf->route_lifetime_sensitive); ! 103: ! 104: struct radv_opt_route *opt = (void *) *buf; ! 105: *buf += opt_len; ! 106: opt->type = OPT_ROUTE; ! 107: opt->length = 1 + px_blocks; ! 108: opt->pxlen = net6_pxlen(rt->n.addr); ! 109: opt->flags = preference; ! 110: opt->lifetime = valid ? htonl(lifetime) : 0; ! 111: ! 112: /* Copy the relevant part of the prefix */ ! 113: ip6_addr px_addr = ip6_hton(net6_prefix(rt->n.addr)); ! 114: memcpy(opt->prefix, &px_addr, 8 * px_blocks); ! 115: ! 116: /* Keeping track of first linger timeout */ ! 117: if (!rt->valid) ! 118: ifa->valid_time = MIN(ifa->valid_time, rt->changed + ifa->cf->route_linger_time S); ! 119: ! 120: return 0; ! 121: } ! 122: ! 123: static int ! 124: radv_prepare_rdnss(struct radv_iface *ifa, list *rdnss_list, char **buf, char *bufend) ! 125: { ! 126: struct radv_rdnss_config *rcf = HEAD(*rdnss_list); ! 127: ! 128: while(NODE_VALID(rcf)) ! 129: { ! 130: struct radv_rdnss_config *rcf_base = rcf; ! 131: struct radv_opt_rdnss *op = (void *) *buf; ! 132: int max_i = (bufend - *buf - sizeof(struct radv_opt_rdnss)) / sizeof(ip6_addr); ! 133: int i = 0; ! 134: ! 135: if (max_i < 1) ! 136: goto too_much; ! 137: ! 138: op->type = OPT_RDNSS; ! 139: op->reserved = 0; ! 140: ! 141: if (rcf->lifetime_mult) ! 142: op->lifetime = htonl(rcf->lifetime_mult * ifa->cf->max_ra_int); ! 143: else ! 144: op->lifetime = htonl(rcf->lifetime); ! 145: ! 146: while(NODE_VALID(rcf) && ! 147: (rcf->lifetime == rcf_base->lifetime) && ! 148: (rcf->lifetime_mult == rcf_base->lifetime_mult)) ! 149: { ! 150: if (i >= max_i) ! 151: goto too_much; ! 152: ! 153: op->servers[i] = ip6_hton(rcf->server); ! 154: i++; ! 155: ! 156: rcf = NODE_NEXT(rcf); ! 157: } ! 158: ! 159: op->length = 1+2*i; ! 160: *buf += 8 * op->length; ! 161: } ! 162: ! 163: return 0; ! 164: ! 165: too_much: ! 166: log(L_WARN "%s: Too many RA options on interface %s", ! 167: ifa->ra->p.name, ifa->iface->name); ! 168: return -1; ! 169: } ! 170: ! 171: int ! 172: radv_process_domain(struct radv_dnssl_config *cf) ! 173: { ! 174: /* Format of domain in search list is <size> <label> <size> <label> ... 0 */ ! 175: ! 176: char *dom = cf->domain; ! 177: char *dom_end = dom; /* Just to */ ! 178: u8 *dlen_save = &cf->dlen_first; ! 179: uint len; ! 180: ! 181: while (dom_end) ! 182: { ! 183: dom_end = strchr(dom, '.'); ! 184: len = dom_end ? (uint)(dom_end - dom) : strlen(dom); ! 185: ! 186: if (len < 1 || len > 63) ! 187: return -1; ! 188: ! 189: *dlen_save = len; ! 190: dlen_save = (u8 *) dom_end; ! 191: ! 192: dom += len + 1; ! 193: } ! 194: ! 195: len = dom - cf->domain; ! 196: if (len > 254) ! 197: return -1; ! 198: ! 199: cf->dlen_all = len; ! 200: ! 201: return 0; ! 202: } ! 203: ! 204: static int ! 205: radv_prepare_dnssl(struct radv_iface *ifa, list *dnssl_list, char **buf, char *bufend) ! 206: { ! 207: struct radv_dnssl_config *dcf = HEAD(*dnssl_list); ! 208: ! 209: while(NODE_VALID(dcf)) ! 210: { ! 211: struct radv_dnssl_config *dcf_base = dcf; ! 212: struct radv_opt_dnssl *op = (void *) *buf; ! 213: int bsize = bufend - *buf - sizeof(struct radv_opt_dnssl); ! 214: int bpos = 0; ! 215: ! 216: if (bsize < 0) ! 217: goto too_much; ! 218: ! 219: bsize = bsize & ~7; /* Round down to multiples of 8 */ ! 220: ! 221: op->type = OPT_DNSSL; ! 222: op->reserved = 0; ! 223: ! 224: if (dcf->lifetime_mult) ! 225: op->lifetime = htonl(dcf->lifetime_mult * ifa->cf->max_ra_int); ! 226: else ! 227: op->lifetime = htonl(dcf->lifetime); ! 228: ! 229: while(NODE_VALID(dcf) && ! 230: (dcf->lifetime == dcf_base->lifetime) && ! 231: (dcf->lifetime_mult == dcf_base->lifetime_mult)) ! 232: { ! 233: if (bpos + dcf->dlen_all + 1 > bsize) ! 234: goto too_much; ! 235: ! 236: op->domain[bpos++] = dcf->dlen_first; ! 237: memcpy(op->domain + bpos, dcf->domain, dcf->dlen_all); ! 238: bpos += dcf->dlen_all; ! 239: ! 240: dcf = NODE_NEXT(dcf); ! 241: } ! 242: ! 243: int blen = (bpos + 7) / 8; ! 244: bzero(op->domain + bpos, 8 * blen - bpos); ! 245: op->length = 1 + blen; ! 246: *buf += 8 * op->length; ! 247: } ! 248: ! 249: return 0; ! 250: ! 251: too_much: ! 252: log(L_WARN "%s: Too many RA options on interface %s", ! 253: ifa->ra->p.name, ifa->iface->name); ! 254: return -1; ! 255: } ! 256: ! 257: static int ! 258: radv_prepare_prefix(struct radv_iface *ifa, struct radv_prefix *px, ! 259: char **buf, char *bufend) ! 260: { ! 261: struct radv_prefix_config *pc = px->cf; ! 262: ! 263: if (*buf + sizeof(struct radv_opt_prefix) > bufend) ! 264: { ! 265: log(L_WARN "%s: Too many prefixes on interface %s", ! 266: ifa->ra->p.name, ifa->iface->name); ! 267: return -1; ! 268: } ! 269: ! 270: struct radv_opt_prefix *op = (void *) *buf; ! 271: op->type = OPT_PREFIX; ! 272: op->length = 4; ! 273: op->pxlen = px->prefix.pxlen; ! 274: op->flags = (pc->onlink ? OPT_PX_ONLINK : 0) | ! 275: (pc->autonomous ? OPT_PX_AUTONOMOUS : 0); ! 276: op->valid_lifetime = (ifa->ra->active || !pc->valid_lifetime_sensitive) ? ! 277: htonl(pc->valid_lifetime) : 0; ! 278: op->preferred_lifetime = (ifa->ra->active || !pc->preferred_lifetime_sensitive) ? ! 279: htonl(pc->preferred_lifetime) : 0; ! 280: op->reserved = 0; ! 281: op->prefix = ip6_hton(px->prefix.prefix); ! 282: *buf += sizeof(*op); ! 283: ! 284: /* Keeping track of first linger timeout */ ! 285: if (!px->valid) ! 286: ifa->valid_time = MIN(ifa->valid_time, px->changed + ifa->cf->prefix_linger_time S); ! 287: ! 288: return 0; ! 289: } ! 290: ! 291: static void ! 292: radv_prepare_ra(struct radv_iface *ifa) ! 293: { ! 294: struct radv_proto *p = ifa->ra; ! 295: struct radv_config *cf = (struct radv_config *) (p->p.cf); ! 296: struct radv_iface_config *ic = ifa->cf; ! 297: btime now = current_time(); ! 298: ! 299: char *buf = ifa->sk->tbuf; ! 300: char *bufstart = buf; ! 301: char *bufend = buf + ifa->sk->tbsize; ! 302: ! 303: struct radv_ra_packet *pkt = (void *) buf; ! 304: pkt->type = ICMPV6_RA; ! 305: pkt->code = 0; ! 306: pkt->checksum = 0; ! 307: pkt->current_hop_limit = ic->current_hop_limit; ! 308: pkt->router_lifetime = (p->valid && (p->active || !ic->default_lifetime_sensitive)) ? ! 309: htons(ic->default_lifetime) : 0; ! 310: pkt->flags = (ic->managed ? OPT_RA_MANAGED : 0) | ! 311: (ic->other_config ? OPT_RA_OTHER_CFG : 0) | ! 312: (pkt->router_lifetime ? ic->default_preference : 0); ! 313: pkt->reachable_time = htonl(ic->reachable_time); ! 314: pkt->retrans_timer = htonl(ic->retrans_timer); ! 315: buf += sizeof(*pkt); ! 316: ! 317: if (ic->link_mtu) ! 318: { ! 319: struct radv_opt_mtu *om = (void *) buf; ! 320: om->type = OPT_MTU; ! 321: om->length = 1; ! 322: om->reserved = 0; ! 323: om->mtu = htonl(ic->link_mtu); ! 324: buf += sizeof (*om); ! 325: } ! 326: ! 327: /* Keeping track of first linger timeout */ ! 328: ifa->valid_time = TIME_INFINITY; ! 329: ! 330: struct radv_prefix *px; ! 331: WALK_LIST(px, ifa->prefixes) ! 332: { ! 333: /* Skip invalid prefixes that are past linger timeout but still not pruned */ ! 334: if (!px->valid && ((px->changed + ic->prefix_linger_time S) <= now)) ! 335: continue; ! 336: ! 337: if (radv_prepare_prefix(ifa, px, &buf, bufend) < 0) ! 338: goto done; ! 339: } ! 340: ! 341: if (! ic->rdnss_local) ! 342: if (radv_prepare_rdnss(ifa, &cf->rdnss_list, &buf, bufend) < 0) ! 343: goto done; ! 344: ! 345: if (radv_prepare_rdnss(ifa, &ic->rdnss_list, &buf, bufend) < 0) ! 346: goto done; ! 347: ! 348: if (! ic->dnssl_local) ! 349: if (radv_prepare_dnssl(ifa, &cf->dnssl_list, &buf, bufend) < 0) ! 350: goto done; ! 351: ! 352: if (radv_prepare_dnssl(ifa, &ic->dnssl_list, &buf, bufend) < 0) ! 353: goto done; ! 354: ! 355: if (p->fib_up) ! 356: { ! 357: FIB_WALK(&p->routes, struct radv_route, rt) ! 358: { ! 359: /* Skip invalid routes that are past linger timeout but still not pruned */ ! 360: if (!rt->valid && ((rt->changed + ic->route_linger_time S) <= now)) ! 361: continue; ! 362: ! 363: if (radv_prepare_route(ifa, rt, &buf, bufend) < 0) ! 364: goto done; ! 365: } ! 366: FIB_WALK_END; ! 367: } ! 368: ! 369: done: ! 370: ifa->plen = buf - bufstart; ! 371: } ! 372: ! 373: ! 374: void ! 375: radv_send_ra(struct radv_iface *ifa, ip_addr to) ! 376: { ! 377: struct radv_proto *p = ifa->ra; ! 378: ! 379: /* TX queue is already full */ ! 380: if (!sk_tx_buffer_empty(ifa->sk)) ! 381: return; ! 382: ! 383: if (ifa->valid_time <= current_time()) ! 384: radv_invalidate(ifa); ! 385: ! 386: /* We store prepared RA in tbuf */ ! 387: if (!ifa->plen) ! 388: radv_prepare_ra(ifa); ! 389: ! 390: if (ipa_zero(to)) ! 391: { ! 392: to = IP6_ALL_NODES; ! 393: RADV_TRACE(D_PACKETS, "Sending RA via %s", ifa->iface->name); ! 394: } ! 395: else ! 396: { ! 397: RADV_TRACE(D_PACKETS, "Sending RA to %I via %s", to, ifa->iface->name); ! 398: } ! 399: ! 400: int done = sk_send_to(ifa->sk, ifa->plen, to, 0); ! 401: if (!done) ! 402: log(L_WARN "%s: TX queue full on %s", p->p.name, ifa->iface->name); ! 403: } ! 404: ! 405: ! 406: static void ! 407: radv_receive_rs(struct radv_proto *p, struct radv_iface *ifa, ip_addr from) ! 408: { ! 409: RADV_TRACE(D_PACKETS, "Received RS from %I via %s", ! 410: from, ifa->iface->name); ! 411: ! 412: if (ifa->cf->solicited_ra_unicast && ipa_nonzero(from)) ! 413: radv_send_ra(ifa, from); ! 414: else ! 415: radv_iface_notify(ifa, RA_EV_RS); ! 416: } ! 417: ! 418: static int ! 419: radv_rx_hook(sock *sk, uint size) ! 420: { ! 421: struct radv_iface *ifa = sk->data; ! 422: struct radv_proto *p = ifa->ra; ! 423: ! 424: /* We want just packets from sk->iface */ ! 425: if (sk->lifindex != sk->iface->index) ! 426: return 1; ! 427: ! 428: if (ipa_equal(sk->faddr, sk->saddr)) ! 429: return 1; ! 430: ! 431: if (size < 8) ! 432: return 1; ! 433: ! 434: byte *buf = sk->rbuf; ! 435: ! 436: if (buf[1] != 0) ! 437: return 1; ! 438: ! 439: /* Validation is a bit sloppy - Hop Limit is not checked and ! 440: length of options is ignored for RS and left to later for RA */ ! 441: ! 442: switch (buf[0]) ! 443: { ! 444: case ICMPV6_RS: ! 445: radv_receive_rs(p, ifa, sk->faddr); ! 446: return 1; ! 447: ! 448: case ICMPV6_RA: ! 449: RADV_TRACE(D_PACKETS, "Received RA from %I via %s", ! 450: sk->faddr, ifa->iface->name); ! 451: /* FIXME - there should be some checking of received RAs, but we just ignore them */ ! 452: return 1; ! 453: ! 454: default: ! 455: return 1; ! 456: } ! 457: } ! 458: ! 459: static void ! 460: radv_tx_hook(sock *sk) ! 461: { ! 462: struct radv_iface *ifa = sk->data; ! 463: log(L_INFO "%s: TX queue ready on %s", ifa->ra->p.name, ifa->iface->name); ! 464: ! 465: /* Some RAs may be missed due to full TX queue */ ! 466: radv_iface_notify(ifa, RA_EV_RS); ! 467: } ! 468: ! 469: static void ! 470: radv_err_hook(sock *sk, int err) ! 471: { ! 472: struct radv_iface *ifa = sk->data; ! 473: log(L_ERR "%s: Socket error on %s: %M", ifa->ra->p.name, ifa->iface->name, err); ! 474: } ! 475: ! 476: int ! 477: radv_sk_open(struct radv_iface *ifa) ! 478: { ! 479: sock *sk = sk_new(ifa->pool); ! 480: sk->type = SK_IP; ! 481: sk->subtype = SK_IPV6; ! 482: sk->dport = ICMPV6_PROTO; ! 483: sk->saddr = ifa->addr->ip; ! 484: sk->vrf = ifa->ra->p.vrf; ! 485: ! 486: sk->ttl = 255; /* Mandatory for Neighbor Discovery packets */ ! 487: sk->rx_hook = radv_rx_hook; ! 488: sk->tx_hook = radv_tx_hook; ! 489: sk->err_hook = radv_err_hook; ! 490: sk->iface = ifa->iface; ! 491: sk->rbsize = 1024; // bufsize(ifa); ! 492: sk->tbsize = 1024; // bufsize(ifa); ! 493: sk->data = ifa; ! 494: sk->flags = SKF_LADDR_RX; ! 495: ! 496: if (sk_open(sk) < 0) ! 497: goto err; ! 498: ! 499: /* We want listen just to ICMPv6 messages of type RS and RA */ ! 500: if (sk_set_icmp6_filter(sk, ICMPV6_RS, ICMPV6_RA) < 0) ! 501: goto err; ! 502: ! 503: if (sk_setup_multicast(sk) < 0) ! 504: goto err; ! 505: ! 506: if (sk_join_group(sk, IP6_ALL_ROUTERS) < 0) ! 507: goto err; ! 508: ! 509: ifa->sk = sk; ! 510: return 1; ! 511: ! 512: err: ! 513: sk_log_error(sk, ifa->ra->p.name); ! 514: rfree(sk); ! 515: return 0; ! 516: } ! 517: