]> git.ipfire.org Git - thirdparty/bird.git/blame - filter/filter.c
Filters: write access to dynamic attributes should actually work. It
[thirdparty/bird.git] / filter / filter.c
CommitLineData
23b1539b
PM
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.
29818140 7 *
720d911d 8 * Notice that pair is stored as integer: first << 16 | second
2f702671
PM
9 *
10 * FIXME: Check if prefixes are really prefixes.
23b1539b
PM
11 */
12
13#include <stdio.h>
14#include <fcntl.h>
15#include <unistd.h>
16#include <sys/signal.h>
17#include <setjmp.h>
18
19#include "nest/bird.h"
20#include "lib/lists.h"
21#include "lib/resource.h"
22#include "lib/socket.h"
38506f71 23#include "lib/string.h"
23b1539b
PM
24#include "nest/route.h"
25#include "nest/protocol.h"
26#include "nest/iface.h"
27#include "conf/conf.h"
28#include "filter/filter.h"
29
30struct f_inst *startup_func = NULL;
31
32#define runtime(x) do { \
33 log( L_ERR x ); \
34 res.type = T_RETURN; \
35 res.val.i = F_ERROR; \
36 return res; \
37 } while(0)
38
39#define ARG(x,y) \
40 x = interpret(what->y); \
41 if (x.type == T_RETURN) \
42 return x;
43
2db3b288
PM
44#define ONEARG ARG(v1, a1.p)
45#define TWOARGS ARG(v1, a1.p) \
46 ARG(v2, a2.p)
23b1539b
PM
47#define TWOARGS_C TWOARGS \
48 if (v1.type != v2.type) \
49 runtime( "Can not operate with values of incompatible types" );
50
38506f71
PM
51#define CMP_ERROR 999
52
53/* Compare two values, returns -1, 0, 1 compared, ERROR 999 */
54int
55val_compare(struct f_val v1, struct f_val v2)
56{
41be4444
PM
57 if ((v1.type == T_VOID) && (v2.type == T_VOID))
58 return 0;
59 if (v1.type == T_VOID) /* Hack for else */
60 return -1;
61 if (v2.type == T_VOID)
62 return 1;
63
7db7b7db
PM
64 if (v1.type != v2.type)
65 return CMP_ERROR;
38506f71 66 switch (v1.type) {
f4536657 67 case T_ENUM:
38506f71 68 case T_INT:
d3dd620b 69 case T_PAIR:
38506f71
PM
70 if (v1.val.i == v2.val.i) return 0;
71 if (v1.val.i < v2.val.i) return -1;
72 return 1;
43fc099b 73 case T_IP:
6dc7a0cb
PM
74 case T_PREFIX:
75 return ipa_compare(v1.val.px.ip, v2.val.px.ip);
41be4444 76 default: { printf( "Error comparing\n" ); return CMP_ERROR; }
38506f71
PM
77 }
78}
79
6dc7a0cb
PM
80int
81val_simple_in_range(struct f_val v1, struct f_val v2)
82{
83 if ((v1.type == T_IP) && (v2.type == T_PREFIX))
84 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))));
85
86 if ((v1.type == T_PREFIX) && (v2.type == T_PREFIX)) {
87 ip_addr mask;
88 if (v1.val.px.len & (LEN_PLUS | LEN_MINUS | LEN_RANGE))
89 return CMP_ERROR;
90 mask = ipa_mkmask( v2.val.px.len & LEN_MASK );
91 if (ipa_compare(ipa_and(v2.val.px.ip, mask), ipa_and(v1.val.px.ip, mask)))
92 return 0;
93 /* FIXME: read rpsl or better ask mj: is it really like this? */
94 if ((v2.val.px.len & LEN_MINUS) && (v1.val.px.len <= (v2.val.px.len & LEN_MASK)))
95 return 0;
96 if ((v2.val.px.len & LEN_PLUS) && (v1.val.px.len < (v2.val.px.len & LEN_MASK)))
97 return 0;
98 if ((v2.val.px.len & LEN_RANGE) && ((v1.val.px.len < (0xff & (v2.val.px.len >> 16)))
99 || (v1.val.px.len > (0xff & (v2.val.px.len >> 8)))))
100 return 0;
101 return 1;
102 }
103 return CMP_ERROR;
104}
105
7db7b7db
PM
106int
107val_in_range(struct f_val v1, struct f_val v2)
108{
6dc7a0cb
PM
109 int res;
110
111 res = val_simple_in_range(v1, v2);
112
113 if (res != CMP_ERROR)
114 return res;
115
2f702671 116 if (((v1.type == T_INT) || ((v1.type == T_IP) || (v1.type == T_PREFIX)) && (v2.type == T_SET))) {
6dc7a0cb
PM
117 struct f_tree *n;
118 n = find_tree(v2.val.t, v1);
119 if (!n)
120 return 0;
121 return !! (val_simple_in_range(v1, n->from)); /* We turn CMP_ERROR into compared ok, and that's fine */
122 }
7db7b7db
PM
123 return CMP_ERROR;
124}
125
38506f71
PM
126static void
127tree_print(struct f_tree *t)
128{
129 if (!t) {
130 printf( "() " );
131 return;
132 }
133 printf( "[ " );
134 tree_print( t->left );
135 printf( ", " ); val_print( t->from ); printf( ".." ); val_print( t->to ); printf( ", " );
136 tree_print( t->right );
137 printf( "] " );
138}
139
140void
141val_print(struct f_val v)
142{
143 char buf[2048];
144#define PRINTF(a...) bsnprintf( buf, 2040, a )
145 buf[0] = 0;
146 switch (v.type) {
147 case T_VOID: PRINTF( "(void)" ); break;
148 case T_BOOL: PRINTF( v.val.i ? "TRUE" : "FALSE" ); break;
149 case T_INT: PRINTF( "%d ", v.val.i ); break;
150 case T_STRING: PRINTF( "%s", v.val.s ); break;
6dc7a0cb 151 case T_IP: PRINTF( "%I", v.val.px.ip ); break;
720d911d
PM
152 case T_PREFIX: PRINTF( "%I/%d", v.val.px.ip, v.val.px.len ); break;
153 case T_PAIR: PRINTF( "(%d,%d)", v.val.i >> 16, v.val.i & 0xffff ); break;
38506f71 154 case T_SET: tree_print( v.val.t ); PRINTF( "\n" ); break;
346a12c2 155 case T_ENUM: PRINTF( "(enum %x)%d", v.type, v.val.i ); break;
38506f71
PM
156 default: PRINTF( "[unknown type %x]", v.type );
157 }
158 printf( buf );
159}
160
48f9e019 161static struct rte **f_rte, *f_rte_old;
f31156ca 162static struct linpool *f_pool;
36bbfc70 163
7db7b7db
PM
164static struct f_val interpret(struct f_inst *what);
165
23b1539b
PM
166static struct f_val
167interpret(struct f_inst *what)
168{
169 struct symbol *sym;
170 struct f_val v1, v2, res;
38506f71 171 int i,j,k;
23b1539b
PM
172
173 res.type = T_VOID;
174 if (!what)
175 return res;
176
177 switch(what->code) {
178 case ',':
179 TWOARGS;
180 break;
181
182/* Binary operators */
183 case '+':
184 TWOARGS_C;
185 switch (res.type = v1.type) {
186 case T_VOID: runtime( "Can not operate with values of type void" );
187 case T_INT: res.val.i = v1.val.i + v2.val.i; break;
188 default: runtime( "Usage of unknown type" );
189 }
190 break;
191 case '/':
192 TWOARGS_C;
193 switch (res.type = v1.type) {
194 case T_VOID: runtime( "Can not operate with values of type void" );
195 case T_INT: res.val.i = v1.val.i / v2.val.i; break;
196 case T_IP: if (v2.type != T_INT)
197 runtime( "Operator / is <ip>/<int>" );
198 break;
199 default: runtime( "Usage of unknown type" );
200 }
201 break;
202
203/* Relational operators */
38506f71
PM
204
205#define COMPARE(x) \
206 TWOARGS_C; \
207 res.type = T_BOOL; \
208 i = val_compare(v1, v2); \
209 if (i==CMP_ERROR) \
210 runtime( "Error in comparation" ); \
211 res.val.i = (x); \
23b1539b 212 break;
38506f71
PM
213
214 case '!=': COMPARE(i!=0);
215 case '==': COMPARE(i==0);
216 case '<': COMPARE(i==-1);
217 case '<=': COMPARE(i!=1);
218
29818140 219 /* FIXME: Should be able to work with prefixes of limited sizes */
38506f71
PM
220 case '~':
221 TWOARGS;
23b1539b 222 res.type = T_BOOL;
7db7b7db
PM
223 res.val.i = val_in_range(v1, v2);
224 if (res.val.i == CMP_ERROR)
225 runtime( "~ applied on unknown type pair" );
23b1539b 226 break;
f4536657
PM
227 case 'de':
228 ONEARG;
229 res.type = T_BOOL;
230 res.val.i = (v1.type != T_VOID);
231 break;
23b1539b 232
d3dd620b 233 /* Set to indirect value, a1 = variable, a2 = value */
23b1539b 234 case 's':
2db3b288
PM
235 ARG(v2, a2.p);
236 sym = what->a1.p;
23b1539b
PM
237 switch (res.type = v2.type) {
238 case T_VOID: runtime( "Can not assign void values" );
f4536657 239 case T_ENUM:
23b1539b 240 case T_INT:
d3dd620b
PM
241 case T_IP:
242 case T_PREFIX:
243 case T_PAIR:
244 if (sym->class != (SYM_VARIABLE | v2.type))
23b1539b 245 runtime( "Variable of bad type" );
d3dd620b 246 * (struct f_val *) sym->aux2 = v2;
23b1539b 247 break;
d3dd620b
PM
248 default:
249 bug( "Set to invalid type\n" );
23b1539b
PM
250 }
251 break;
252
d3dd620b 253 case 'c': /* integer (or simple type) constant */
c7b43f33 254 res.type = what->aux;
d3dd620b 255 res.val.i = what->a2.i;
23b1539b 256 break;
38506f71
PM
257 case 'C':
258 res = * ((struct f_val *) what->a1.p);
259 break;
23b1539b
PM
260 case 'p':
261 ONEARG;
38506f71 262 val_print(v1);
23b1539b
PM
263 break;
264 case '?': /* ? has really strange error value, so we can implement if ... else nicely :-) */
265 ONEARG;
266 if (v1.type != T_BOOL)
267 runtime( "If requires bool expression" );
268 if (v1.val.i) {
2db3b288 269 ARG(res,a2.p);
23b1539b
PM
270 res.val.i = 0;
271 } else res.val.i = 1;
272 res.type = T_BOOL;
273 break;
274 case '0':
275 printf( "No operation\n" );
276 break;
277 case 'p,':
278 ONEARG;
d3dd620b
PM
279 if (what->a2.i != F_NONL)
280 printf( "\n" );
23b1539b 281
2db3b288 282 switch (what->a2.i) {
23b1539b
PM
283 case F_QUITBIRD:
284 die( "Filter asked me to die" );
285 case F_ACCEPT:
286 /* Should take care about turning ACCEPT into MODIFY */
287 case F_ERROR:
c7b43f33 288 case F_REJECT: /* FIXME (noncritical) Should print compele route along with reason to reject route */
23b1539b 289 res.type = T_RETURN;
2db3b288 290 res.val.i = what->a1.i;
23b1539b 291 break;
d3dd620b 292 case F_NONL:
23b1539b
PM
293 case F_NOP:
294 break;
295 default:
296 bug( "unknown return type: can not happen");
297 }
298 break;
36bbfc70
PM
299 case 'a': /* rta access */
300 {
301 struct rta *rta = (*f_rte)->attrs;
c7b43f33 302 res.type = what->aux;
36bbfc70
PM
303 switch(res.type) {
304 case T_IP:
6dc7a0cb 305 res.val.px.ip = * (ip_addr *) ((char *) rta + what->a2.i);
36bbfc70 306 break;
c7b43f33
PM
307 case T_ENUM:
308 res.val.i = * ((char *) rta + what->a2.i);
309 break;
36bbfc70
PM
310 case T_PREFIX: /* Warning: this works only for prefix of network */
311 {
312 res.val.px.ip = (*f_rte)->net->n.prefix;
313 res.val.px.len = (*f_rte)->net->n.pxlen;
314 break;
315 }
316 default:
317 bug( "Invalid type for rta access" );
318 }
319 }
320 break;
6dc7a0cb 321 case 'ea': /* Access to extended attributes [hmm, but we need it read/write, do we?] */
91447965
PM
322 {
323 eattr *e = ea_find( (*f_rte)->attrs->eattrs, what->a2.i );
324 if (!e) {
325 res.type = T_VOID;
326 break;
327 }
c7b43f33 328 res.type = what->aux;
91447965
PM
329 switch (what->a1.i) {
330 case T_INT:
331 res.val.i = e->u.data;
332 break;
333 }
334 }
6dc7a0cb 335 break;
f31156ca
PM
336 case 'eS':
337 ONEARG;
338 if (v1.type != what->aux)
339 runtime("Wrong type when setting dynamic attribute\n");
340
f31156ca
PM
341 {
342 struct ea_list *l = lp_alloc(f_pool, sizeof(struct ea_list) + sizeof(eattr));
343
344 l->next = NULL;
345 l->flags = EALF_SORTED;
346 l->count = 1;
347 l->attrs[0].id = what->a2.i;
348 l->attrs[0].flags = 0;
349 switch (what->aux) {
350 case T_INT:
351 l->attrs[0].type = EAF_TYPE_INT | EAF_INLINE;
352 l->attrs[0].u.data = v1.val.i;
353 break;
48f9e019
PM
354 case T_VOID:
355 l->attrs[0].type = EAF_TYPE_UNDEF | EAF_INLINE;
356 l->attrs[0].u.data = 0;
357 break;
f31156ca 358 }
48f9e019
PM
359 *f_rte = rte_do_cow(*f_rte);
360 l->next = *f_rte->attrs->eattrs;
361 *f_rte->attrs->eattrs = l;
f31156ca 362 }
f31156ca 363 break;
48f9e019 364
36bbfc70
PM
365 case 'cp': /* Convert prefix to ... */
366 ONEARG;
367 if (v1.type != T_PREFIX)
368 runtime( "Can not convert non-prefix this way" );
c7b43f33 369 res.type = what->aux;
36bbfc70
PM
370 switch(res.type) {
371 case T_INT: res.val.i = v1.val.px.len; break;
6dc7a0cb 372 case T_IP: res.val.px.ip = v1.val.px.ip; break;
36bbfc70
PM
373 default: bug( "Unknown prefix to conversion\n" );
374 }
375 break;
6542ece9
PM
376 case 'ca': /* CALL */
377 ONEARG;
378 res = interpret(what->a2.p);
379 break;
41be4444 380 case 'SW':
7db7b7db 381 ONEARG;
41be4444
PM
382 {
383 struct f_tree *t = find_tree(what->a2.p, v1);
384 if (!t) {
385 v1.type = T_VOID;
386 t = find_tree(what->a2.p, v1);
387 if (!t) {
388 printf( "No else statement?\n ");
389 break;
390 }
391 }
392 if (!t->data)
393 die( "Impossible: no code associated!\n" );
394 return interpret(t->data);
395 }
7db7b7db 396 break;
d3dd620b 397 case 'iM': /* IP.MASK(val) */
f4536657
PM
398 TWOARGS;
399 if (v2.type != T_INT)
400 runtime( "Can not use this type for mask.");
401 if (v1.type != T_IP)
402 runtime( "You can mask only IP addresses." );
403 {
404 ip_addr mask = ipa_mkmask(v2.val.i);
405 res.type = T_IP;
406 res.val.px.ip = ipa_and(mask, v1.val.px.ip);
407 }
d3dd620b 408 break;
23b1539b
PM
409 default:
410 bug( "Unknown instruction %d (%c)", what->code, what->code & 0xff);
411 }
412 if (what->next)
413 return interpret(what->next);
414 return res;
415}
416
417int
418f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struct linpool *tmp_pool)
419{
420 struct f_inst *inst;
421 struct f_val res;
422 debug( "Running filter `%s'...", filter->name );
423
36bbfc70 424 f_rte = rte;
48f9e019 425 f_rte_old = *rte;
f31156ca 426 f_pool = tmp_pool;
23b1539b
PM
427 inst = filter->root;
428 res = interpret(inst);
429 if (res.type != T_RETURN)
430 return F_ERROR;
431 debug( "done (%d)\n", res.val.i );
432 return res.val.i;
433}
434
435
436void
437filters_postconfig(void)
438{
439 struct f_val res;
8ba2cc06
PM
440 if (startup_func) {
441 printf( "Launching startup function...\n" );
23b1539b 442 res = interpret(startup_func);
bad631e0 443 if (res.type == F_ERROR)
8ba2cc06
PM
444 die( "Startup function resulted in error." );
445 printf( "done\n" );
446 }
23b1539b 447}