summaryrefslogtreecommitdiff
path: root/filter
diff options
context:
space:
mode:
Diffstat (limited to 'filter')
-rw-r--r--filter/config.Y7
-rw-r--r--filter/f-util.c20
-rw-r--r--filter/filter.c100
-rw-r--r--filter/filter.h9
-rw-r--r--filter/test.conf51
5 files changed, 163 insertions, 24 deletions
diff --git a/filter/config.Y b/filter/config.Y
index 0166d27b..2e8b522e 100644
--- a/filter/config.Y
+++ b/filter/config.Y
@@ -259,6 +259,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
DEFINED,
ADD, DELETE, CONTAINS, RESET,
PREPEND, FIRST, LAST, MATCH,
+ ROA_CHECK,
EMPTY,
FILTER, WHERE, EVAL)
@@ -495,7 +496,7 @@ pair_item:
/* Hack: $2 and $4 should be pair_expr, but that would cause shift/reduce conflict */
if ((pair_a($2) != pair_b($2)) || (pair_a($4) != pair_b($4)))
cf_error("syntax error");
- $$ = f_new_pair_item(pair_b($2), pair_b($4), $8, $10);
+ $$ = f_new_pair_item(pair_b($2), $8, pair_b($4), $10);
}
;
@@ -755,6 +756,9 @@ term:
| DELETE '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'd'; }
| FILTER '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'f'; }
+ | ROA_CHECK '(' SYM ')' { $$ = f_generate_roa_check($3, NULL, NULL); }
+ | ROA_CHECK '(' SYM ',' term ',' term ')' { $$ = f_generate_roa_check($3, $5, $7); }
+
/* | term '.' LEN { $$->code = P('P','l'); } */
/* function_call is inlined here */
@@ -801,7 +805,6 @@ print_list: /* EMPTY */ { $$ = NULL; }
$$ = $1;
} else $$ = $3;
}
-
;
var_listn: term {
diff --git a/filter/f-util.c b/filter/f-util.c
index 9f2eb6b3..5908ac64 100644
--- a/filter/f-util.c
+++ b/filter/f-util.c
@@ -54,6 +54,24 @@ f_generate_complex(int operation, int operation_aux, struct f_inst *dyn, struct
return set_dyn;
}
+
+struct f_inst *
+f_generate_roa_check(struct symbol *sym, struct f_inst *prefix, struct f_inst *asn)
+{
+ struct f_inst_roa_check *ret = cfg_allocz(sizeof(struct f_inst_roa_check));
+ ret->i.code = P('R','C');
+ ret->i.lineno = ifs->conf_lino;
+ ret->i.arg1 = prefix;
+ ret->i.arg2 = asn;
+ /* prefix == NULL <-> asn == NULL */
+
+ if ((sym->class != SYM_ROA) || ! sym->def)
+ cf_error("%s is not a ROA table", sym->name);
+ ret->rtc = sym->def;
+
+ return &ret->i;
+}
+
char *
filter_name(struct filter *filter)
{
@@ -61,6 +79,8 @@ filter_name(struct filter *filter)
return "ACCEPT";
else if (filter == FILTER_REJECT)
return "REJECT";
+ else if (!filter->name)
+ return "(unnamed)";
else
return filter->name;
}
diff --git a/filter/filter.c b/filter/filter.c
index d6d338bf..acdcfd2b 100644
--- a/filter/filter.c
+++ b/filter/filter.c
@@ -228,6 +228,9 @@ val_simple_in_range(struct f_val v1, struct f_val v2)
{
if ((v1.type == T_PATH) && (v2.type == T_PATH_MASK))
return as_path_match(v1.val.ad, v2.val.path_mask);
+ if ((v1.type == T_INT) && (v2.type == T_PATH))
+ return as_path_is_member(v2.val.ad, v1.val.i);
+
if (((v1.type == T_PAIR) || (v1.type == T_QUAD)) && (v2.type == T_CLIST))
return int_set_contains(v2.val.ad, v1.val.i);
#ifndef IPV6
@@ -245,7 +248,7 @@ val_simple_in_range(struct f_val v1, struct f_val v2)
return ipa_in_net(v1.val.px.ip, v2.val.px.ip, v2.val.px.len);
if ((v1.type == T_PREFIX) && (v2.type == T_PREFIX))
- return ipa_in_net(v1.val.px.ip, v2.val.px.ip, v2.val.px.len) && (v1.val.px.len >= v2.val.px.len);
+ return net_in_net(v1.val.px.ip, v1.val.px.len, v2.val.px.ip, v2.val.px.len);
return CMP_ERROR;
}
@@ -320,28 +323,34 @@ eclist_match_set(struct adata *list, struct f_tree *set)
}
static struct adata *
-clist_filter(struct linpool *pool, struct adata *clist, struct f_tree *set, int pos)
+clist_filter(struct linpool *pool, struct adata *list, struct f_val set, int pos)
{
- if (!clist)
+ if (!list)
return NULL;
+ int tree = (set.type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
struct f_val v;
- clist_set_type(set, &v);
+ if (tree)
+ clist_set_type(set.val.t, &v);
+ else
+ v.type = T_PAIR;
- u32 tmp[clist->length/4];
- u32 *l = (u32 *) clist->data;
+ int len = int_set_get_size(list);
+ u32 *l = int_set_get_data(list);
+ u32 tmp[len];
u32 *k = tmp;
- u32 *end = l + clist->length/4;
+ u32 *end = l + len;
while (l < end) {
v.val.i = *l++;
- if (pos == !!find_tree(set, v)) /* pos && find_tree || !pos && !find_tree */
+ /* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */
+ if ((tree ? !!find_tree(set.val.t, v) : int_set_contains(set.val.ad, v.val.i)) == pos)
*k++ = v.val.i;
}
int nl = (k - tmp) * 4;
- if (nl == clist->length)
- return clist;
+ if (nl == list->length)
+ return list;
struct adata *res = adata_empty(pool, nl);
memcpy(res->data, tmp, nl);
@@ -349,11 +358,12 @@ clist_filter(struct linpool *pool, struct adata *clist, struct f_tree *set, int
}
static struct adata *
-eclist_filter(struct linpool *pool, struct adata *list, struct f_tree *set, int pos)
+eclist_filter(struct linpool *pool, struct adata *list, struct f_val set, int pos)
{
if (!list)
return NULL;
+ int tree = (set.type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
struct f_val v;
int len = int_set_get_size(list);
@@ -365,7 +375,8 @@ eclist_filter(struct linpool *pool, struct adata *list, struct f_tree *set, int
v.type = T_EC;
for (i = 0; i < len; i += 2) {
v.val.ec = ec_get(l, i);
- if (pos == !!find_tree(set, v)) { /* pos && find_tree || !pos && !find_tree */
+ /* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */
+ if ((tree ? !!find_tree(set.val.t, v) : ec_set_contains(set.val.ad, v.val.ec)) == pos) {
*k++ = l[i];
*k++ = l[i+1];
}
@@ -1116,6 +1127,8 @@ interpret(struct f_inst *what)
#endif
else if ((v2.type == T_SET) && clist_set_type(v2.val.t, &dummy))
arg_set = 1;
+ else if (v2.type == T_CLIST)
+ arg_set = 2;
else
runtime("Can't add/delete non-pair");
@@ -1123,22 +1136,25 @@ interpret(struct f_inst *what)
switch (what->aux)
{
case 'a':
- if (arg_set)
+ if (arg_set == 1)
runtime("Can't add set");
- res.val.ad = int_set_add(f_pool, v1.val.ad, i);
+ else if (!arg_set)
+ res.val.ad = int_set_add(f_pool, v1.val.ad, i);
+ else
+ res.val.ad = int_set_union(f_pool, v1.val.ad, v2.val.ad);
break;
case 'd':
if (!arg_set)
res.val.ad = int_set_del(f_pool, v1.val.ad, i);
else
- res.val.ad = clist_filter(f_pool, v1.val.ad, v2.val.t, 0);
+ res.val.ad = clist_filter(f_pool, v1.val.ad, v2, 0);
break;
case 'f':
if (!arg_set)
runtime("Can't filter pair");
- res.val.ad = clist_filter(f_pool, v1.val.ad, v2.val.t, 1);
+ res.val.ad = clist_filter(f_pool, v1.val.ad, v2, 1);
break;
default:
@@ -1153,6 +1169,8 @@ interpret(struct f_inst *what)
/* v2.val is either EC or EC-set */
if ((v2.type == T_SET) && eclist_set_type(v2.val.t))
arg_set = 1;
+ else if (v2.type == T_ECLIST)
+ arg_set = 2;
else if (v2.type != T_EC)
runtime("Can't add/delete non-pair");
@@ -1160,22 +1178,25 @@ interpret(struct f_inst *what)
switch (what->aux)
{
case 'a':
- if (arg_set)
+ if (arg_set == 1)
runtime("Can't add set");
- res.val.ad = ec_set_add(f_pool, v1.val.ad, v2.val.ec);
+ else if (!arg_set)
+ res.val.ad = ec_set_add(f_pool, v1.val.ad, v2.val.ec);
+ else
+ res.val.ad = ec_set_union(f_pool, v1.val.ad, v2.val.ad);
break;
case 'd':
if (!arg_set)
res.val.ad = ec_set_del(f_pool, v1.val.ad, v2.val.ec);
else
- res.val.ad = eclist_filter(f_pool, v1.val.ad, v2.val.t, 0);
+ res.val.ad = eclist_filter(f_pool, v1.val.ad, v2, 0);
break;
case 'f':
if (!arg_set)
runtime("Can't filter ec");
- res.val.ad = eclist_filter(f_pool, v1.val.ad, v2.val.t, 1);
+ res.val.ad = eclist_filter(f_pool, v1.val.ad, v2, 1);
break;
default:
@@ -1187,6 +1208,38 @@ interpret(struct f_inst *what)
break;
+ case P('R','C'): /* ROA Check */
+ if (what->arg1)
+ {
+ TWOARGS;
+ if ((v1.type != T_PREFIX) || (v2.type != T_INT))
+ runtime("Invalid argument to roa_check()");
+
+ as = v2.val.i;
+ }
+ else
+ {
+ v1.val.px.ip = (*f_rte)->net->n.prefix;
+ v1.val.px.len = (*f_rte)->net->n.pxlen;
+
+ /* We ignore temporary attributes, probably not a problem here */
+ /* 0x02 is a value of BA_AS_PATH, we don't want to include BGP headers */
+ eattr *e = ea_find((*f_rte)->attrs->eattrs, EA_CODE(EAP_BGP, 0x02));
+
+ if (!e || e->type != EAF_TYPE_AS_PATH)
+ runtime("Missing AS_PATH attribute");
+
+ as_path_get_last(e->u.ptr, &as);
+ }
+
+ struct roa_table_config *rtc = ((struct f_inst_roa_check *) what)->rtc;
+ if (!rtc->table)
+ runtime("Missing ROA table");
+
+ res.type = T_ENUM_ROA;
+ res.val.i = roa_check(rtc->table, v1.val.px.ip, v1.val.px.len, as);
+ break;
+
default:
bug( "Unknown instruction %d (%c)", what->code, what->code & 0xff);
}
@@ -1311,6 +1364,13 @@ i_same(struct f_inst *f1, struct f_inst *f2)
case P('C','a'): TWOARGS; break;
case P('a','f'):
case P('a','l'): ONEARG; break;
+ case P('R','C'):
+ TWOARGS;
+ /* Does not really make sense - ROA check resuls may change anyway */
+ if (strcmp(((struct f_inst_roa_check *) f1)->rtc->name,
+ ((struct f_inst_roa_check *) f2)->rtc->name))
+ return 0;
+ break;
default:
bug( "Unknown instruction %d in same (%c)", f1->code, f1->code & 0xff);
}
diff --git a/filter/filter.h b/filter/filter.h
index 2cf4652d..2386fc95 100644
--- a/filter/filter.h
+++ b/filter/filter.h
@@ -32,6 +32,12 @@ struct f_inst { /* Instruction */
#define arg1 a1.p
#define arg2 a2.p
+/* Not enough fields in f_inst for three args used by roa_check() */
+struct f_inst_roa_check {
+ struct f_inst i;
+ struct roa_table_config *rtc;
+};
+
struct f_prefix {
ip_addr ip;
int len;
@@ -66,6 +72,8 @@ struct f_inst *f_new_inst(void);
struct f_inst *f_new_dynamic_attr(int type, int f_type, int code); /* Type as core knows it, type as filters know it, and code of dynamic attribute */
struct f_tree *f_new_tree(void);
struct f_inst *f_generate_complex(int operation, int operation_aux, struct f_inst *dyn, struct f_inst *argument);
+struct f_inst *f_generate_roa_check(struct symbol *sym, struct f_inst *prefix, struct f_inst *asn);
+
struct f_tree *build_tree(struct f_tree *);
struct f_tree *find_tree(struct f_tree *t, struct f_val val);
@@ -141,6 +149,7 @@ int tree_compare(const void *p1, const void *p2);
#define T_ENUM_SCOPE 0x32
#define T_ENUM_RTC 0x33
#define T_ENUM_RTD 0x34
+#define T_ENUM_ROA 0x35
/* new enums go here */
#define T_ENUM_EMPTY 0x3f /* Special hack for atomic_aggr */
diff --git a/filter/test.conf b/filter/test.conf
index 4f09637c..64e6d91b 100644
--- a/filter/test.conf
+++ b/filter/test.conf
@@ -52,12 +52,40 @@ function fifteen()
return 15;
}
+roa table rl
+{
+ roa 10.110.0.0/16 max 16 as 1000;
+ roa 10.120.0.0/16 max 24 as 1000;
+ roa 10.130.0.0/16 max 24 as 2000;
+ roa 10.130.128.0/18 max 24 as 3000;
+}
+
+function test_roa()
+{
+ # cannot be tested in __startup(), sorry
+ print "Testing ROA";
+ print "Should be true: ", roa_check(rl, 10.10.0.0/16, 1000) = ROA_UNKNOWN,
+ " ", roa_check(rl, 10.0.0.0/8, 1000) = ROA_UNKNOWN,
+ " ", roa_check(rl, 10.110.0.0/16, 1000) = ROA_VALID,
+ " ", roa_check(rl, 10.110.0.0/16, 2000) = ROA_INVALID,
+ " ", roa_check(rl, 10.110.32.0/20, 1000) = ROA_INVALID,
+ " ", roa_check(rl, 10.120.32.0/20, 1000) = ROA_VALID;
+ print "Should be true: ", roa_check(rl, 10.120.32.0/20, 2000) = ROA_INVALID,
+ " ", roa_check(rl, 10.120.32.32/28, 1000) = ROA_INVALID,
+ " ", roa_check(rl, 10.130.130.0/24, 1000) = ROA_INVALID,
+ " ", roa_check(rl, 10.130.130.0/24, 2000) = ROA_VALID,
+ " ", roa_check(rl, 10.130.30.0/24, 3000) = ROA_INVALID,
+ " ", roa_check(rl, 10.130.130.0/24, 3000) = ROA_VALID;
+}
+
function paths()
bgpmask pm1;
bgpmask pm2;
bgppath p2;
clist l;
+clist l2;
eclist el;
+eclist el2;
{
pm1 = / 4 3 2 1 /;
pm2 = [= 4 3 2 1 =];
@@ -67,10 +95,10 @@ eclist el;
p2 = prepend( p2, 3 );
p2 = prepend( p2, 4 );
print "Testing paths: ", p2;
- print "Should be true: ", p2 ~ pm1, " ", p2 ~ pm2;
+ print "Should be true: ", p2 ~ pm1, " ", p2 ~ pm2, " ", 3 ~ p2;
print "4 = ", p2.len;
p2 = prepend( p2, 5 );
- print "Should be false: ", p2 ~ pm1, " ", p2 ~ pm2;
+ print "Should be false: ", p2 ~ pm1, " ", p2 ~ pm2, " ", 10 ~ p2;
print "Should be true: ", p2 ~ / ? 4 3 2 1 /, " ", p2, " ", / ? 4 3 2 1 /;
print "Should be true: ", p2 ~ [= * 4 3 * 1 =], " ", p2, " ", [= * 4 3 * 1 =];
print "Should be true: ", p2 ~ [= (3+2) (2*2) 3 2 1 =], " ", p2 ~ mkpath(5, 4);
@@ -108,6 +136,7 @@ eclist el;
l = add( l, (3,3) );
l = add( l, (3,4) );
l = add( l, (3,5) );
+ l2 = filter( l, [(3,*)] );
l = delete( l, [(3,2..4)] );
print "Community list (1,2) (3,1) (3,5) ", l;
l = add( l, (3,2) );
@@ -120,6 +149,14 @@ eclist el;
print "Community list (3,1) ", l;
l = delete( l, [(*,(onef(5)))] );
print "Community list empty ", l;
+ l2 = add( l2, (3,6) );
+ l = filter( l2, [(3,1..4)] );
+ l2 = filter( l2, [(3,3..6)] );
+ print "clist A (1..4): ", l;
+ print "clist B (3..6): ", l2;
+ print "clist A union B: ", add( l2, l );
+ print "clist A isect B: ", filter( l, l2 );
+ print "clist A \ B: ", delete( l, l2 );
el = -- empty --;
el = add(el, (rt, 10, 20));
@@ -143,6 +180,16 @@ eclist el;
print "EC list (rt, 10, 1) (rt, 10, 30): ", el;
print "Testing EC list, true: ", (rt, 10, 1) ~ el, " ", el ~ [(rt, 10, ten..40)];
print "Testing EC list, false: ", (rt, 10, 20) ~ el, " ", (ro, 10.20.30.40, 100) ~ el, " ", el ~ [(rt, 10, 35..40)], " ", el ~ [(ro, 10, *)];
+ el = add(el, (rt, 10, 40));
+ el2 = filter(el, [(rt, 10, 20..40)] );
+ el2 = add(el2, (rt, 10, 50));
+ print "eclist A (1,30,40): ", el;
+ print "eclist B (30,40,50): ", el2;
+ print "eclist A union B: ", add( el2, el );
+ print "eclist A isect B: ", filter( el, el2 );
+ print "eclist A \ B: ", delete( el, el2 );
+
+# test_roa();
}
function bla()