Annotation of embedaddon/bird/proto/radv/packets.c, revision 1.1.1.2

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>