File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / bird / proto / radv / packets.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Aug 22 12:33:54 2017 UTC (6 years, 10 months ago) by misho
Branches: bird, MAIN
CVS tags: v1_6_3p0, v1_6_3, HEAD
bird 1.6.3

    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>