]> git.ipfire.org Git - thirdparty/bird.git/blob - filter/filter.c
fd6ea35263c3df387b3104f2c1bd6a7d10ef66b1
[thirdparty/bird.git] / filter / filter.c
1 /*
2 * Filters: utility functions
3 *
4 * Copyright 1998 Pavel Machek <pavel@ucw.cz>
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL.
7 *
8 * Notice that pair is stored as integer: first << 16 | second
9 *
10 */
11
12 #define LOCAL_DEBUG
13
14 #include "nest/bird.h"
15 #include "lib/lists.h"
16 #include "lib/resource.h"
17 #include "lib/socket.h"
18 #include "lib/string.h"
19 #include "lib/unaligned.h"
20 #include "nest/route.h"
21 #include "nest/protocol.h"
22 #include "nest/iface.h"
23 #include "nest/attrs.h"
24 #include "conf/conf.h"
25 #include "filter/filter.h"
26
27 #define P(a,b) ((a<<8) | b)
28
29 struct f_inst *startup_func = NULL;
30
31 #define CMP_ERROR 999
32
33 /* Compare two values, returns -1, 0, 1 compared, ERROR 999 */
34 int
35 val_compare(struct f_val v1, struct f_val v2)
36 {
37 if ((v1.type == T_VOID) && (v2.type == T_VOID))
38 return 0;
39 if (v1.type == T_VOID) /* Hack for else */
40 return -1;
41 if (v2.type == T_VOID)
42 return 1;
43
44 if (v1.type != v2.type)
45 return CMP_ERROR;
46 switch (v1.type) {
47 case T_ENUM:
48 case T_INT:
49 case T_PAIR:
50 if (v1.val.i == v2.val.i) return 0;
51 if (v1.val.i < v2.val.i) return -1;
52 return 1;
53 case T_IP:
54 case T_PREFIX:
55 return ipa_compare(v1.val.px.ip, v2.val.px.ip);
56 default:
57 return CMP_ERROR;
58 }
59 }
60
61 int
62 val_simple_in_range(struct f_val v1, struct f_val v2)
63 {
64 if ((v1.type == T_PATH) && (v2.type == T_PATH_MASK))
65 return as_path_match(v1.val.ad, v2.val.path_mask);
66 if ((v1.type == T_PAIR) && (v2.type == T_CLIST))
67 return int_set_contains(v2.val.ad, v1.val.i);
68
69 if ((v1.type == T_IP) && (v2.type == T_PREFIX))
70 return !(ipa_compare(ipa_and(v2.val.px.ip, ipa_mkmask(v2.val.px.len)), ipa_and(v1.val.px.ip, ipa_mkmask(v2.val.px.len))));
71
72 if ((v1.type == T_PREFIX) && (v2.type == T_PREFIX)) {
73 ip_addr mask;
74 if (v1.val.px.len & (LEN_PLUS | LEN_MINUS | LEN_RANGE))
75 return CMP_ERROR;
76 mask = ipa_mkmask( v2.val.px.len & LEN_MASK );
77 if (ipa_compare(ipa_and(v2.val.px.ip, mask), ipa_and(v1.val.px.ip, mask)))
78 return 0;
79
80 if ((v2.val.px.len & LEN_MINUS) && (v1.val.px.len <= (v2.val.px.len & LEN_MASK)))
81 return 0;
82 if ((v2.val.px.len & LEN_PLUS) && (v1.val.px.len < (v2.val.px.len & LEN_MASK)))
83 return 0;
84 if ((v2.val.px.len & LEN_RANGE) && ((v1.val.px.len < (0xff & (v2.val.px.len >> 16)))
85 || (v1.val.px.len > (0xff & (v2.val.px.len >> 8)))))
86 return 0;
87 return 1;
88 }
89 return CMP_ERROR;
90 }
91
92 int
93 val_in_range(struct f_val v1, struct f_val v2)
94 {
95 int res;
96
97 res = val_simple_in_range(v1, v2);
98
99 if (res != CMP_ERROR)
100 return res;
101
102 if (((v1.type == T_INT) || ((v1.type == T_IP) || (v1.type == T_PREFIX)) && (v2.type == T_SET))) {
103 struct f_tree *n;
104 n = find_tree(v2.val.t, v1);
105 if (!n)
106 return 0;
107 return !! (val_simple_in_range(v1, n->from)); /* We turn CMP_ERROR into compared ok, and that's fine */
108 }
109 return CMP_ERROR;
110 }
111
112 static void
113 tree_print(struct f_tree *t)
114 {
115 if (!t) {
116 debug( "() " );
117 return;
118 }
119 debug( "[ " );
120 tree_print( t->left );
121 debug( ", " ); val_print( t->from ); debug( ".." ); val_print( t->to ); debug( ", " );
122 tree_print( t->right );
123 debug( "] " );
124 }
125
126 void
127 val_print(struct f_val v)
128 {
129 char buf[2048];
130 char buf2[1024];
131 #define PRINTF(a...) bsnprintf( buf, 2040, a )
132 buf[0] = 0;
133 switch (v.type) {
134 case T_VOID: PRINTF( "(void)" ); break;
135 case T_BOOL: PRINTF( v.val.i ? "TRUE" : "FALSE" ); break;
136 case T_INT: PRINTF( "%d ", v.val.i ); break;
137 case T_STRING: PRINTF( "%s", v.val.s ); break;
138 case T_IP: PRINTF( "%I", v.val.px.ip ); break;
139 case T_PREFIX: PRINTF( "%I/%d", v.val.px.ip, v.val.px.len ); break;
140 case T_PAIR: PRINTF( "(%d,%d)", v.val.i >> 16, v.val.i & 0xffff ); break;
141 case T_SET: tree_print( v.val.t ); PRINTF( "\n" ); break;
142 case T_ENUM: PRINTF( "(enum %x)%d", v.type, v.val.i ); break;
143 case T_PATH: as_path_format(v.val.ad, buf2, 1020); PRINTF( "(path %s)", buf2 ); break;
144 case T_CLIST: int_set_format(v.val.ad, buf2, 1020); PRINTF( "(clist %s)", buf2 ); break;
145 case T_PATH_MASK: debug( "(pathmask " ); { struct f_path_mask *p = v.val.s; while (p) { debug("%d ", p->val); p=p->next; } debug(")" ); } break;
146 default: PRINTF( "[unknown type %x]", v.type );
147 #undef PRINTF
148 }
149 debug( buf );
150 }
151
152 static struct rte **f_rte, *f_rte_old;
153 static struct linpool *f_pool;
154 static struct ea_list **f_tmp_attrs;
155 static int f_flags;
156 static rta *f_rta_copy;
157
158 #define runtime(x) do { \
159 log( L_ERR x ); \
160 res.type = T_RETURN; \
161 res.val.i = F_ERROR; \
162 return res; \
163 } while(0)
164
165 #define ARG(x,y) \
166 x = interpret(what->y); \
167 if (x.type & T_RETURN) \
168 return x;
169
170 #define ONEARG ARG(v1, a1.p)
171 #define TWOARGS ARG(v1, a1.p) \
172 ARG(v2, a2.p)
173 #define TWOARGS_C TWOARGS \
174 if (v1.type != v2.type) \
175 runtime( "Can not operate with values of incompatible types" );
176
177 static struct f_val
178 interpret(struct f_inst *what)
179 {
180 struct symbol *sym;
181 struct f_val v1, v2, res;
182 int i,j,k;
183
184 res.type = T_VOID;
185 if (!what)
186 return res;
187
188 switch(what->code) {
189 case ',':
190 TWOARGS;
191 break;
192
193 /* Binary operators */
194 case '+':
195 TWOARGS_C;
196 switch (res.type = v1.type) {
197 case T_VOID: runtime( "Can not operate with values of type void" );
198 case T_INT: res.val.i = v1.val.i + v2.val.i; break;
199 default: runtime( "Usage of unknown type" );
200 }
201 break;
202 case '/':
203 TWOARGS_C;
204 switch (res.type = v1.type) {
205 case T_VOID: runtime( "Can not operate with values of type void" );
206 case T_INT: res.val.i = v1.val.i / v2.val.i; break;
207 case T_IP: if (v2.type != T_INT)
208 runtime( "Operator / is <ip>/<int>" );
209 break;
210 default: runtime( "Usage of unknown type" );
211 }
212 break;
213
214 /* Relational operators */
215
216 #define COMPARE(x) \
217 TWOARGS_C; \
218 res.type = T_BOOL; \
219 i = val_compare(v1, v2); \
220 if (i==CMP_ERROR) \
221 runtime( "Error in comparation" ); \
222 res.val.i = (x); \
223 break;
224
225 case P('!','='): COMPARE(i!=0);
226 case P('=','='): COMPARE(i==0);
227 case '<': COMPARE(i==-1);
228 case P('<','='): COMPARE(i!=1);
229
230 case '!':
231 ONEARG;
232 if (v1.type != T_BOOL)
233 runtime( "not applied to non-boolean" );
234 res = v1;
235 res.val.i = !res.val.i;
236 break;
237
238 case '~':
239 TWOARGS;
240 res.type = T_BOOL;
241 res.val.i = val_in_range(v1, v2);
242 if (res.val.i == CMP_ERROR)
243 runtime( "~ applied on unknown type pair" );
244 break;
245 case P('d','e'):
246 ONEARG;
247 res.type = T_BOOL;
248 res.val.i = (v1.type != T_VOID);
249 break;
250
251 /* Set to indirect value, a1 = variable, a2 = value */
252 case 's':
253 ARG(v2, a2.p);
254 sym = what->a1.p;
255 switch (res.type = v2.type) {
256 case T_VOID: runtime( "Can not assign void values" );
257 case T_ENUM:
258 case T_INT:
259 case T_IP:
260 case T_PREFIX:
261 case T_PAIR:
262 case T_PATH:
263 case T_CLIST:
264 case T_PATH_MASK:
265 if (sym->class != (SYM_VARIABLE | v2.type))
266 runtime( "Variable of bad type" );
267 * (struct f_val *) sym->aux2 = v2;
268 break;
269 default:
270 bug( "Set to invalid type" );
271 }
272 break;
273
274 case 'c': /* integer (or simple type) constant */
275 res.type = what->aux;
276 res.val.i = what->a2.i;
277 break;
278 case 'C':
279 res = * ((struct f_val *) what->a1.p);
280 break;
281 case 'p':
282 ONEARG;
283 val_print(v1);
284 break;
285 case '?': /* ? has really strange error value, so we can implement if ... else nicely :-) */
286 ONEARG;
287 if (v1.type != T_BOOL)
288 runtime( "If requires bool expression" );
289 if (v1.val.i) {
290 ARG(res,a2.p);
291 res.val.i = 0;
292 } else res.val.i = 1;
293 res.type = T_BOOL;
294 break;
295 case '0':
296 debug( "No operation\n" );
297 break;
298 case P('p',','):
299 ONEARG;
300 if (what->a2.i == F_NOP || (what->a2.i != F_NONL && what->a1.p))
301 debug( "\n" );
302
303 switch (what->a2.i) {
304 case F_QUITBIRD:
305 die( "Filter asked me to die" );
306 case F_ACCEPT:
307 /* Should take care about turning ACCEPT into MODIFY */
308 case F_ERROR:
309 case F_REJECT: /* FIXME (noncritical) Should print complete route along with reason to reject route */
310 res.type = T_RETURN;
311 res.val.i = what->a2.i;
312 return res; /* We have to return now, no more processing. */
313 case F_NONL:
314 case F_NOP:
315 break;
316 default:
317 bug( "unknown return type: can not happen");
318 }
319 break;
320 case 'a': /* rta access */
321 {
322 struct rta *rta = (*f_rte)->attrs;
323 res.type = what->aux;
324 switch(res.type) {
325 case T_IP:
326 res.val.px.ip = * (ip_addr *) ((char *) rta + what->a2.i);
327 break;
328 case T_ENUM:
329 res.val.i = * ((char *) rta + what->a2.i);
330 break;
331 case T_PREFIX: /* Warning: this works only for prefix of network */
332 {
333 res.val.px.ip = (*f_rte)->net->n.prefix;
334 res.val.px.len = (*f_rte)->net->n.pxlen;
335 break;
336 }
337 default:
338 bug( "Invalid type for rta access (%x)", res.type );
339 }
340 }
341 break;
342 case P('e','a'): /* Access to extended attributes */
343 {
344 eattr *e = NULL;
345 if (!(f_flags & FF_FORCE_TMPATTR))
346 e = ea_find( (*f_rte)->attrs->eattrs, what->a2.i );
347 if (!e)
348 e = ea_find( (*f_tmp_attrs), what->a2.i );
349 if ((!e) && (f_flags & FF_FORCE_TMPATTR))
350 e = ea_find( (*f_rte)->attrs->eattrs, what->a2.i );
351
352 if (!e) {
353 res.type = T_VOID;
354 break;
355 }
356 res.type = what->aux; /* FIXME: should check type? */
357 switch (what->aux) {
358 case T_INT:
359 res.val.i = e->u.data;
360 break;
361 case T_CLIST:
362 case T_PATH:
363 res.val.ad = e->u.ptr;
364 break;
365 default:
366 bug("Unknown type in e,a\n");
367 }
368 }
369 break;
370 case P('e','S'):
371 ONEARG;
372 if (v1.type != what->aux)
373 runtime("Wrong type when setting dynamic attribute");
374
375 {
376 struct ea_list *l = lp_alloc(f_pool, sizeof(struct ea_list) + sizeof(eattr));
377
378 l->next = NULL;
379 l->flags = EALF_SORTED;
380 l->count = 1;
381 l->attrs[0].id = what->a2.i;
382 l->attrs[0].flags = 0;
383 l->attrs[0].type = what->aux | EAF_ORIGINATED;
384 switch (what->aux & EAF_TYPE_MASK) {
385 case EAF_TYPE_INT:
386 if (v1.type != T_INT)
387 runtime( "Setting int attribute to non-int value" );
388 l->attrs[0].u.data = v1.val.i;
389 break;
390 case EAF_TYPE_AS_PATH:
391 if (v1.type != T_PATH)
392 runtime( "Setting path attribute to non-path value" );
393 l->attrs[0].u.ptr = v1.val.ad;
394 break;
395 case EAF_TYPE_INT_SET:
396 if (v1.type != T_CLIST)
397 runtime( "Setting int set attribute to non-clist value" );
398 l->attrs[0].u.ptr = v1.val.ad;
399 break;
400 case EAF_TYPE_UNDEF:
401 if (v1.type != T_VOID)
402 runtime( "Setting void attribute to non-void value" );
403 l->attrs[0].u.data = 0;
404 break;
405 }
406
407 if (!(what->aux & EAF_TEMP) && (!(f_flags & FF_FORCE_TMPATTR))) {
408 if (!f_rta_copy) {
409 f_rta_copy = lp_alloc(f_pool, sizeof(rta));
410 memcpy(f_rta_copy, (*f_rte)->attrs, sizeof(rta));
411 f_rta_copy->aflags = 0;
412 *f_rte = rte_cow(*f_rte);
413 (*f_rte)->attrs = f_rta_copy;
414 }
415 l->next = f_rta_copy->eattrs;
416 f_rta_copy->eattrs = l;
417 } else {
418 l->next = (*f_tmp_attrs);
419 (*f_tmp_attrs) = l;
420 }
421 }
422 break;
423
424 case 'L': /* Get length of */
425 ONEARG;
426 res.type = T_INT;
427 switch(v1.type) {
428 case T_PREFIX: res.val.i = v1.val.px.len; break;
429 case T_PATH: res.val.i = as_path_getlen(v1.val.ad); break;
430 default: bug( "Length of what?" );
431 }
432 break;
433 case P('c','p'): /* Convert prefix to ... */
434 ONEARG;
435 if (v1.type != T_PREFIX)
436 runtime( "Can not convert non-prefix this way" );
437 res.type = what->aux;
438 switch(res.type) {
439 /* case T_INT: res.val.i = v1.val.px.len; break; Not needed any more */
440 case T_IP: res.val.px.ip = v1.val.px.ip; break;
441 default: bug( "Unknown prefix to conversion" );
442 }
443 break;
444 case 'r':
445 ONEARG;
446 res = v1;
447 res.type |= T_RETURN;
448 break;
449 case P('c','a'): /* CALL: this is special: if T_RETURN and returning some value, mask it out */
450 ONEARG;
451 res = interpret(what->a2.p);
452 if (res.type == T_RETURN)
453 return res;
454 res.type &= ~T_RETURN;
455 break;
456 case P('S','W'):
457 ONEARG;
458 {
459 struct f_tree *t = find_tree(what->a2.p, v1);
460 if (!t) {
461 v1.type = T_VOID;
462 t = find_tree(what->a2.p, v1);
463 if (!t) {
464 debug( "No else statement?\n ");
465 break;
466 }
467 }
468 if (!t->data)
469 bug( "Impossible: no code associated!" );
470 return interpret(t->data);
471 }
472 break;
473 case P('i','M'): /* IP.MASK(val) */
474 TWOARGS;
475 if (v2.type != T_INT)
476 runtime( "Can not use this type for mask.");
477 if (v1.type != T_IP)
478 runtime( "You can mask only IP addresses." );
479 {
480 ip_addr mask = ipa_mkmask(v2.val.i);
481 res.type = T_IP;
482 res.val.px.ip = ipa_and(mask, v1.val.px.ip);
483 }
484 break;
485
486 case 'E': /* Create empty attribute */
487 res.type = what->aux;
488 res.val.ad = adata_empty(f_pool);
489 break;
490 case P('A','p'): /* Path prepend */
491 TWOARGS;
492 if (v1.type != T_PATH)
493 runtime("Can't prepend to non-path");
494 if (v2.type != T_INT)
495 runtime("Can't prepend non-integer");
496
497 res.type = T_PATH;
498 res.val.ad = as_path_prepend(f_pool, v1.val.ad, v2.val.i);
499 break;
500
501 case P('C','a'): /* Community list add or delete */
502 TWOARGS;
503 if (v1.type != T_CLIST)
504 runtime("Can't add/delete to non-clist");
505 if (v2.type != T_PAIR)
506 runtime("Can't add/delete non-pair");
507
508 res.type = T_CLIST;
509 switch (what->aux) {
510 case 'a': res.val.ad = int_set_add(f_pool, v1.val.ad, v2.val.i); break;
511 case 'd': res.val.ad = int_set_del(f_pool, v1.val.ad, v2.val.i); break;
512 default: bug("unknown Ca operation");
513 }
514 break;
515
516 default:
517 bug( "Unknown instruction %d (%c)", what->code, what->code & 0xff);
518 }
519 if (what->next)
520 return interpret(what->next);
521 return res;
522 }
523
524 #undef ARG
525 #define ARG(x,y) \
526 if (!i_same(f1->y, f2->y)) \
527 return 0;
528
529 #define ONEARG ARG(v1, a1.p)
530 #define TWOARGS ARG(v1, a1.p) \
531 ARG(v2, a2.p)
532
533 #define A2_SAME if (f1->a2.i != f2->a2.i) return 0;
534
535 int
536 i_same(struct f_inst *f1, struct f_inst *f2)
537 {
538 if ((!!f1) != (!!f2))
539 return 0;
540 if (!f1)
541 return 1;
542 if (f1->aux != f2->aux)
543 return 0;
544 if (f1->code != f2->code)
545 return 0;
546 if (f1 == f2) /* It looks strange, but it is possible with call rewriting trickery */
547 return 1;
548
549 switch(f1->code) {
550 case ',': /* fall through */
551 case '+':
552 case '/':
553 case P('!','='):
554 case P('=','='):
555 case '<':
556 case P('<','='): TWOARGS; break;
557
558 case '!': ONEARG; break;
559 case '~': TWOARGS; break;
560 case P('d','e'): ONEARG; break;
561
562 case 's':
563 ARG(v2, a2.p);
564 {
565 struct symbol *s1, *s2;
566 s1 = f1->a1.p;
567 s2 = f2->a1.p;
568 if (strcmp(s1->name, s2->name))
569 return 0;
570 if (s1->class != s2->class)
571 return 0;
572 }
573 break;
574
575 case 'c': A2_SAME; break;
576 case 'C':
577 if (val_compare(* (struct f_val *) f1->a1.p, * (struct f_val *) f2->a2.p))
578 return 0;
579 break;
580 case 'p': case 'L': ONEARG; break;
581 case '?': TWOARGS; break;
582 case '0': case 'E': break;
583 case P('p',','): ONEARG; A2_SAME; break;
584 case 'a': A2_SAME; break;
585 case P('e','a'): A2_SAME; break;
586 case P('e','S'): ONEARG; A2_SAME; break;
587
588 case 'r': ONEARG; break;
589 case P('c','p'): ONEARG; break;
590 case P('c','a'): /* Call rewriting trickery to avoid exponential behaviour */
591 ONEARG;
592 if (!i_same(f1->a2.p, f2->a2.p))
593 return 0;
594 f2->a2.p = f1->a2.p;
595 break;
596 case P('S','W'): ONEARG; if (!same_tree(f1->a2.p, f2->a2.p)) return 0; break;
597 case P('i','M'): TWOARGS; break;
598 case P('A','p'): TWOARGS; break;
599 case P('C','a'): TWOARGS; break;
600 default:
601 bug( "Unknown instruction %d in same (%c)", f1->code, f1->code & 0xff);
602 }
603 return i_same(f1->next, f2->next);
604 }
605
606 int
607 f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struct linpool *tmp_pool, int flags)
608 {
609 struct f_inst *inst;
610 struct f_val res;
611 DBG( "Running filter `%s'...", filter->name );
612
613 f_flags = flags;
614 f_tmp_attrs = tmp_attrs;
615 f_rte = rte;
616 f_rte_old = *rte;
617 f_rta_copy = NULL;
618 f_pool = tmp_pool;
619 inst = filter->root;
620 res = interpret(inst);
621 if (res.type != T_RETURN)
622 return F_ERROR;
623 DBG( "done (%d)\n", res.val.i );
624 return res.val.i;
625 }
626
627 void
628 filters_postconfig(void)
629 {
630 struct f_val res;
631 if (startup_func) {
632 debug( "Launching startup function...\n" );
633 f_pool = lp_new(&root_pool, 1024);
634 res = interpret(startup_func);
635 if (res.type == F_ERROR)
636 die( "Startup function resulted in error." );
637 debug( "done\n" );
638 }
639 }
640
641 int
642 filter_same(struct filter *new, struct filter *old)
643 {
644 if (old == new) /* Handle FILTER_ACCEPT and FILTER_REJECT */
645 return 1;
646 if (old == FILTER_ACCEPT || old == FILTER_REJECT ||
647 new == FILTER_ACCEPT || new == FILTER_REJECT)
648 return 0;
649 return i_same(new->root, old->root);
650 }
651
652 /* This should end up far away from here!
653 */
654 struct adata *
655 comlist_add(struct linpool *pool, struct adata *list, u32 val)
656 {
657 struct adata *res = lp_alloc(pool, list->length + sizeof(struct adata) + 4);
658 res->length = list->length+4;
659 * (u32 *) res->data = val;
660 memcpy((char *) res->data + 4, list->data, list->length);
661 return res;
662 }
663
664 struct adata *
665 comlist_contains(struct adata *list, u32 val)
666 {
667 u32 *l = &(list->data);
668 int i;
669 for (i=0; i<list->length/4; i++)
670 if (*l++ == val)
671 return 1;
672 return 0;
673 }
674
675 struct adata *
676 comlist_del(struct linpool *pool, struct adata *list, u32 val)
677 {
678 struct adata *res;
679 u32 *l, *k;
680 int i;
681
682 if (!comlist_contains(list, val))
683 return list;
684
685 res = lp_alloc(pool, list->length + sizeof(struct adata) - 4);
686 res->length = list->length-4;
687
688 l = &(list->data);
689 k = &(res->data);
690 for (i=0; i<list->length/4; i++)
691 if (l[i] != val)
692 *k++ = l[i];
693
694 return res;
695 }
696
697 struct adata *
698 adata_empty(struct linpool *pool)
699 {
700 struct adata *res = lp_alloc(pool, sizeof(struct adata));
701 res->length = 0;
702 return res;
703 }