File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / bird / nest / rt-roa.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 -- Route Origin Authorization
    3:  *
    4:  *
    5:  *	Can be freely distributed and used under the terms of the GNU GPL.
    6:  */
    7: 
    8: #undef LOCAL_DEBUG
    9: 
   10: #include "nest/bird.h"
   11: #include "nest/route.h"
   12: #include "nest/cli.h"
   13: #include "lib/lists.h"
   14: #include "lib/resource.h"
   15: #include "lib/event.h"
   16: #include "lib/string.h"
   17: #include "conf/conf.h"
   18: 
   19: 
   20: pool *roa_pool;
   21: static slab *roa_slab;			/* Slab of struct roa_item */
   22: static list roa_table_list;		/* List of struct roa_table */
   23: struct roa_table *roa_table_default;	/* The first ROA table in the config */
   24: 
   25: static inline int
   26: src_match(struct roa_item *it, byte src)
   27: { return !src || it->src == src; }
   28: 
   29: /**
   30:  * roa_add_item - add a ROA entry
   31:  * @t: ROA table
   32:  * @prefix: prefix of the ROA entry
   33:  * @pxlen: prefix length of the ROA entry
   34:  * @maxlen: max length field of the ROA entry
   35:  * @asn: AS number field of the ROA entry
   36:  * @src: source of the ROA entry (ROA_SRC_*)
   37:  *
   38:  * The function adds a new ROA entry to the ROA table. If the same ROA
   39:  * is already in the table, nothing is added. @src field is used to
   40:  * distinguish different sources of ROAs.
   41:  */
   42: void
   43: roa_add_item(struct roa_table *t, ip_addr prefix, byte pxlen, byte maxlen, u32 asn, byte src)
   44: {
   45:   struct roa_node *n = fib_get(&t->fib, &prefix, pxlen);
   46: 
   47:   // if ((n->items == NULL) && (n->n.x0 != ROA_INVALID))
   48:   // t->cached_items--;
   49: 
   50:   struct roa_item *it;
   51:   for (it = n->items; it; it = it->next)
   52:     if ((it->maxlen == maxlen) && (it->asn == asn) && src_match(it, src))
   53:       return;
   54: 
   55:   it = sl_alloc(roa_slab);
   56:   it->asn = asn;
   57:   it->maxlen = maxlen;
   58:   it->src = src;
   59:   it->next = n->items;
   60:   n->items = it;
   61: }
   62: 
   63: /**
   64:  * roa_delete_item - delete a ROA entry
   65:  * @t: ROA table
   66:  * @prefix: prefix of the ROA entry
   67:  * @pxlen: prefix length of the ROA entry
   68:  * @maxlen: max length field of the ROA entry
   69:  * @asn: AS number field of the ROA entry
   70:  * @src: source of the ROA entry (ROA_SRC_*)
   71:  *
   72:  * The function removes a specified ROA entry from the ROA table and
   73:  * frees it. If @src field is not ROA_SRC_ANY, only entries from
   74:  * that source are considered.
   75:  */
   76: void
   77: roa_delete_item(struct roa_table *t, ip_addr prefix, byte pxlen, byte maxlen, u32 asn, byte src)
   78: {
   79:   struct roa_node *n = fib_find(&t->fib, &prefix, pxlen);
   80: 
   81:   if (!n)
   82:     return;
   83: 
   84:   struct roa_item *it, **itp;
   85:   for (itp = &n->items; it = *itp; itp = &it->next)
   86:     if ((it->maxlen == maxlen) && (it->asn == asn) && src_match(it, src))
   87:       break;
   88: 
   89:   if (!it)
   90:     return;
   91: 
   92:   *itp = it->next;
   93:   sl_free(roa_slab, it);
   94: 
   95:   // if ((n->items == NULL) && (n->n.x0 != ROA_INVALID))
   96:   // t->cached_items++;
   97: }
   98: 
   99: 
  100: /**
  101:  * roa_flush - flush a ROA table
  102:  * @t: ROA table
  103:  * @src: source of ROA entries (ROA_SRC_*)
  104:  *
  105:  * The function removes and frees ROA entries from the ROA table. If
  106:  * @src is ROA_SRC_ANY, all entries in the table are removed,
  107:  * otherwise only all entries from that source are removed.
  108:  */
  109: void
  110: roa_flush(struct roa_table *t, byte src)
  111: {
  112:   struct roa_item *it, **itp;
  113:   struct roa_node *n;
  114: 
  115:   FIB_WALK(&t->fib, fn)
  116:     {
  117:       n = (struct roa_node *) fn;
  118: 
  119:       itp = &n->items;
  120:       while (it = *itp)
  121: 	if (src_match(it, src))
  122: 	  {
  123: 	    *itp = it->next;
  124: 	    sl_free(roa_slab, it);
  125: 	  }
  126: 	else
  127: 	  itp = &it->next;
  128:     }
  129:   FIB_WALK_END;
  130: 
  131:   // TODO add cleanup of roa_nodes
  132: }
  133: 
  134: 
  135: 
  136: /*
  137: byte
  138: roa_check(struct roa_table *t, ip_addr prefix, byte pxlen, u32 asn)
  139: {
  140:   struct roa_node *n = fib_find(&t->fib, &prefix, pxlen);
  141: 
  142:   if (n && n->n.x0 == ROA_UNKNOWN)
  143:     return ROA_UNKNOWN;
  144: 
  145:   if (n && n->n.x0 == ROA_VALID && asn == n->cached_asn)
  146:     return ROA_VALID;
  147: 
  148:   byte rv = roa_match(t, n, prefix, pxlen, asn);
  149: 
  150:   if (rv != ROA_INVALID)
  151:     {
  152:       if (!n)
  153: 	{
  154: 	  if (t->cached_items >= t->cached_items_max)
  155: 	  n = fib_get(&t->fib, &prefix, pxlen);
  156: 	  t->cached_items++;
  157: 	}
  158: 
  159:       n->cached_asn = asn;
  160:       n->n.x0 = rv;
  161:     }
  162: 
  163:   return rv;
  164: }
  165: */
  166: 
  167: /**
  168:  * roa_check - check validity of route origination in a ROA table 
  169:  * @t: ROA table
  170:  * @prefix: network prefix to check
  171:  * @pxlen: length of network prefix
  172:  * @asn: AS number of network prefix
  173:  *
  174:  * Implements RFC 6483 route validation for the given network
  175:  * prefix. The procedure is to find all candidate ROAs - ROAs whose
  176:  * prefixes cover the give network prefix. If there is no candidate
  177:  * ROA, return ROA_UNKNOWN. If there is a candidate ROA with matching
  178:  * ASN and maxlen field greater than or equal to the given prefix
  179:  * length, return ROA_VALID. Otherwise return ROA_INVALID. If caller
  180:  * cannot determine origin AS, 0 could be used (in that case ROA_VALID
  181:  * cannot happen).
  182:  */
  183: byte
  184: roa_check(struct roa_table *t, ip_addr prefix, byte pxlen, u32 asn)
  185: {
  186:   struct roa_node *n;
  187:   ip_addr px;
  188:   byte anything = 0;
  189: 
  190:   int len;
  191:   for (len = pxlen; len >= 0; len--)
  192:     {
  193:       px = ipa_and(prefix, ipa_mkmask(len));
  194:       n = fib_find(&t->fib, &px, len);
  195: 
  196:       if (!n)
  197: 	continue;
  198: 
  199:       struct roa_item *it;
  200:       for (it = n->items; it; it = it->next)
  201: 	{
  202: 	  anything = 1;
  203: 	  if ((it->maxlen >= pxlen) && (it->asn == asn) && asn)
  204: 	    return ROA_VALID;
  205: 	}
  206:     }
  207: 
  208:   return anything ? ROA_INVALID : ROA_UNKNOWN;
  209: }
  210: 
  211: static void
  212: roa_node_init(struct fib_node *fn)
  213: {
  214:   struct roa_node *n = (struct roa_node *) fn;
  215:   n->items = NULL;
  216: }
  217: 
  218: static inline void
  219: roa_populate(struct roa_table *t)
  220: {
  221:   struct roa_item_config *ric;
  222:   for (ric = t->cf->roa_items; ric; ric = ric->next)
  223:     roa_add_item(t, ric->prefix, ric->pxlen, ric->maxlen, ric->asn, ROA_SRC_CONFIG);
  224: }
  225: 
  226: static void
  227: roa_new_table(struct roa_table_config *cf)
  228: {
  229:   struct roa_table *t;
  230: 
  231:   t = mb_allocz(roa_pool, sizeof(struct roa_table));
  232:   fib_init(&t->fib, roa_pool, sizeof(struct roa_node), 0, roa_node_init);
  233:   t->name = cf->name;
  234:   t->cf = cf;
  235: 
  236:   cf->table = t;
  237:   add_tail(&roa_table_list, &t->n);
  238: 
  239:   roa_populate(t);
  240: }
  241: 
  242: struct roa_table_config *
  243: roa_new_table_config(struct symbol *s)
  244: {
  245:   struct roa_table_config *rtc = cfg_allocz(sizeof(struct roa_table_config));
  246: 
  247:   cf_define_symbol(s, SYM_ROA, rtc);
  248:   rtc->name = s->name;
  249:   add_tail(&new_config->roa_tables, &rtc->n);
  250:   return rtc;
  251: }
  252: 
  253: /**
  254:  * roa_add_item_config - add a static ROA entry to a ROA table configuration
  255:  *
  256:  * Arguments are self-explanatory. The first is the ROA table config, rest
  257:  * are specifying the ROA entry.
  258:  */
  259: void
  260: roa_add_item_config(struct roa_table_config *rtc, ip_addr prefix, byte pxlen, byte maxlen, u32 asn)
  261: {
  262:   struct roa_item_config *ric = cfg_allocz(sizeof(struct roa_item_config));
  263: 
  264:   ric->prefix = prefix;
  265:   ric->pxlen = pxlen;
  266:   ric->maxlen = maxlen;
  267:   ric->asn = asn;
  268:   ric->next = rtc->roa_items;
  269:   rtc->roa_items = ric;
  270: }
  271: 
  272: /**
  273:  * roa_init - initialize ROA tables
  274:  *
  275:  * This function is called during BIRD startup. It initializes
  276:  * the ROA table module.
  277:  */
  278: void
  279: roa_init(void)
  280: {
  281:   roa_pool = rp_new(&root_pool, "ROA tables");
  282:   roa_slab = sl_new(roa_pool, sizeof(struct roa_item));
  283:   init_list(&roa_table_list);
  284: }
  285: 
  286: void
  287: roa_preconfig(struct config *c)
  288: {
  289:   init_list(&c->roa_tables);
  290: }
  291: 
  292: 
  293: /**
  294:  * roa_commit - commit new ROA table configuration
  295:  * @new: new configuration
  296:  * @old: original configuration or %NULL if it's boot time config
  297:  *
  298:  * Scan differences between @old and @new configuration and modify the
  299:  * ROA tables according to these changes. If @new defines a previously
  300:  * unknown table, create it, if it omits a table existing in @old,
  301:  * delete it (there are no references, only indirect through struct
  302:  * roa_table_config). If it exists in both configurations, update the
  303:  * configured ROA entries.
  304:  */
  305: void
  306: roa_commit(struct config *new, struct config *old)
  307: {
  308:   struct roa_table_config *cf;
  309:   struct roa_table *t;
  310: 
  311:   if (old)
  312:     WALK_LIST(t, roa_table_list)
  313:       {
  314: 	struct symbol *sym = cf_find_symbol(new, t->name);
  315: 	if (sym && sym->class == SYM_ROA)
  316: 	  {
  317: 	    /* Found old table in new config */
  318: 	    cf = sym->def;
  319: 	    cf->table = t;
  320: 	    t->name = cf->name;
  321: 	    t->cf = cf;
  322: 
  323: 	    /* Reconfigure it */
  324: 	    roa_flush(t, ROA_SRC_CONFIG);
  325: 	    roa_populate(t);
  326: 	  }
  327: 	else
  328: 	  {
  329: 	    t->cf->table = NULL;
  330: 
  331: 	    /* Free it now */
  332: 	    roa_flush(t, ROA_SRC_ANY);
  333: 	    rem_node(&t->n);
  334: 	    fib_free(&t->fib);
  335: 	    mb_free(t);
  336: 	  }
  337:       }
  338: 
  339:   /* Add new tables */
  340:   WALK_LIST(cf, new->roa_tables)
  341:     if (! cf->table)
  342:       roa_new_table(cf);
  343: 
  344:   roa_table_default = EMPTY_LIST(new->roa_tables) ? NULL :
  345:     ((struct roa_table_config *) HEAD(new->roa_tables))->table;
  346: }
  347: 
  348: 
  349: 
  350: static void
  351: roa_show_node(struct cli *c, struct roa_node *rn, int len, u32 asn)
  352: {
  353:   struct roa_item *ri;
  354: 
  355:   for (ri = rn->items; ri; ri = ri->next)
  356:     if ((ri->maxlen >= len) && (!asn || (ri->asn == asn)))
  357:       cli_printf(c, -1019, "%I/%d max %d as %u", rn->n.prefix, rn->n.pxlen, ri->maxlen, ri->asn);
  358: }
  359: 
  360: static void
  361: roa_show_cont(struct cli *c)
  362: {
  363:   struct roa_show_data *d = c->rover;
  364:   struct fib *fib = &d->table->fib;
  365:   struct fib_iterator *it = &d->fit;
  366:   struct roa_node *rn;
  367:   unsigned max = 32;
  368: 
  369:   FIB_ITERATE_START(fib, it, f)
  370:     {
  371:       rn = (struct roa_node *) f;
  372: 
  373:       if (!max--)
  374: 	{
  375: 	  FIB_ITERATE_PUT(it, f);
  376: 	  return;
  377: 	}
  378: 
  379:       if ((d->mode == ROA_SHOW_ALL) ||
  380: 	  net_in_net(rn->n.prefix, rn->n.pxlen, d->prefix, d->pxlen))
  381: 	roa_show_node(c, rn, 0, d->asn);
  382:     }
  383:   FIB_ITERATE_END(f);
  384: 
  385:   cli_printf(c, 0, "");
  386:   c->cont = c->cleanup = NULL;
  387: }
  388: 
  389: static void
  390: roa_show_cleanup(struct cli *c)
  391: {
  392:   struct roa_show_data *d = c->rover;
  393: 
  394:   /* Unlink the iterator */
  395:   fit_get(&d->table->fib, &d->fit);
  396: }
  397: 
  398: void
  399: roa_show(struct roa_show_data *d)
  400: {
  401:   struct roa_node *rn;
  402:   ip_addr px;
  403:   int len;
  404: 
  405:   switch (d->mode)
  406:     {
  407:     case ROA_SHOW_ALL:
  408:     case ROA_SHOW_IN:
  409:       FIB_ITERATE_INIT(&d->fit, &d->table->fib);
  410:       this_cli->cont = roa_show_cont;
  411:       this_cli->cleanup = roa_show_cleanup;
  412:       this_cli->rover = d;
  413:       break;
  414: 
  415:     case ROA_SHOW_PX:
  416:       rn = fib_find(&d->table->fib, &d->prefix, d->pxlen);
  417:       if (rn)
  418: 	{
  419: 	  roa_show_node(this_cli, rn, 0, d->asn);
  420: 	  cli_msg(0, "");
  421: 	}
  422:       else
  423: 	cli_msg(-8001, "Network not in table");
  424:       break;
  425: 
  426:     case ROA_SHOW_FOR:
  427:       for (len = d->pxlen; len >= 0; len--)
  428: 	{
  429: 	  px = ipa_and(d->prefix, ipa_mkmask(len));
  430: 	  rn = fib_find(&d->table->fib, &px, len);
  431: 
  432: 	  if (!rn)
  433: 	    continue;
  434: 
  435: 	  roa_show_node(this_cli, rn, 0, d->asn);
  436: 	}
  437:       cli_msg(0, "");
  438:       break;
  439:     }
  440: }

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