]> git.ipfire.org Git - thirdparty/bird.git/blob - nest/rt-roa.c
Doc: Remove some superfluous slashes
[thirdparty/bird.git] / nest / rt-roa.c
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, *tx;
310
311 if (old)
312 WALK_LIST_DELSAFE(t, tx, 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 }