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

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: 

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