filter.c 9.46 KB
Newer Older
1
2
3
4
5
6
/*
 *	Filters: utility functions
 *
 *	Copyright 1998 Pavel Machek <pavel@ucw.cz>
 *
 *	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
13
14
15
16
17
18
19
20
 */

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/signal.h>
#include <setjmp.h>

#include "nest/bird.h"
#include "lib/lists.h"
#include "lib/resource.h"
#include "lib/socket.h"
21
#include "lib/string.h"
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include "nest/route.h"
#include "nest/protocol.h"
#include "nest/iface.h"
#include "conf/conf.h"
#include "filter/filter.h"

struct f_inst *startup_func = NULL;

#define runtime(x) do { \
    log( L_ERR x ); \
    res.type = T_RETURN; \
    res.val.i = F_ERROR; \
    return res; \
  } while(0)

#define ARG(x,y) \
	x = interpret(what->y); \
	if (x.type == T_RETURN) \
		return x;

Pavel Machek's avatar
Pavel Machek committed
42
43
44
#define ONEARG ARG(v1, a1.p)
#define TWOARGS ARG(v1, a1.p) \
		ARG(v2, a2.p)
45
46
47
48
#define TWOARGS_C TWOARGS \
                  if (v1.type != v2.type) \
		    runtime( "Can not operate with values of incompatible types" );

49
50
51
52
53
54
#define CMP_ERROR 999

/* Compare two values, returns -1, 0, 1 compared, ERROR 999 */
int
val_compare(struct f_val v1, struct f_val v2)
{
Pavel Machek's avatar
Pavel Machek committed
55
56
57
58
59
60
61
  if ((v1.type == T_VOID) && (v2.type == T_VOID))
    return 0;
  if (v1.type == T_VOID)	/* Hack for else */
    return -1;
  if (v2.type == T_VOID)
    return 1;

62
63
  if (v1.type != v2.type)
    return CMP_ERROR;
64
65
  switch (v1.type) {
  case T_INT: 
66
  case T_PAIR:
67
68
69
    if (v1.val.i == v2.val.i) return 0;
    if (v1.val.i < v2.val.i) return -1;
    return 1;
70
  case T_IP:
71
72
  case T_PREFIX:
    return ipa_compare(v1.val.px.ip, v2.val.px.ip);
Pavel Machek's avatar
Pavel Machek committed
73
  default: { printf( "Error comparing\n" ); return CMP_ERROR; }
74
75
76
  }
}

77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
int 
val_simple_in_range(struct f_val v1, struct f_val v2)
{
  if ((v1.type == T_IP) && (v2.type == T_PREFIX))
    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))));

  if ((v1.type == T_PREFIX) && (v2.type == T_PREFIX)) {
    ip_addr mask;
    if (v1.val.px.len & (LEN_PLUS | LEN_MINUS | LEN_RANGE))
      return CMP_ERROR;
    mask = ipa_mkmask( v2.val.px.len & LEN_MASK );
    if (ipa_compare(ipa_and(v2.val.px.ip, mask), ipa_and(v1.val.px.ip, mask)))
      return 0;
    /* FIXME: read rpsl or better ask mj: is it really like this? */
    if ((v2.val.px.len & LEN_MINUS) && (v1.val.px.len <= (v2.val.px.len & LEN_MASK)))
      return 0;
    if ((v2.val.px.len & LEN_PLUS) && (v1.val.px.len < (v2.val.px.len & LEN_MASK)))
      return 0;
    if ((v2.val.px.len & LEN_RANGE) && ((v1.val.px.len < (0xff & (v2.val.px.len >> 16)))
					|| (v1.val.px.len > (0xff & (v2.val.px.len >> 8)))))
      return 0;
    return 1;    
  }
  return CMP_ERROR;
}

103
104
105
int
val_in_range(struct f_val v1, struct f_val v2)
{
106
107
108
109
110
111
112
113
114
115
116
117
118
119
  int res;

  res = val_simple_in_range(v1, v2);

  if (res != CMP_ERROR)
    return res;

  if (((v1.type == T_INT) || (v1.type == T_IP)) && (v2.type == T_SET)) {
    struct f_tree *n;
    n = find_tree(v2.val.t, v1);
    if (!n)
      return 0;
    return !! (val_simple_in_range(v1, n->from));	/* We turn CMP_ERROR into compared ok, and that's fine */
  }
120
121
122
  return CMP_ERROR;
}

123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
static void
tree_print(struct f_tree *t)
{
  if (!t) {
    printf( "() " );
    return;
  }
  printf( "[ " );
  tree_print( t->left );
  printf( ", " ); val_print( t->from ); printf( ".." ); val_print( t->to ); printf( ", " );
  tree_print( t->right );
  printf( "] " );
}

