]> git.ipfire.org Git - thirdparty/bird.git/blame - filter/filter.c
More CLI plans...
[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
36bbfc70 161static struct rte **f_rte;
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
341 /* This willl only work if it is not already there! */
342 {
343 struct ea_list *l = lp_alloc(f_pool, sizeof(struct ea_list) + sizeof(eattr));
344
345 l->next = NULL;
346 l->flags = EALF_SORTED;
347 l->count = 1;
348 l->attrs[0].id = what->a2.i;
349 l->attrs[0].flags = 0;
350 switch (what->aux) {
351 case T_INT:
352 l->attrs[0].type = EAF_TYPE_INT | EAF_INLINE;
353 l->attrs[0].u.data = v1.val.i;
354 break;
355 }
356 /* FIXME: need to do copy on write of rte + rta + insert at the beggining */
357 }
358
359 case 'eD': /*FIXME: unset: implement me */
360 die("Implement me!!!" );
361 break;
36bbfc70
PM
362 case 'cp': /* Convert prefix to ... */
363 ONEARG;
364 if (v1.type != T_PREFIX)
365 runtime( "Can not convert non-prefix this way" );
c7b43f33 366 res.type = what->aux;
36bbfc70
PM
367 switch(res.type) {
368 case T_INT: res.val.i = v1.val.px.len; break;
6dc7a0cb 369 case T_IP: res.val.px.ip = v1.val.px.ip; break;
36bbfc70
PM
370 default: bug( "Unknown prefix to conversion\n" );
371 }
372 break;
6542ece9
PM
373 case 'ca': /* CALL */
374 ONEARG;
375 res = interpret(what->a2.p);
376 break;
41be4444 377 case 'SW':
7db7b7db 378 ONEARG;
41be4444
PM
379 {
380 struct f_tree *t = find_tree(what->a2.p, v1);
381 if (!t) {
382 v1.type = T_VOID;
383 t = find_tree(what->a2.p, v1);
384 if (!t) {
385 printf( "No else statement?\n ");
386 break;
387 }
388 }
389 if (!t->data)
390 die( "Impossible: no code associated!\n" );
391 return interpret(t->data);
392 }
7db7b7db 393 break;
d3dd620b 394 case 'iM': /* IP.MASK(val) */
f4536657
PM
395 TWOARGS;
396 if (v2.type != T_INT)
397 runtime( "Can not use this type for mask.");
398 if (v1.type != T_IP)
399 runtime( "You can mask only IP addresses." );
400 {
401 ip_addr mask = ipa_mkmask(v2.val.i);
402 res.type = T_IP;
403 res.val.px.ip = ipa_and(mask, v1.val.px.ip);
404 }
d3dd620b 405 break;
23b1539b
PM
406 default:
407 bug( "Unknown instruction %d (%c)", what->code, what->code & 0xff);
408 }
409 if (what->next)
410 return interpret(what->next);
411 return res;
412}
413
414int
415f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struct linpool *tmp_pool)
416{
417 struct f_inst *inst;
418 struct f_val res;
419 debug( "Running filter `%s'...", filter->name );
420
36bbfc70 421 f_rte = rte;
f31156ca 422 f_pool = tmp_pool;
23b1539b
PM
423 inst = filter->root;
424 res = interpret(inst);
425 if (res.type != T_RETURN)
426 return F_ERROR;
427 debug( "done (%d)\n", res.val.i );
428 return res.val.i;
429}
430
431
432void
433filters_postconfig(void)
434{
435 struct f_val res;
8ba2cc06
PM
436 if (startup_func) {
437 printf( "Launching startup function...\n" );
23b1539b 438 res = interpret(startup_func);
bad631e0 439 if (res.type == F_ERROR)
8ba2cc06
PM
440 die( "Startup function resulted in error." );
441 printf( "done\n" );
442 }
23b1539b 443}