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