1 |
|
|
/* $OpenBSD: rde_filter.c,v 1.77 2016/06/03 17:36:37 benno Exp $ */ |
2 |
|
|
|
3 |
|
|
/* |
4 |
|
|
* Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org> |
5 |
|
|
* |
6 |
|
|
* Permission to use, copy, modify, and distribute this software for any |
7 |
|
|
* purpose with or without fee is hereby granted, provided that the above |
8 |
|
|
* copyright notice and this permission notice appear in all copies. |
9 |
|
|
* |
10 |
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
11 |
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
12 |
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
13 |
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
14 |
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
15 |
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
16 |
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
17 |
|
|
*/ |
18 |
|
|
#include <sys/types.h> |
19 |
|
|
#include <sys/queue.h> |
20 |
|
|
|
21 |
|
|
#include <limits.h> |
22 |
|
|
#include <stdlib.h> |
23 |
|
|
#include <string.h> |
24 |
|
|
|
25 |
|
|
#include "bgpd.h" |
26 |
|
|
#include "rde.h" |
27 |
|
|
|
28 |
|
|
int rde_filter_match(struct filter_rule *, struct rde_aspath *, |
29 |
|
|
struct bgpd_addr *, u_int8_t, struct rde_peer *, struct rde_peer *); |
30 |
|
|
int filterset_equal(struct filter_set_head *, struct filter_set_head *); |
31 |
|
|
|
32 |
|
|
void |
33 |
|
|
rde_apply_set(struct rde_aspath *asp, struct filter_set_head *sh, |
34 |
|
|
u_int8_t aid, struct rde_peer *from, struct rde_peer *peer) |
35 |
|
|
{ |
36 |
|
|
struct filter_set *set; |
37 |
|
|
u_char *np; |
38 |
|
|
int as, type; |
39 |
|
|
u_int32_t prep_as; |
40 |
|
|
u_int16_t nl; |
41 |
|
|
u_int8_t prepend; |
42 |
|
|
|
43 |
|
|
if (asp == NULL) |
44 |
|
|
return; |
45 |
|
|
|
46 |
|
|
TAILQ_FOREACH(set, sh, entry) { |
47 |
|
|
switch (set->type) { |
48 |
|
|
case ACTION_SET_LOCALPREF: |
49 |
|
|
asp->lpref = set->action.metric; |
50 |
|
|
break; |
51 |
|
|
case ACTION_SET_RELATIVE_LOCALPREF: |
52 |
|
|
if (set->action.relative > 0) { |
53 |
|
|
if (set->action.relative + asp->lpref < |
54 |
|
|
asp->lpref) |
55 |
|
|
asp->lpref = UINT_MAX; |
56 |
|
|
else |
57 |
|
|
asp->lpref += set->action.relative; |
58 |
|
|
} else { |
59 |
|
|
if ((u_int32_t)-set->action.relative > |
60 |
|
|
asp->lpref) |
61 |
|
|
asp->lpref = 0; |
62 |
|
|
else |
63 |
|
|
asp->lpref += set->action.relative; |
64 |
|
|
} |
65 |
|
|
break; |
66 |
|
|
case ACTION_SET_MED: |
67 |
|
|
asp->flags |= F_ATTR_MED | F_ATTR_MED_ANNOUNCE; |
68 |
|
|
asp->med = set->action.metric; |
69 |
|
|
break; |
70 |
|
|
case ACTION_SET_RELATIVE_MED: |
71 |
|
|
asp->flags |= F_ATTR_MED | F_ATTR_MED_ANNOUNCE; |
72 |
|
|
if (set->action.relative > 0) { |
73 |
|
|
if (set->action.relative + asp->med < |
74 |
|
|
asp->med) |
75 |
|
|
asp->med = UINT_MAX; |
76 |
|
|
else |
77 |
|
|
asp->med += set->action.relative; |
78 |
|
|
} else { |
79 |
|
|
if ((u_int32_t)-set->action.relative > |
80 |
|
|
asp->med) |
81 |
|
|
asp->med = 0; |
82 |
|
|
else |
83 |
|
|
asp->med += set->action.relative; |
84 |
|
|
} |
85 |
|
|
break; |
86 |
|
|
case ACTION_SET_WEIGHT: |
87 |
|
|
asp->weight = set->action.metric; |
88 |
|
|
break; |
89 |
|
|
case ACTION_SET_RELATIVE_WEIGHT: |
90 |
|
|
if (set->action.relative > 0) { |
91 |
|
|
if (set->action.relative + asp->weight < |
92 |
|
|
asp->weight) |
93 |
|
|
asp->weight = UINT_MAX; |
94 |
|
|
else |
95 |
|
|
asp->weight += set->action.relative; |
96 |
|
|
} else { |
97 |
|
|
if ((u_int32_t)-set->action.relative > |
98 |
|
|
asp->weight) |
99 |
|
|
asp->weight = 0; |
100 |
|
|
else |
101 |
|
|
asp->weight += set->action.relative; |
102 |
|
|
} |
103 |
|
|
break; |
104 |
|
|
case ACTION_SET_PREPEND_SELF: |
105 |
|
|
prep_as = rde_local_as(); |
106 |
|
|
prepend = set->action.prepend; |
107 |
|
|
np = aspath_prepend(asp->aspath, prep_as, prepend, &nl); |
108 |
|
|
aspath_put(asp->aspath); |
109 |
|
|
asp->aspath = aspath_get(np, nl); |
110 |
|
|
free(np); |
111 |
|
|
break; |
112 |
|
|
case ACTION_SET_PREPEND_PEER: |
113 |
|
|
if (from == NULL) |
114 |
|
|
break; |
115 |
|
|
prep_as = from->conf.remote_as; |
116 |
|
|
prepend = set->action.prepend; |
117 |
|
|
np = aspath_prepend(asp->aspath, prep_as, prepend, &nl); |
118 |
|
|
aspath_put(asp->aspath); |
119 |
|
|
asp->aspath = aspath_get(np, nl); |
120 |
|
|
free(np); |
121 |
|
|
break; |
122 |
|
|
case ACTION_SET_NEXTHOP: |
123 |
|
|
case ACTION_SET_NEXTHOP_REJECT: |
124 |
|
|
case ACTION_SET_NEXTHOP_BLACKHOLE: |
125 |
|
|
case ACTION_SET_NEXTHOP_NOMODIFY: |
126 |
|
|
case ACTION_SET_NEXTHOP_SELF: |
127 |
|
|
nexthop_modify(asp, &set->action.nexthop, set->type, |
128 |
|
|
aid); |
129 |
|
|
break; |
130 |
|
|
case ACTION_SET_COMMUNITY: |
131 |
|
|
switch (set->action.community.as) { |
132 |
|
|
case COMMUNITY_ERROR: |
133 |
|
|
case COMMUNITY_ANY: |
134 |
|
|
fatalx("rde_apply_set bad community string"); |
135 |
|
|
case COMMUNITY_NEIGHBOR_AS: |
136 |
|
|
as = peer->conf.remote_as; |
137 |
|
|
break; |
138 |
|
|
default: |
139 |
|
|
as = set->action.community.as; |
140 |
|
|
break; |
141 |
|
|
} |
142 |
|
|
|
143 |
|
|
switch (set->action.community.type) { |
144 |
|
|
case COMMUNITY_ERROR: |
145 |
|
|
case COMMUNITY_ANY: |
146 |
|
|
fatalx("rde_apply_set bad community string"); |
147 |
|
|
case COMMUNITY_NEIGHBOR_AS: |
148 |
|
|
type = peer->conf.remote_as; |
149 |
|
|
break; |
150 |
|
|
default: |
151 |
|
|
type = set->action.community.type; |
152 |
|
|
break; |
153 |
|
|
} |
154 |
|
|
|
155 |
|
|
community_set(asp, as, type); |
156 |
|
|
break; |
157 |
|
|
case ACTION_DEL_COMMUNITY: |
158 |
|
|
switch (set->action.community.as) { |
159 |
|
|
case COMMUNITY_ERROR: |
160 |
|
|
fatalx("rde_apply_set bad community string"); |
161 |
|
|
case COMMUNITY_NEIGHBOR_AS: |
162 |
|
|
as = peer->conf.remote_as; |
163 |
|
|
break; |
164 |
|
|
case COMMUNITY_ANY: |
165 |
|
|
default: |
166 |
|
|
as = set->action.community.as; |
167 |
|
|
break; |
168 |
|
|
} |
169 |
|
|
|
170 |
|
|
switch (set->action.community.type) { |
171 |
|
|
case COMMUNITY_ERROR: |
172 |
|
|
fatalx("rde_apply_set bad community string"); |
173 |
|
|
case COMMUNITY_NEIGHBOR_AS: |
174 |
|
|
type = peer->conf.remote_as; |
175 |
|
|
break; |
176 |
|
|
case COMMUNITY_ANY: |
177 |
|
|
default: |
178 |
|
|
type = set->action.community.type; |
179 |
|
|
break; |
180 |
|
|
} |
181 |
|
|
|
182 |
|
|
community_delete(asp, as, type); |
183 |
|
|
break; |
184 |
|
|
case ACTION_PFTABLE: |
185 |
|
|
/* convert pftable name to an id */ |
186 |
|
|
set->action.id = pftable_name2id(set->action.pftable); |
187 |
|
|
set->type = ACTION_PFTABLE_ID; |
188 |
|
|
/* FALLTHROUGH */ |
189 |
|
|
case ACTION_PFTABLE_ID: |
190 |
|
|
pftable_unref(asp->pftableid); |
191 |
|
|
asp->pftableid = set->action.id; |
192 |
|
|
pftable_ref(asp->pftableid); |
193 |
|
|
break; |
194 |
|
|
case ACTION_RTLABEL: |
195 |
|
|
/* convert the route label to an id for faster access */ |
196 |
|
|
set->action.id = rtlabel_name2id(set->action.rtlabel); |
197 |
|
|
set->type = ACTION_RTLABEL_ID; |
198 |
|
|
/* FALLTHROUGH */ |
199 |
|
|
case ACTION_RTLABEL_ID: |
200 |
|
|
rtlabel_unref(asp->rtlabelid); |
201 |
|
|
asp->rtlabelid = set->action.id; |
202 |
|
|
rtlabel_ref(asp->rtlabelid); |
203 |
|
|
break; |
204 |
|
|
case ACTION_SET_ORIGIN: |
205 |
|
|
asp->origin = set->action.origin; |
206 |
|
|
break; |
207 |
|
|
case ACTION_SET_EXT_COMMUNITY: |
208 |
|
|
community_ext_set(asp, &set->action.ext_community, |
209 |
|
|
peer->conf.remote_as); |
210 |
|
|
break; |
211 |
|
|
case ACTION_DEL_EXT_COMMUNITY: |
212 |
|
|
community_ext_delete(asp, &set->action.ext_community, |
213 |
|
|
peer->conf.remote_as); |
214 |
|
|
break; |
215 |
|
|
} |
216 |
|
|
} |
217 |
|
|
} |
218 |
|
|
|
219 |
|
|
int |
220 |
|
|
rde_filter_match(struct filter_rule *f, struct rde_aspath *asp, |
221 |
|
|
struct bgpd_addr *prefix, u_int8_t plen, struct rde_peer *peer, |
222 |
|
|
struct rde_peer *from) |
223 |
|
|
{ |
224 |
|
|
u_int32_t pas; |
225 |
|
|
int cas, type; |
226 |
|
|
|
227 |
|
|
if (asp != NULL && f->match.as.type != AS_NONE) { |
228 |
|
|
if (f->match.as.flags & AS_FLAG_NEIGHBORAS) |
229 |
|
|
pas = peer->conf.remote_as; |
230 |
|
|
else |
231 |
|
|
pas = f->match.as.as; |
232 |
|
|
if (aspath_match(asp->aspath->data, asp->aspath->len, |
233 |
|
|
&f->match.as, pas) == 0) |
234 |
|
|
return (0); |
235 |
|
|
} |
236 |
|
|
|
237 |
|
|
if (asp != NULL && f->match.aslen.type != ASLEN_NONE) |
238 |
|
|
if (aspath_lenmatch(asp->aspath, f->match.aslen.type, |
239 |
|
|
f->match.aslen.aslen) == 0) |
240 |
|
|
return (0); |
241 |
|
|
|
242 |
|
|
if (asp != NULL && f->match.community.as != COMMUNITY_UNSET) { |
243 |
|
|
switch (f->match.community.as) { |
244 |
|
|
case COMMUNITY_ERROR: |
245 |
|
|
fatalx("rde_apply_set bad community string"); |
246 |
|
|
case COMMUNITY_NEIGHBOR_AS: |
247 |
|
|
cas = peer->conf.remote_as; |
248 |
|
|
break; |
249 |
|
|
default: |
250 |
|
|
cas = f->match.community.as; |
251 |
|
|
break; |
252 |
|
|
} |
253 |
|
|
|
254 |
|
|
switch (f->match.community.type) { |
255 |
|
|
case COMMUNITY_ERROR: |
256 |
|
|
fatalx("rde_apply_set bad community string"); |
257 |
|
|
case COMMUNITY_NEIGHBOR_AS: |
258 |
|
|
type = peer->conf.remote_as; |
259 |
|
|
break; |
260 |
|
|
default: |
261 |
|
|
type = f->match.community.type; |
262 |
|
|
break; |
263 |
|
|
} |
264 |
|
|
|
265 |
|
|
if (community_match(asp, cas, type) == 0) |
266 |
|
|
return (0); |
267 |
|
|
} |
268 |
|
|
if (asp != NULL && |
269 |
|
|
(f->match.ext_community.flags & EXT_COMMUNITY_FLAG_VALID)) |
270 |
|
|
if (community_ext_match(asp, &f->match.ext_community, |
271 |
|
|
peer->conf.remote_as) == 0) |
272 |
|
|
return (0); |
273 |
|
|
|
274 |
|
|
if (f->match.prefix.addr.aid != 0) { |
275 |
|
|
if (f->match.prefix.addr.aid != prefix->aid) |
276 |
|
|
/* don't use IPv4 rules for IPv6 and vice versa */ |
277 |
|
|
return (0); |
278 |
|
|
|
279 |
|
|
if (prefix_compare(prefix, &f->match.prefix.addr, |
280 |
|
|
f->match.prefix.len)) |
281 |
|
|
return (0); |
282 |
|
|
|
283 |
|
|
/* test prefixlen stuff too */ |
284 |
|
|
switch (f->match.prefix.op) { |
285 |
|
|
case OP_NONE: /* perfect match */ |
286 |
|
|
return (plen == f->match.prefix.len); |
287 |
|
|
case OP_EQ: |
288 |
|
|
return (plen == f->match.prefix.len_min); |
289 |
|
|
case OP_NE: |
290 |
|
|
return (plen != f->match.prefix.len_min); |
291 |
|
|
case OP_RANGE: |
292 |
|
|
return ((plen >= f->match.prefix.len_min) && |
293 |
|
|
(plen <= f->match.prefix.len_max)); |
294 |
|
|
case OP_XRANGE: |
295 |
|
|
return ((plen < f->match.prefix.len_min) || |
296 |
|
|
(plen > f->match.prefix.len_max)); |
297 |
|
|
case OP_LE: |
298 |
|
|
return (plen <= f->match.prefix.len_min); |
299 |
|
|
case OP_LT: |
300 |
|
|
return (plen < f->match.prefix.len_min); |
301 |
|
|
case OP_GE: |
302 |
|
|
return (plen >= f->match.prefix.len_min); |
303 |
|
|
case OP_GT: |
304 |
|
|
return (plen > f->match.prefix.len_min); |
305 |
|
|
} |
306 |
|
|
/* NOTREACHED */ |
307 |
|
|
} |
308 |
|
|
if (f->match.nexthop.flags != 0) { |
309 |
|
|
struct bgpd_addr *nexthop, *cmpaddr; |
310 |
|
|
if (asp != NULL && asp->nexthop == NULL) |
311 |
|
|
/* no nexthop, skip */ |
312 |
|
|
return (0); |
313 |
|
|
nexthop = &asp->nexthop->exit_nexthop; |
314 |
|
|
if (f->match.nexthop.flags == FILTER_NEXTHOP_ADDR) |
315 |
|
|
cmpaddr = &f->match.nexthop.addr; |
316 |
|
|
else |
317 |
|
|
cmpaddr = &from->remote_addr; |
318 |
|
|
if (cmpaddr->aid != nexthop->aid) |
319 |
|
|
/* don't use IPv4 rules for IPv6 and vice versa */ |
320 |
|
|
return (0); |
321 |
|
|
|
322 |
|
|
switch (cmpaddr->aid) { |
323 |
|
|
case AID_INET: |
324 |
|
|
if (cmpaddr->v4.s_addr != nexthop->v4.s_addr) |
325 |
|
|
return (0); |
326 |
|
|
break; |
327 |
|
|
case AID_INET6: |
328 |
|
|
if (memcmp(&cmpaddr->v6, &nexthop->v6, |
329 |
|
|
sizeof(struct in6_addr))) |
330 |
|
|
return (0); |
331 |
|
|
break; |
332 |
|
|
default: |
333 |
|
|
fatalx("King Bula lost in address space"); |
334 |
|
|
} |
335 |
|
|
} |
336 |
|
|
|
337 |
|
|
/* matched somewhen or is anymatch rule */ |
338 |
|
|
return (1); |
339 |
|
|
} |
340 |
|
|
|
341 |
|
|
int |
342 |
|
|
rde_filter_equal(struct filter_head *a, struct filter_head *b, |
343 |
|
|
struct rde_peer *peer) |
344 |
|
|
{ |
345 |
|
|
struct filter_rule *fa, *fb; |
346 |
|
|
|
347 |
|
|
fa = a ? TAILQ_FIRST(a) : NULL; |
348 |
|
|
fb = b ? TAILQ_FIRST(b) : NULL; |
349 |
|
|
|
350 |
|
|
while (fa != NULL || fb != NULL) { |
351 |
|
|
/* skip all rules with wrong peer */ |
352 |
|
|
if (peer != NULL && fa != NULL && fa->peer.groupid != 0 && |
353 |
|
|
fa->peer.groupid != peer->conf.groupid) { |
354 |
|
|
fa = TAILQ_NEXT(fa, entry); |
355 |
|
|
continue; |
356 |
|
|
} |
357 |
|
|
if (peer != NULL && fa != NULL && fa->peer.peerid != 0 && |
358 |
|
|
fa->peer.peerid != peer->conf.id) { |
359 |
|
|
fa = TAILQ_NEXT(fa, entry); |
360 |
|
|
continue; |
361 |
|
|
} |
362 |
|
|
|
363 |
|
|
if (peer != NULL && fb != NULL && fb->peer.groupid != 0 && |
364 |
|
|
fb->peer.groupid != peer->conf.groupid) { |
365 |
|
|
fb = TAILQ_NEXT(fb, entry); |
366 |
|
|
continue; |
367 |
|
|
} |
368 |
|
|
if (peer != NULL && fb != NULL && fb->peer.peerid != 0 && |
369 |
|
|
fb->peer.peerid != peer->conf.id) { |
370 |
|
|
fb = TAILQ_NEXT(fb, entry); |
371 |
|
|
continue; |
372 |
|
|
} |
373 |
|
|
|
374 |
|
|
if (peer != NULL && fa != NULL && fa->peer.remote_as != 0 && |
375 |
|
|
fa->peer.remote_as != peer->conf.remote_as) { |
376 |
|
|
fa = TAILQ_NEXT(fa, entry); |
377 |
|
|
continue; |
378 |
|
|
} |
379 |
|
|
|
380 |
|
|
/* compare the two rules */ |
381 |
|
|
if ((fa == NULL && fb != NULL) || (fa != NULL && fb == NULL)) |
382 |
|
|
/* new rule added or removed */ |
383 |
|
|
return (0); |
384 |
|
|
|
385 |
|
|
if (fa->action != fb->action || fa->quick != fb->quick) |
386 |
|
|
return (0); |
387 |
|
|
if (memcmp(&fa->peer, &fb->peer, sizeof(fa->peer))) |
388 |
|
|
return (0); |
389 |
|
|
if (memcmp(&fa->match, &fb->match, sizeof(fa->match))) |
390 |
|
|
return (0); |
391 |
|
|
if (!filterset_equal(&fa->set, &fb->set)) |
392 |
|
|
return (0); |
393 |
|
|
|
394 |
|
|
fa = TAILQ_NEXT(fa, entry); |
395 |
|
|
fb = TAILQ_NEXT(fb, entry); |
396 |
|
|
} |
397 |
|
|
return (1); |
398 |
|
|
} |
399 |
|
|
|
400 |
|
|
void |
401 |
|
|
filterlist_free(struct filter_head *fh) |
402 |
|
|
{ |
403 |
|
|
struct filter_rule *r; |
404 |
|
|
|
405 |
|
|
if (fh == NULL) |
406 |
|
|
return; |
407 |
|
|
|
408 |
|
|
while ((r = TAILQ_FIRST(fh)) != NULL) { |
409 |
|
|
TAILQ_REMOVE(fh, r, entry); |
410 |
|
|
filterset_free(&r->set); |
411 |
|
|
free(r); |
412 |
|
|
} |
413 |
|
|
free(fh); |
414 |
|
|
} |
415 |
|
|
|
416 |
|
|
/* free a filterset and take care of possible name2id references */ |
417 |
|
|
void |
418 |
|
|
filterset_free(struct filter_set_head *sh) |
419 |
|
|
{ |
420 |
|
|
struct filter_set *s; |
421 |
|
|
struct nexthop *nh; |
422 |
|
|
|
423 |
|
|
if (sh == NULL) |
424 |
|
|
return; |
425 |
|
|
|
426 |
|
|
while ((s = TAILQ_FIRST(sh)) != NULL) { |
427 |
|
|
TAILQ_REMOVE(sh, s, entry); |
428 |
|
|
if (s->type == ACTION_RTLABEL_ID) |
429 |
|
|
rtlabel_unref(s->action.id); |
430 |
|
|
else if (s->type == ACTION_PFTABLE_ID) |
431 |
|
|
pftable_unref(s->action.id); |
432 |
|
|
else if (s->type == ACTION_SET_NEXTHOP && |
433 |
|
|
bgpd_process == PROC_RDE) { |
434 |
|
|
nh = nexthop_get(&s->action.nexthop); |
435 |
|
|
--nh->refcnt; |
436 |
|
|
(void)nexthop_delete(nh); |
437 |
|
|
} |
438 |
|
|
free(s); |
439 |
|
|
} |
440 |
|
|
} |
441 |
|
|
|
442 |
|
|
/* |
443 |
|
|
* this function is a bit more complicated than a memcmp() because there are |
444 |
|
|
* types that need to be considered equal e.g. ACTION_SET_MED and |
445 |
|
|
* ACTION_SET_RELATIVE_MED. Also ACTION_SET_COMMUNITY and ACTION_SET_NEXTHOP |
446 |
|
|
* need some special care. It only checks the types and not the values so |
447 |
|
|
* it does not do a real compare. |
448 |
|
|
*/ |
449 |
|
|
int |
450 |
|
|
filterset_cmp(struct filter_set *a, struct filter_set *b) |
451 |
|
|
{ |
452 |
|
|
if (strcmp(filterset_name(a->type), filterset_name(b->type))) |
453 |
|
|
return (a->type - b->type); |
454 |
|
|
|
455 |
|
|
if (a->type == ACTION_SET_COMMUNITY || |
456 |
|
|
a->type == ACTION_DEL_COMMUNITY) { /* a->type == b->type */ |
457 |
|
|
/* compare community */ |
458 |
|
|
if (a->action.community.as - b->action.community.as != 0) |
459 |
|
|
return (a->action.community.as - |
460 |
|
|
b->action.community.as); |
461 |
|
|
return (a->action.community.type - b->action.community.type); |
462 |
|
|
} |
463 |
|
|
|
464 |
|
|
if (a->type == ACTION_SET_EXT_COMMUNITY || |
465 |
|
|
a->type == ACTION_DEL_EXT_COMMUNITY) { /* a->type == b->type */ |
466 |
|
|
return (memcmp(&a->action.ext_community, |
467 |
|
|
&b->action.ext_community, sizeof(a->action.ext_community))); |
468 |
|
|
} |
469 |
|
|
|
470 |
|
|
if (a->type == ACTION_SET_NEXTHOP && b->type == ACTION_SET_NEXTHOP) { |
471 |
|
|
/* |
472 |
|
|
* This is the only interesting case, all others are considered |
473 |
|
|
* equal. It does not make sense to e.g. set a nexthop and |
474 |
|
|
* reject it at the same time. Allow one IPv4 and one IPv6 |
475 |
|
|
* per filter set or only one of the other nexthop modifiers. |
476 |
|
|
*/ |
477 |
|
|
return (a->action.nexthop.aid - b->action.nexthop.aid); |
478 |
|
|
} |
479 |
|
|
|
480 |
|
|
/* equal */ |
481 |
|
|
return (0); |
482 |
|
|
} |
483 |
|
|
|
484 |
|
|
void |
485 |
|
|
filterset_move(struct filter_set_head *source, struct filter_set_head *dest) |
486 |
|
|
{ |
487 |
|
|
struct filter_set *s; |
488 |
|
|
|
489 |
|
|
TAILQ_INIT(dest); |
490 |
|
|
|
491 |
|
|
if (source == NULL) |
492 |
|
|
return; |
493 |
|
|
|
494 |
|
|
while ((s = TAILQ_FIRST(source)) != NULL) { |
495 |
|
|
TAILQ_REMOVE(source, s, entry); |
496 |
|
|
TAILQ_INSERT_TAIL(dest, s, entry); |
497 |
|
|
} |
498 |
|
|
} |
499 |
|
|
|
500 |
|
|
int |
501 |
|
|
filterset_equal(struct filter_set_head *ah, struct filter_set_head *bh) |
502 |
|
|
{ |
503 |
|
|
struct filter_set *a, *b; |
504 |
|
|
const char *as, *bs; |
505 |
|
|
|
506 |
|
|
for (a = TAILQ_FIRST(ah), b = TAILQ_FIRST(bh); |
507 |
|
|
a != NULL && b != NULL; |
508 |
|
|
a = TAILQ_NEXT(a, entry), b = TAILQ_NEXT(b, entry)) { |
509 |
|
|
switch (a->type) { |
510 |
|
|
case ACTION_SET_PREPEND_SELF: |
511 |
|
|
case ACTION_SET_PREPEND_PEER: |
512 |
|
|
if (a->type == b->type && |
513 |
|
|
a->action.prepend == b->action.prepend) |
514 |
|
|
continue; |
515 |
|
|
break; |
516 |
|
|
case ACTION_SET_LOCALPREF: |
517 |
|
|
case ACTION_SET_MED: |
518 |
|
|
case ACTION_SET_WEIGHT: |
519 |
|
|
if (a->type == b->type && |
520 |
|
|
a->action.metric == b->action.metric) |
521 |
|
|
continue; |
522 |
|
|
break; |
523 |
|
|
case ACTION_SET_RELATIVE_LOCALPREF: |
524 |
|
|
case ACTION_SET_RELATIVE_MED: |
525 |
|
|
case ACTION_SET_RELATIVE_WEIGHT: |
526 |
|
|
if (a->type == b->type && |
527 |
|
|
a->action.relative == b->action.relative) |
528 |
|
|
continue; |
529 |
|
|
break; |
530 |
|
|
case ACTION_SET_NEXTHOP: |
531 |
|
|
if (a->type == b->type && |
532 |
|
|
memcmp(&a->action.nexthop, &b->action.nexthop, |
533 |
|
|
sizeof(a->action.nexthop)) == 0) |
534 |
|
|
continue; |
535 |
|
|
break; |
536 |
|
|
case ACTION_SET_NEXTHOP_BLACKHOLE: |
537 |
|
|
case ACTION_SET_NEXTHOP_REJECT: |
538 |
|
|
case ACTION_SET_NEXTHOP_NOMODIFY: |
539 |
|
|
case ACTION_SET_NEXTHOP_SELF: |
540 |
|
|
if (a->type == b->type) |
541 |
|
|
continue; |
542 |
|
|
break; |
543 |
|
|
case ACTION_DEL_COMMUNITY: |
544 |
|
|
case ACTION_SET_COMMUNITY: |
545 |
|
|
if (a->type == b->type && |
546 |
|
|
memcmp(&a->action.community, &b->action.community, |
547 |
|
|
sizeof(a->action.community)) == 0) |
548 |
|
|
continue; |
549 |
|
|
break; |
550 |
|
|
case ACTION_PFTABLE: |
551 |
|
|
case ACTION_PFTABLE_ID: |
552 |
|
|
if (b->type == ACTION_PFTABLE) |
553 |
|
|
bs = b->action.pftable; |
554 |
|
|
else if (b->type == ACTION_PFTABLE_ID) |
555 |
|
|
bs = pftable_id2name(b->action.id); |
556 |
|
|
else |
557 |
|
|
break; |
558 |
|
|
|
559 |
|
|
if (a->type == ACTION_PFTABLE) |
560 |
|
|
as = a->action.pftable; |
561 |
|
|
else |
562 |
|
|
as = pftable_id2name(a->action.id); |
563 |
|
|
|
564 |
|
|
if (strcmp(as, bs) == 0) |
565 |
|
|
continue; |
566 |
|
|
break; |
567 |
|
|
case ACTION_RTLABEL: |
568 |
|
|
case ACTION_RTLABEL_ID: |
569 |
|
|
if (b->type == ACTION_RTLABEL) |
570 |
|
|
bs = b->action.rtlabel; |
571 |
|
|
else if (b->type == ACTION_RTLABEL_ID) |
572 |
|
|
bs = rtlabel_id2name(b->action.id); |
573 |
|
|
else |
574 |
|
|
break; |
575 |
|
|
|
576 |
|
|
if (a->type == ACTION_RTLABEL) |
577 |
|
|
as = a->action.rtlabel; |
578 |
|
|
else |
579 |
|
|
as = rtlabel_id2name(a->action.id); |
580 |
|
|
|
581 |
|
|
if (strcmp(as, bs) == 0) |
582 |
|
|
continue; |
583 |
|
|
break; |
584 |
|
|
case ACTION_SET_ORIGIN: |
585 |
|
|
if (a->type == b->type && |
586 |
|
|
a->action.origin == b->action.origin) |
587 |
|
|
continue; |
588 |
|
|
break; |
589 |
|
|
case ACTION_SET_EXT_COMMUNITY: |
590 |
|
|
case ACTION_DEL_EXT_COMMUNITY: |
591 |
|
|
if (a->type == b->type && memcmp( |
592 |
|
|
&a->action.ext_community, |
593 |
|
|
&b->action.ext_community, |
594 |
|
|
sizeof(a->action.ext_community)) == 0) |
595 |
|
|
continue; |
596 |
|
|
break; |
597 |
|
|
} |
598 |
|
|
/* compare failed */ |
599 |
|
|
return (0); |
600 |
|
|
} |
601 |
|
|
if (a != NULL || b != NULL) |
602 |
|
|
return (0); |
603 |
|
|
return (1); |
604 |
|
|
} |
605 |
|
|
|
606 |
|
|
const char * |
607 |
|
|
filterset_name(enum action_types type) |
608 |
|
|
{ |
609 |
|
|
switch (type) { |
610 |
|
|
case ACTION_SET_LOCALPREF: |
611 |
|
|
case ACTION_SET_RELATIVE_LOCALPREF: |
612 |
|
|
return ("localpref"); |
613 |
|
|
case ACTION_SET_MED: |
614 |
|
|
case ACTION_SET_RELATIVE_MED: |
615 |
|
|
return ("metric"); |
616 |
|
|
case ACTION_SET_WEIGHT: |
617 |
|
|
case ACTION_SET_RELATIVE_WEIGHT: |
618 |
|
|
return ("weight"); |
619 |
|
|
case ACTION_SET_PREPEND_SELF: |
620 |
|
|
return ("prepend-self"); |
621 |
|
|
case ACTION_SET_PREPEND_PEER: |
622 |
|
|
return ("prepend-peer"); |
623 |
|
|
case ACTION_SET_NEXTHOP: |
624 |
|
|
case ACTION_SET_NEXTHOP_REJECT: |
625 |
|
|
case ACTION_SET_NEXTHOP_BLACKHOLE: |
626 |
|
|
case ACTION_SET_NEXTHOP_NOMODIFY: |
627 |
|
|
case ACTION_SET_NEXTHOP_SELF: |
628 |
|
|
return ("nexthop"); |
629 |
|
|
case ACTION_SET_COMMUNITY: |
630 |
|
|
return ("community"); |
631 |
|
|
case ACTION_DEL_COMMUNITY: |
632 |
|
|
return ("community delete"); |
633 |
|
|
case ACTION_PFTABLE: |
634 |
|
|
case ACTION_PFTABLE_ID: |
635 |
|
|
return ("pftable"); |
636 |
|
|
case ACTION_RTLABEL: |
637 |
|
|
case ACTION_RTLABEL_ID: |
638 |
|
|
return ("rtlabel"); |
639 |
|
|
case ACTION_SET_ORIGIN: |
640 |
|
|
return ("origin"); |
641 |
|
|
case ACTION_SET_EXT_COMMUNITY: |
642 |
|
|
return ("ext-community"); |
643 |
|
|
case ACTION_DEL_EXT_COMMUNITY: |
644 |
|
|
return ("ext-community delete"); |
645 |
|
|
} |
646 |
|
|
|
647 |
|
|
fatalx("filterset_name: got lost"); |
648 |
|
|
} |
649 |
|
|
|
650 |
|
|
/* |
651 |
|
|
* Copyright (c) 2001 Daniel Hartmeier |
652 |
|
|
* All rights reserved. |
653 |
|
|
* |
654 |
|
|
* Redistribution and use in source and binary forms, with or without |
655 |
|
|
* modification, are permitted provided that the following conditions |
656 |
|
|
* are met: |
657 |
|
|
* |
658 |
|
|
* - Redistributions of source code must retain the above copyright |
659 |
|
|
* notice, this list of conditions and the following disclaimer. |
660 |
|
|
* - Redistributions in binary form must reproduce the above |
661 |
|
|
* copyright notice, this list of conditions and the following |
662 |
|
|
* disclaimer in the documentation and/or other materials provided |
663 |
|
|
* with the distribution. |
664 |
|
|
* |
665 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
666 |
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
667 |
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
668 |
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
669 |
|
|
* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
670 |
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
671 |
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
672 |
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
673 |
|
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
674 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
675 |
|
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
676 |
|
|
* POSSIBILITY OF SUCH DAMAGE. |
677 |
|
|
* |
678 |
|
|
* Effort sponsored in part by the Defense Advanced Research Projects |
679 |
|
|
* Agency (DARPA) and Air Force Research Laboratory, Air Force |
680 |
|
|
* Materiel Command, USAF, under agreement number F30602-01-2-0537. |
681 |
|
|
* |
682 |
|
|
*/ |
683 |
|
|
|
684 |
|
|
#define RDE_FILTER_SET_SKIP_STEPS(i) \ |
685 |
|
|
do { \ |
686 |
|
|
while (head[i] != cur) { \ |
687 |
|
|
head[i]->skip[i].ptr = cur; \ |
688 |
|
|
head[i] = TAILQ_NEXT(head[i], entry); \ |
689 |
|
|
} \ |
690 |
|
|
} while (0) |
691 |
|
|
|
692 |
|
|
struct peer; |
693 |
|
|
void print_rule(struct peer *, struct filter_rule *); |
694 |
|
|
|
695 |
|
|
void |
696 |
|
|
rde_filter_calc_skip_steps(struct filter_head *rules) |
697 |
|
|
{ |
698 |
|
|
struct filter_rule *cur, *prev, *head[RDE_FILTER_SKIP_COUNT]; |
699 |
|
|
int i; |
700 |
|
|
|
701 |
|
|
if (rules == NULL) |
702 |
|
|
return; |
703 |
|
|
|
704 |
|
|
cur = TAILQ_FIRST(rules); |
705 |
|
|
|
706 |
|
|
prev = cur; |
707 |
|
|
for (i = 0; i < RDE_FILTER_SKIP_COUNT; ++i) |
708 |
|
|
head[i] = cur; |
709 |
|
|
while (cur != NULL) { |
710 |
|
|
if (cur->peer.groupid != prev->peer.groupid) |
711 |
|
|
RDE_FILTER_SET_SKIP_STEPS(RDE_FILTER_SKIP_GROUPID); |
712 |
|
|
if (cur->peer.remote_as != prev->peer.remote_as) |
713 |
|
|
RDE_FILTER_SET_SKIP_STEPS(RDE_FILTER_SKIP_REMOTE_AS); |
714 |
|
|
if (cur->peer.peerid != prev->peer.peerid) |
715 |
|
|
RDE_FILTER_SET_SKIP_STEPS(RDE_FILTER_SKIP_PEERID); |
716 |
|
|
prev = cur; |
717 |
|
|
cur = TAILQ_NEXT(cur, entry); |
718 |
|
|
} |
719 |
|
|
for (i = 0; i < RDE_FILTER_SKIP_COUNT; ++i) |
720 |
|
|
RDE_FILTER_SET_SKIP_STEPS(i); |
721 |
|
|
|
722 |
|
|
} |
723 |
|
|
|
724 |
|
|
#define RDE_FILTER_TEST_ATTRIB(t, a) \ |
725 |
|
|
do { \ |
726 |
|
|
if (t) { \ |
727 |
|
|
f = a; \ |
728 |
|
|
goto nextrule; \ |
729 |
|
|
} \ |
730 |
|
|
} while (0) |
731 |
|
|
|
732 |
|
|
enum filter_actions |
733 |
|
|
rde_filter(struct filter_head *rules, struct rde_aspath **new, |
734 |
|
|
struct rde_peer *peer, struct rde_aspath *asp, struct bgpd_addr *prefix, |
735 |
|
|
u_int8_t prefixlen, struct rde_peer *from) |
736 |
|
|
{ |
737 |
|
|
struct filter_rule *f; |
738 |
|
|
enum filter_actions action = ACTION_ALLOW; /* default allow */ |
739 |
|
|
|
740 |
|
|
if (new != NULL) |
741 |
|
|
*new = NULL; |
742 |
|
|
|
743 |
|
|
if (asp->flags & F_ATTR_PARSE_ERR) |
744 |
|
|
/* |
745 |
|
|
* don't try to filter bad updates just deny them |
746 |
|
|
* so they act as implicit withdraws |
747 |
|
|
*/ |
748 |
|
|
return (ACTION_DENY); |
749 |
|
|
|
750 |
|
|
if (rules == NULL) |
751 |
|
|
return (action); |
752 |
|
|
|
753 |
|
|
f = TAILQ_FIRST(rules); |
754 |
|
|
while (f != NULL) { |
755 |
|
|
RDE_FILTER_TEST_ATTRIB( |
756 |
|
|
(f->peer.groupid && |
757 |
|
|
f->peer.groupid != peer->conf.groupid), |
758 |
|
|
f->skip[RDE_FILTER_SKIP_GROUPID].ptr); |
759 |
|
|
RDE_FILTER_TEST_ATTRIB( |
760 |
|
|
(f->peer.remote_as && |
761 |
|
|
f->peer.remote_as != peer->conf.remote_as), |
762 |
|
|
f->skip[RDE_FILTER_SKIP_REMOTE_AS].ptr); |
763 |
|
|
RDE_FILTER_TEST_ATTRIB( |
764 |
|
|
(f->peer.peerid && |
765 |
|
|
f->peer.peerid != peer->conf.id), |
766 |
|
|
f->skip[RDE_FILTER_SKIP_PEERID].ptr); |
767 |
|
|
if (rde_filter_match(f, asp, prefix, prefixlen, peer, from)) { |
768 |
|
|
if (asp != NULL && new != NULL) { |
769 |
|
|
/* asp may get modified so create a copy */ |
770 |
|
|
if (*new == NULL) { |
771 |
|
|
*new = path_copy(asp); |
772 |
|
|
/* ... and use the copy from now on */ |
773 |
|
|
asp = *new; |
774 |
|
|
} |
775 |
|
|
rde_apply_set(asp, &f->set, prefix->aid, |
776 |
|
|
from, peer); |
777 |
|
|
} |
778 |
|
|
if (f->action != ACTION_NONE) |
779 |
|
|
action = f->action; |
780 |
|
|
if (f->quick) |
781 |
|
|
return (action); |
782 |
|
|
} |
783 |
|
|
f = TAILQ_NEXT(f, entry); |
784 |
|
|
nextrule: ; |
785 |
|
|
} |
786 |
|
|
return (action); |
787 |
|
|
} |