void
val_print(struct f_val v)
{
  char buf[2048];
#define PRINTF(a...) bsnprintf( buf, 2040, a )
  buf[0] = 0;
  switch (v.type) {
  case T_VOID: PRINTF( "(void)" ); break;
  case T_BOOL: PRINTF( v.val.i ? "TRUE" : "FALSE" ); break;
  case T_INT: PRINTF( "%d ", v.val.i ); break;
  case T_STRING: PRINTF( "%s", v.val.s ); break;
148
  case T_IP: PRINTF( "%I", v.val.px.ip ); break;
149
150
  case T_PREFIX: PRINTF( "%I/%d", v.val.px.ip, v.val.px.len ); break;
  case T_PAIR: PRINTF( "(%d,%d)", v.val.i >> 16, v.val.i & 0xffff ); break;
151
152
153
154
155
156
  case T_SET: tree_print( v.val.t ); PRINTF( "\n" ); break;
  default: PRINTF( "[unknown type %x]", v.type );
  }
  printf( buf );
}

157
158
static struct rte **f_rte;

159
160
static struct f_val interpret(struct f_inst *what);

161
162
163
164
165
static struct f_val
interpret(struct f_inst *what)
{
  struct symbol *sym;
  struct f_val v1, v2, res;
166
  int i,j,k;
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198

  res.type = T_VOID;
  if (!what)
    return res;

  switch(what->code) {
  case ',':
    TWOARGS;
    break;

/* Binary operators */
  case '+':
    TWOARGS_C;
    switch (res.type = v1.type) {
    case T_VOID: runtime( "Can not operate with values of type void" );
    case T_INT: res.val.i = v1.val.i + v2.val.i; break;
    default: runtime( "Usage of unknown type" );
    }
    break;
  case '/':
    TWOARGS_C;
    switch (res.type = v1.type) {
    case T_VOID: runtime( "Can not operate with values of type void" );
    case T_INT: res.val.i = v1.val.i / v2.val.i; break;
    case T_IP: if (v2.type != T_INT)
                 runtime( "Operator / is <ip>/<int>" );
               break;
    default: runtime( "Usage of unknown type" );
    }
    break;

/* Relational operators */
199
200
201
202
203
204
205
206

#define COMPARE(x) \
    TWOARGS_C; \
    res.type = T_BOOL; \
    i = val_compare(v1, v2); \
    if (i==CMP_ERROR) \
      runtime( "Error in comparation" ); \
    res.val.i = (x); \
207
    break;
208
209
210
211
212
213

  case '!=': COMPARE(i!=0);
  case '==': COMPARE(i==0);
  case '<': COMPARE(i==-1);
  case '<=': COMPARE(i!=1);

214
    /* FIXME: Should be able to work with prefixes of limited sizes */
215
216
  case '~':
    TWOARGS;
217
    res.type = T_BOOL;
218
219
220
    res.val.i = val_in_range(v1, v2);
    if (res.val.i == CMP_ERROR)
      runtime( "~ applied on unknown type pair" );
221
222
    break;

223
  /* Set to indirect value, a1 = variable, a2 = value */
224
  case 's':
Pavel Machek's avatar
Pavel Machek committed
225
226
    ARG(v2, a2.p);
    sym = what->a1.p;
227
228
229
    switch (res.type = v2.type) {
    case T_VOID: runtime( "Can not assign void values" );
    case T_INT: 
230
231
232
233
    case T_IP: 
    case T_PREFIX: 
    case T_PAIR: 
      if (sym->class != (SYM_VARIABLE | v2.type))
234
	runtime( "Variable of bad type" );
235
      * (struct f_val *) sym->aux2 = v2; 
236
      break;
237
238
    default:
      bug( "Set to invalid type\n" );
239
240
241
    }
    break;

242
  case 'c':	/* integer (or simple type) constant */
Pavel Machek's avatar
Pavel Machek committed
243
    res.type = what->a1.i;
244
    res.val.i = what->a2.i;
245
    break;
246
247
248
  case 'C':
    res = * ((struct f_val *) what->a1.p);
    break;
249
250
  case 'p':
    ONEARG;
251
    val_print(v1);
252
253
254
255
256
257
    break;
  case '?':	/* ? has really strange error value, so we can implement if ... else nicely :-) */
    ONEARG;
    if (v1.type != T_BOOL)
      runtime( "If requires bool expression" );
    if (v1.val.i) {
Pavel Machek's avatar
Pavel Machek committed
258
      ARG(res,a2.p);
259
260
261
262
263
264
265
266
267
      res.val.i = 0;
    } else res.val.i = 1;
    res.type = T_BOOL;
    break;
  case '0':
    printf( "No operation\n" );
    break;
  case 'p,':
    ONEARG;
268
269
    if (what->a2.i != F_NONL)
      printf( "\n" );
270

Pavel Machek's avatar
Pavel Machek committed
271
    switch (what->a2.i) {
272
273
274
275
276
277
278
    case F_QUITBIRD:
      die( "Filter asked me to die" );
    case F_ACCEPT:
      /* Should take care about turning ACCEPT into MODIFY */
    case F_ERROR:
    case F_REJECT:
      res.type = T_RETURN;
Pavel Machek's avatar
Pavel Machek committed
279
      res.val.i = what->a1.i;
280
      break;
281
    case F_NONL:
282
283
284
285
286
287
    case F_NOP:
      break;
    default:
      bug( "unknown return type: can not happen");
    }
    break;
288
289
290
291
292
293
  case 'a':	/* rta access */
    {
      struct rta *rta = (*f_rte)->attrs;
      res.type = what->a1.i;
      switch(res.type) {
      case T_IP:
294
	res.val.px.ip = * (ip_addr *) ((char *) rta + what->a2.i);
295
296
297
298
299
300
301
302
303
304
305
306
	break;
      case T_PREFIX:	/* Warning: this works only for prefix of network */
	{
	  res.val.px.ip = (*f_rte)->net->n.prefix;
	  res.val.px.len = (*f_rte)->net->n.pxlen;
	  break;
	}
      default:
	bug( "Invalid type for rta access" );
      }
    }
    break;
307
  case 'ea':	/* Access to extended attributes [hmm, but we need it read/write, do we?] */
308
309
310
311
312
313
314
315
316
317
318
319
320
    {
      eattr *e = ea_find( (*f_rte)->attrs->eattrs, what->a2.i );
      if (!e) {
	res.type = T_VOID;
	break;
      }
      res.type = what->a1.i;
      switch (what->a1.i) {
      case T_INT:
	res.val.i = e->u.data;
	break;
      }
    }
321
    break;
322
323
324
325
326
327
328
  case 'cp':	/* Convert prefix to ... */
    ONEARG;
    if (v1.type != T_PREFIX)
      runtime( "Can not convert non-prefix this way" );
    res.type = what->a2.i;
    switch(res.type) {
    case T_INT:	res.val.i = v1.val.px.len; break;
329
    case T_IP: res.val.px.ip = v1.val.px.ip; break;
330
331
332
    default: bug( "Unknown prefix to conversion\n" );
    }
    break;
333
334
335
336
  case 'ca': /* CALL */
    ONEARG;
    res = interpret(what->a2.p);
    break;
Pavel Machek's avatar
Pavel Machek committed
337
  case 'SW':
338
    ONEARG;
Pavel Machek's avatar
Pavel Machek committed
339
340
341
342
343
344
345
346
347
348
349
350
351
352
    {
      struct f_tree *t = find_tree(what->a2.p, v1);
      if (!t) {
	v1.type = T_VOID;
	t = find_tree(what->a2.p, v1);
	if (!t) {
	  printf( "No else statement?\n ");
	  break;
	}
      }	
      if (!t->data)
	die( "Impossible: no code associated!\n" );
      return interpret(t->data);
    }
353
    break;
354
355
356
357
  case 'iM': /* IP.MASK(val) */
    TWOARGS_C;
    bug( "Should implement ip.mask\n" );
    break;
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
  default:
    bug( "Unknown instruction %d (%c)", what->code, what->code & 0xff);
  }
  if (what->next)
    return interpret(what->next);
  return res;
}

int
f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struct linpool *tmp_pool)
{
  struct f_inst *inst;
  struct f_val res;
  debug( "Running filter `%s'...", filter->name );

373
  f_rte = rte;
374
375
376
377
378
379
380
381
382
383
384
385
386
  inst = filter->root;
  res = interpret(inst);
  if (res.type != T_RETURN)
    return F_ERROR;
  debug( "done (%d)\n", res.val.i );
  return res.val.i;
}


void
filters_postconfig(void)
{
  struct f_val res;
387
388
  if (startup_func) {
    printf( "Launching startup function...\n" );
389
    res = interpret(startup_func);
Pavel Machek's avatar
Pavel Machek committed
390
    if (res.type == F_ERROR)
391
392
393
      die( "Startup function resulted in error." );
    printf( "done\n" );
  }
394
}