Return to packets.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / bird / proto / radv |
1.1 ! misho 1: /* ! 2: * BIRD -- RAdv Packet Processing ! 3: * ! 4: * ! 5: * Can be freely distributed and used under the terms of the GNU GPL. ! 6: */ ! 7: ! 8: ! 9: #include <stdlib.h> ! 10: #include "radv.h" ! 11: ! 12: struct radv_ra_packet ! 13: { ! 14: u8 type; ! 15: u8 code; ! 16: u16 checksum; ! 17: u8 current_hop_limit; ! 18: u8 flags; ! 19: u16 router_lifetime; ! 20: u32 reachable_time; ! 21: u32 retrans_timer; ! 22: }; ! 23: ! 24: #define OPT_RA_MANAGED 0x80 ! 25: #define OPT_RA_OTHER_CFG 0x40 ! 26: ! 27: #define OPT_PREFIX 3 ! 28: #define OPT_MTU 5 ! 29: #define OPT_RDNSS 25 ! 30: #define OPT_DNSSL 31 ! 31: ! 32: struct radv_opt_prefix ! 33: { ! 34: u8 type; ! 35: u8 length; ! 36: u8 pxlen; ! 37: u8 flags; ! 38: u32 valid_lifetime; ! 39: u32 preferred_lifetime; ! 40: u32 reserved; ! 41: ip_addr prefix; ! 42: }; ! 43: ! 44: #define OPT_PX_ONLINK 0x80 ! 45: #define OPT_PX_AUTONOMOUS 0x40 ! 46: ! 47: struct radv_opt_mtu ! 48: { ! 49: u8 type; ! 50: u8 length; ! 51: u16 reserved; ! 52: u32 mtu; ! 53: }; ! 54: ! 55: struct radv_opt_rdnss ! 56: { ! 57: u8 type; ! 58: u8 length; ! 59: u16 reserved; ! 60: u32 lifetime; ! 61: ip_addr servers[]; ! 62: }; ! 63: ! 64: struct radv_opt_dnssl ! 65: { ! 66: u8 type; ! 67: u8 length; ! 68: u16 reserved; ! 69: u32 lifetime; ! 70: char domain[]; ! 71: }; ! 72: ! 73: ! 74: static struct radv_prefix_config default_prefix = { ! 75: .onlink = 1, ! 76: .autonomous = 1, ! 77: .valid_lifetime = DEFAULT_VALID_LIFETIME, ! 78: .preferred_lifetime = DEFAULT_PREFERRED_LIFETIME ! 79: }; ! 80: ! 81: ! 82: static struct radv_prefix_config * ! 83: radv_prefix_match(struct radv_iface *ifa, struct ifa *a) ! 84: { ! 85: struct proto *p = &ifa->ra->p; ! 86: struct radv_config *cf = (struct radv_config *) (p->cf); ! 87: struct radv_prefix_config *pc; ! 88: ! 89: if (a->scope <= SCOPE_LINK) ! 90: return NULL; ! 91: ! 92: WALK_LIST(pc, ifa->cf->pref_list) ! 93: if ((a->pxlen >= pc->pxlen) && ipa_in_net(a->prefix, pc->prefix, pc->pxlen)) ! 94: return pc; ! 95: ! 96: WALK_LIST(pc, cf->pref_list) ! 97: if ((a->pxlen >= pc->pxlen) && ipa_in_net(a->prefix, pc->prefix, pc->pxlen)) ! 98: return pc; ! 99: ! 100: return &default_prefix; ! 101: } ! 102: ! 103: static int ! 104: radv_prepare_rdnss(struct radv_iface *ifa, list *rdnss_list, char **buf, char *bufend) ! 105: { ! 106: struct radv_rdnss_config *rcf = HEAD(*rdnss_list); ! 107: ! 108: while(NODE_VALID(rcf)) ! 109: { ! 110: struct radv_rdnss_config *rcf_base = rcf; ! 111: struct radv_opt_rdnss *op = (void *) *buf; ! 112: int max_i = (bufend - *buf - sizeof(struct radv_opt_rdnss)) / sizeof(ip_addr); ! 113: int i = 0; ! 114: ! 115: if (max_i < 1) ! 116: goto too_much; ! 117: ! 118: op->type = OPT_RDNSS; ! 119: op->reserved = 0; ! 120: ! 121: if (rcf->lifetime_mult) ! 122: op->lifetime = htonl(rcf->lifetime_mult * ifa->cf->max_ra_int); ! 123: else ! 124: op->lifetime = htonl(rcf->lifetime); ! 125: ! 126: while(NODE_VALID(rcf) && ! 127: (rcf->lifetime == rcf_base->lifetime) && ! 128: (rcf->lifetime_mult == rcf_base->lifetime_mult)) ! 129: { ! 130: if (i >= max_i) ! 131: goto too_much; ! 132: ! 133: op->servers[i] = rcf->server; ! 134: ipa_hton(op->servers[i]); ! 135: i++; ! 136: ! 137: rcf = NODE_NEXT(rcf); ! 138: } ! 139: ! 140: op->length = 1+2*i; ! 141: *buf += 8 * op->length; ! 142: } ! 143: ! 144: return 0; ! 145: ! 146: too_much: ! 147: log(L_WARN "%s: Too many RA options on interface %s", ! 148: ifa->ra->p.name, ifa->iface->name); ! 149: return -1; ! 150: } ! 151: ! 152: int ! 153: radv_process_domain(struct radv_dnssl_config *cf) ! 154: { ! 155: /* Format of domain in search list is <size> <label> <size> <label> ... 0 */ ! 156: ! 157: char *dom = cf->domain; ! 158: char *dom_end = dom; /* Just to */ ! 159: u8 *dlen_save = &cf->dlen_first; ! 160: uint len; ! 161: ! 162: while (dom_end) ! 163: { ! 164: dom_end = strchr(dom, '.'); ! 165: len = dom_end ? (uint)(dom_end - dom) : strlen(dom); ! 166: ! 167: if (len < 1 || len > 63) ! 168: return -1; ! 169: ! 170: *dlen_save = len; ! 171: dlen_save = (u8 *) dom_end; ! 172: ! 173: dom += len + 1; ! 174: } ! 175: ! 176: len = dom - cf->domain; ! 177: if (len > 254) ! 178: return -1; ! 179: ! 180: cf->dlen_all = len; ! 181: ! 182: return 0; ! 183: } ! 184: ! 185: static int ! 186: radv_prepare_dnssl(struct radv_iface *ifa, list *dnssl_list, char **buf, char *bufend) ! 187: { ! 188: struct radv_dnssl_config *dcf = HEAD(*dnssl_list); ! 189: ! 190: while(NODE_VALID(dcf)) ! 191: { ! 192: struct radv_dnssl_config *dcf_base = dcf; ! 193: struct radv_opt_dnssl *op = (void *) *buf; ! 194: int bsize = bufend - *buf - sizeof(struct radv_opt_dnssl); ! 195: int bpos = 0; ! 196: ! 197: if (bsize < 0) ! 198: goto too_much; ! 199: ! 200: bsize = bsize & ~7; /* Round down to multiples of 8 */ ! 201: ! 202: op->type = OPT_DNSSL; ! 203: op->reserved = 0; ! 204: ! 205: if (dcf->lifetime_mult) ! 206: op->lifetime = htonl(dcf->lifetime_mult * ifa->cf->max_ra_int); ! 207: else ! 208: op->lifetime = htonl(dcf->lifetime); ! 209: ! 210: while(NODE_VALID(dcf) && ! 211: (dcf->lifetime == dcf_base->lifetime) && ! 212: (dcf->lifetime_mult == dcf_base->lifetime_mult)) ! 213: { ! 214: if (bpos + dcf->dlen_all + 1 > bsize) ! 215: goto too_much; ! 216: ! 217: op->domain[bpos++] = dcf->dlen_first; ! 218: memcpy(op->domain + bpos, dcf->domain, dcf->dlen_all); ! 219: bpos += dcf->dlen_all; ! 220: ! 221: dcf = NODE_NEXT(dcf); ! 222: } ! 223: ! 224: int blen = (bpos + 7) / 8; ! 225: bzero(op->domain + bpos, 8 * blen - bpos); ! 226: op->length = 1 + blen; ! 227: *buf += 8 * op->length; ! 228: } ! 229: ! 230: return 0; ! 231: ! 232: too_much: ! 233: log(L_WARN "%s: Too many RA options on interface %s", ! 234: ifa->ra->p.name, ifa->iface->name); ! 235: return -1; ! 236: } ! 237: ! 238: static void ! 239: radv_prepare_ra(struct radv_iface *ifa) ! 240: { ! 241: struct proto_radv *ra = ifa->ra; ! 242: struct radv_config *cf = (struct radv_config *) (ra->p.cf); ! 243: struct radv_iface_config *ic = ifa->cf; ! 244: ! 245: char *buf = ifa->sk->tbuf; ! 246: char *bufstart = buf; ! 247: char *bufend = buf + ifa->sk->tbsize; ! 248: ! 249: struct radv_ra_packet *pkt = (void *) buf; ! 250: pkt->type = ICMPV6_RA; ! 251: pkt->code = 0; ! 252: pkt->checksum = 0; ! 253: pkt->current_hop_limit = ic->current_hop_limit; ! 254: pkt->router_lifetime = (ra->active || !ic->default_lifetime_sensitive) ? ! 255: htons(ic->default_lifetime) : 0; ! 256: pkt->flags = (ic->managed ? OPT_RA_MANAGED : 0) | ! 257: (ic->other_config ? OPT_RA_OTHER_CFG : 0) | ! 258: (pkt->router_lifetime ? ic->default_preference : 0); ! 259: pkt->reachable_time = htonl(ic->reachable_time); ! 260: pkt->retrans_timer = htonl(ic->retrans_timer); ! 261: buf += sizeof(*pkt); ! 262: ! 263: if (ic->link_mtu) ! 264: { ! 265: struct radv_opt_mtu *om = (void *) buf; ! 266: om->type = OPT_MTU; ! 267: om->length = 1; ! 268: om->reserved = 0; ! 269: om->mtu = htonl(ic->link_mtu); ! 270: buf += sizeof (*om); ! 271: } ! 272: ! 273: struct ifa *addr; ! 274: WALK_LIST(addr, ifa->iface->addrs) ! 275: { ! 276: struct radv_prefix_config *pc; ! 277: pc = radv_prefix_match(ifa, addr); ! 278: ! 279: if (!pc || pc->skip) ! 280: continue; ! 281: ! 282: if (buf + sizeof(struct radv_opt_prefix) > bufend) ! 283: { ! 284: log(L_WARN "%s: Too many prefixes on interface %s", ra->p.name, ifa->iface->name); ! 285: goto done; ! 286: } ! 287: ! 288: struct radv_opt_prefix *op = (void *) buf; ! 289: op->type = OPT_PREFIX; ! 290: op->length = 4; ! 291: op->pxlen = addr->pxlen; ! 292: op->flags = (pc->onlink ? OPT_PX_ONLINK : 0) | ! 293: (pc->autonomous ? OPT_PX_AUTONOMOUS : 0); ! 294: op->valid_lifetime = (ra->active || !pc->valid_lifetime_sensitive) ? ! 295: htonl(pc->valid_lifetime) : 0; ! 296: op->preferred_lifetime = (ra->active || !pc->preferred_lifetime_sensitive) ? ! 297: htonl(pc->preferred_lifetime) : 0; ! 298: op->reserved = 0; ! 299: op->prefix = addr->prefix; ! 300: ipa_hton(op->prefix); ! 301: buf += sizeof(*op); ! 302: } ! 303: ! 304: if (! ic->rdnss_local) ! 305: if (radv_prepare_rdnss(ifa, &cf->rdnss_list, &buf, bufend) < 0) ! 306: goto done; ! 307: ! 308: if (radv_prepare_rdnss(ifa, &ic->rdnss_list, &buf, bufend) < 0) ! 309: goto done; ! 310: ! 311: if (! ic->dnssl_local) ! 312: if (radv_prepare_dnssl(ifa, &cf->dnssl_list, &buf, bufend) < 0) ! 313: goto done; ! 314: ! 315: if (radv_prepare_dnssl(ifa, &ic->dnssl_list, &buf, bufend) < 0) ! 316: goto done; ! 317: ! 318: done: ! 319: ifa->plen = buf - bufstart; ! 320: } ! 321: ! 322: ! 323: void ! 324: radv_send_ra(struct radv_iface *ifa, int shutdown) ! 325: { ! 326: struct proto_radv *ra = ifa->ra; ! 327: ! 328: /* We store prepared RA in tbuf */ ! 329: if (!ifa->plen) ! 330: radv_prepare_ra(ifa); ! 331: ! 332: if (shutdown) ! 333: { ! 334: /* ! 335: * Modify router lifetime to 0, it is not restored because we suppose that ! 336: * the iface will be removed. The preference value also has to be zeroed. ! 337: * (RFC 4191 2.2: If router lifetime is 0, the preference value must be 0.) ! 338: */ ! 339: ! 340: struct radv_ra_packet *pkt = (void *) ifa->sk->tbuf; ! 341: pkt->router_lifetime = 0; ! 342: pkt->flags &= ~RA_PREF_MASK; ! 343: } ! 344: ! 345: RADV_TRACE(D_PACKETS, "Sending RA via %s", ifa->iface->name); ! 346: sk_send_to(ifa->sk, ifa->plen, IP6_ALL_NODES, 0); ! 347: } ! 348: ! 349: ! 350: static int ! 351: radv_rx_hook(sock *sk, uint size) ! 352: { ! 353: struct radv_iface *ifa = sk->data; ! 354: struct proto_radv *ra = ifa->ra; ! 355: ! 356: /* We want just packets from sk->iface */ ! 357: if (sk->lifindex != sk->iface->index) ! 358: return 1; ! 359: ! 360: if (ipa_equal(sk->faddr, ifa->addr->ip)) ! 361: return 1; ! 362: ! 363: if (size < 8) ! 364: return 1; ! 365: ! 366: byte *buf = sk->rbuf; ! 367: ! 368: if (buf[1] != 0) ! 369: return 1; ! 370: ! 371: /* Validation is a bit sloppy - Hop Limit is not checked and ! 372: length of options is ignored for RS and left to later for RA */ ! 373: ! 374: switch (buf[0]) ! 375: { ! 376: case ICMPV6_RS: ! 377: RADV_TRACE(D_PACKETS, "Received RS from %I via %s", ! 378: sk->faddr, ifa->iface->name); ! 379: radv_iface_notify(ifa, RA_EV_RS); ! 380: return 1; ! 381: ! 382: case ICMPV6_RA: ! 383: RADV_TRACE(D_PACKETS, "Received RA from %I via %s", ! 384: sk->faddr, ifa->iface->name); ! 385: /* FIXME - there should be some checking of received RAs, but we just ignore them */ ! 386: return 1; ! 387: ! 388: default: ! 389: return 1; ! 390: } ! 391: } ! 392: ! 393: static void ! 394: radv_tx_hook(sock *sk) ! 395: { ! 396: struct radv_iface *ifa = sk->data; ! 397: log(L_WARN "%s: TX hook called", ifa->ra->p.name); ! 398: } ! 399: ! 400: static void ! 401: radv_err_hook(sock *sk, int err) ! 402: { ! 403: struct radv_iface *ifa = sk->data; ! 404: log(L_ERR "%s: Socket error on %s: %M", ifa->ra->p.name, ifa->iface->name, err); ! 405: } ! 406: ! 407: int ! 408: radv_sk_open(struct radv_iface *ifa) ! 409: { ! 410: sock *sk = sk_new(ifa->ra->p.pool); ! 411: sk->type = SK_IP; ! 412: sk->dport = ICMPV6_PROTO; ! 413: sk->saddr = ifa->addr->ip; ! 414: ! 415: sk->ttl = 255; /* Mandatory for Neighbor Discovery packets */ ! 416: sk->rx_hook = radv_rx_hook; ! 417: sk->tx_hook = radv_tx_hook; ! 418: sk->err_hook = radv_err_hook; ! 419: sk->iface = ifa->iface; ! 420: sk->rbsize = 1024; // bufsize(ifa); ! 421: sk->tbsize = 1024; // bufsize(ifa); ! 422: sk->data = ifa; ! 423: sk->flags = SKF_LADDR_RX; ! 424: ! 425: if (sk_open(sk) < 0) ! 426: goto err; ! 427: ! 428: /* We want listen just to ICMPv6 messages of type RS and RA */ ! 429: if (sk_set_icmp6_filter(sk, ICMPV6_RS, ICMPV6_RA) < 0) ! 430: goto err; ! 431: ! 432: if (sk_setup_multicast(sk) < 0) ! 433: goto err; ! 434: ! 435: if (sk_join_group(sk, IP6_ALL_ROUTERS) < 0) ! 436: goto err; ! 437: ! 438: ifa->sk = sk; ! 439: return 1; ! 440: ! 441: err: ! 442: sk_log_error(sk, ifa->ra->p.name); ! 443: rfree(sk); ! 444: return 0; ! 445: } ! 446: