Annotation of embedaddon/bird2/proto/radv/packets.c, revision 1.1.1.1

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: 

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