Annotation of embedaddon/bird/nest/rt-roa.c, revision 1.1
1.1 ! misho 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>