diff options
-rw-r--r-- | usr.sbin/bgpd/bgpd.conf.5 | 38 | ||||
-rw-r--r-- | usr.sbin/bgpd/bgpd.h | 13 | ||||
-rw-r--r-- | usr.sbin/bgpd/parse.y | 237 | ||||
-rw-r--r-- | usr.sbin/bgpd/printconf.c | 25 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde_filter.c | 58 | ||||
-rw-r--r-- | usr.sbin/bgpd/util.c | 6 |
6 files changed, 195 insertions, 182 deletions
diff --git a/usr.sbin/bgpd/bgpd.conf.5 b/usr.sbin/bgpd/bgpd.conf.5 index 28852119f03..d3520150dc3 100644 --- a/usr.sbin/bgpd/bgpd.conf.5 +++ b/usr.sbin/bgpd/bgpd.conf.5 @@ -1,4 +1,4 @@ -.\" $OpenBSD: bgpd.conf.5,v 1.128 2013/10/17 09:14:02 blambert Exp $ +.\" $OpenBSD: bgpd.conf.5,v 1.129 2013/10/19 15:04:25 claudio Exp $ .\" .\" Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org> .\" Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -16,7 +16,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: October 17 2013 $ +.Dd $Mdocdate: October 19 2013 $ .Dt BGPD.CONF 5 .Os .Sh NAME @@ -1156,11 +1156,6 @@ deny from { 128.251.16.1, 251.128.16.2, group hojo } .Pp .It Pq Ic inet Ns | Ns Ic inet6 This rule applies only to routes matching the stated address family. -The address family needs to be set only in rules that use -.Ic prefixlen -without specifying a -.Ic prefix -beforehand. .Pp .It Ic max-as-len Ar len This rule applies only to @@ -1193,37 +1188,30 @@ in which case the nexthop is compared against the address of the neighbor. Nexthop filtering is not supported on locally announced networks and one must take into consideration previous rules overwriting nexthops. .Pp -.It Xo -.Ic prefix -.Ar address Ns Li / Ns Ar len -.Xc +.It Ic prefix Ar address Ns Li / Ns Ar len +.It Ic prefix Ar address Ns Li / Ns Ar len Ic prefixlen Ar range +.It Ic prefix Ar address Ns Li / Ns Ar len Ic or-longer This rule applies only to .Em UPDATES for the specified prefix. .Pp -Multiple -.Ar address Ns Li / Ns Ar len -entries may be specified, +Multiple entries may be specified, separated by commas or whitespace, if enclosed in curly brackets: .Bd -literal -offset indent -deny from any prefix { 192.168.0.0/16, 10.0.0.0/8 } +deny from any prefix { 192.168.0.0/16, 10.0.0.0/8 or-longer } .Ed .Pp Multiple lists can also be specified, which is useful for macro expansion: .Bd -literal -offset indent good="{ 192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8 }" -bad="{ 224.0.0.0/4, 240.0.0.0/4 }" +bad="{ 224.0.0.0/4 prefixlen >= 4, 240.0.0.0/4 prefixlen >= 4 }" ugly="{ 127.0.0.1/8, 169.254.0.0/16 }" deny from any prefix { $good $bad $ugly } .Ed .Pp -.It Ic prefixlen Ar range -This rule applies only to -.Em UPDATES -for prefixes where the prefixlen matches. Prefix length ranges are specified by using these operators: .Bd -literal -offset indent = (equal) @@ -1250,16 +1238,18 @@ Or, to match all prefix lengths < 8 or > 12, and hence the CIDR netmasks prefixlen 8><12 .Ed .Pp -.Ic prefixlen -can be used together with -.Ic prefix . -.Pp This will match all prefixes in the 10.0.0.0/8 netblock with netmasks longer than 16: .Bd -literal -offset indent prefix 10.0.0.0/8 prefixlen > 16 .Ed .Pp +.Ic or-longer +is a shorthand for: +.Bd -literal -offset indent +.Ic prefix Ar address Ns Li / Ns Ar len Ic prexiflen Ic >= Ar len +.Ed +.Pp .It Ic quick If an .Em UPDATE diff --git a/usr.sbin/bgpd/bgpd.h b/usr.sbin/bgpd/bgpd.h index fef1958a1a1..67f79fc46c9 100644 --- a/usr.sbin/bgpd/bgpd.h +++ b/usr.sbin/bgpd/bgpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: bgpd.h,v 1.279 2013/09/27 08:23:10 sthen Exp $ */ +/* $OpenBSD: bgpd.h,v 1.280 2013/10/19 15:04:25 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -748,7 +748,10 @@ struct ext_comm_pairs { struct filter_prefix { struct bgpd_addr addr; + u_int8_t op; u_int8_t len; + u_int8_t len_min; + u_int8_t len_max; }; struct filter_nexthop { @@ -758,16 +761,8 @@ struct filter_nexthop { #define FILTER_NEXTHOP_NEIGHBOR 2 }; -struct filter_prefixlen { - enum comp_ops op; - u_int8_t aid; - u_int8_t len_min; - u_int8_t len_max; -}; - struct filter_match { struct filter_prefix prefix; - struct filter_prefixlen prefixlen; struct filter_nexthop nexthop; struct filter_as as; struct filter_aslen aslen; diff --git a/usr.sbin/bgpd/parse.y b/usr.sbin/bgpd/parse.y index b8f7f37ec03..1492a08cb58 100644 --- a/usr.sbin/bgpd/parse.y +++ b/usr.sbin/bgpd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.267 2013/09/27 08:23:11 sthen Exp $ */ +/* $OpenBSD: parse.y,v 1.268 2013/10/19 15:04:25 claudio Exp $ */ /* * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -99,6 +99,12 @@ struct filter_prefix_l { struct filter_prefix p; }; +struct filter_prefixlen { + enum comp_ops op; + int len_min; + int len_max; +}; + struct filter_as_l { struct filter_as_l *next; struct filter_as a; @@ -108,7 +114,6 @@ struct filter_match_l { struct filter_match m; struct filter_prefix_l *prefix_l; struct filter_as_l *as_l; - u_int8_t aid; } fmopts; struct peer *alloc_peer(void); @@ -119,6 +124,8 @@ int add_mrtconfig(enum mrt_type, char *, int, struct peer *, int add_rib(char *, u_int, u_int16_t); struct rde_rib *find_rib(char *); int get_id(struct peer *); +int merge_prefixspec(struct filter_prefix_l *, + struct filter_prefixlen *); int expand_rule(struct filter_rule *, struct filter_peers_l *, struct filter_match_l *, struct filter_set_head *); int str2key(char *, char *, size_t); @@ -145,13 +152,13 @@ typedef struct { struct filter_match_l filter_match; struct filter_prefix_l *filter_prefix; struct filter_as_l *filter_as; - struct filter_prefixlen prefixlen; struct filter_set *filter_set; struct filter_set_head *filter_set_head; struct { struct bgpd_addr prefix; u_int8_t len; } prefix; + struct filter_prefixlen prefixlen; struct { u_int8_t enc_alg; char enc_key[IPSEC_ENC_KEY_LEN]; @@ -185,7 +192,7 @@ typedef struct { %token IPSEC ESP AH SPI IKE %token IPV4 IPV6 %token QUALIFY VIA -%token NE LE GE XRANGE +%token NE LE GE XRANGE LONGER %token <v.string> STRING %token <v.number> NUMBER %type <v.number> asnumber as4number optnumber @@ -202,8 +209,7 @@ typedef struct { %type <v.prefixlen> prefixlenop %type <v.filter_set> filter_set_opt %type <v.filter_set_head> filter_set filter_set_l -%type <v.filter_prefix> filter_prefix filter_prefix_l -%type <v.filter_prefix> filter_prefix_h filter_prefix_m +%type <v.filter_prefix> filter_prefix filter_prefix_l filter_prefix_h %type <v.u8> unaryop binaryop filter_as_type %type <v.encspec> encspec %% @@ -1478,23 +1484,32 @@ filter_peer : ANY { } ; -filter_prefix_h : PREFIX filter_prefix { $$ = $2; } - | PREFIX '{' filter_prefix_m '}' { $$ = $3; } - ; - -filter_prefix_m : filter_prefix_l - | '{' filter_prefix_l '}' { $$ = $2; } - | '{' filter_prefix_l '}' filter_prefix_m - { - struct filter_prefix_l *p; - - /* merge, both can be lists */ - for (p = $2; p != NULL && p->next != NULL; p = p->next) - ; /* nothing */ - if (p != NULL) - p->next = $4; - $$ = $2; +filter_prefix_h : IPV4 prefixlenop { + if ($2.op == OP_NONE) + $2.op = OP_GE; + if (($$ = calloc(1, sizeof(struct filter_prefix_l))) == + NULL) + fatal(NULL); + $$->p.addr.aid = AID_INET; + if (merge_prefixspec($$, &$2) == -1) { + free($$); + YYERROR; + } + } + | IPV6 prefixlenop { + if ($2.op == OP_NONE) + $2.op = OP_GE; + if (($$ = calloc(1, sizeof(struct filter_prefix_l))) == + NULL) + fatal(NULL); + $$->p.addr.aid = AID_INET6; + if (merge_prefixspec($$, &$2) == -1) { + free($$); + YYERROR; + } } + | PREFIX filter_prefix { $$ = $2; } + | PREFIX '{' filter_prefix_l '}' { $$ = $3; } ; filter_prefix_l : filter_prefix { $$ = $1; } @@ -1504,20 +1519,18 @@ filter_prefix_l : filter_prefix { $$ = $1; } } ; -filter_prefix : prefix { - if (fmopts.aid && fmopts.aid != $1.prefix.aid) { - yyerror("rules with mixed address families " - "are not allowed"); - YYERROR; - } else - fmopts.aid = $1.prefix.aid; +filter_prefix : prefix prefixlenop { if (($$ = calloc(1, sizeof(struct filter_prefix_l))) == NULL) fatal(NULL); memcpy(&$$->p.addr, &$1.prefix, sizeof($$->p.addr)); $$->p.len = $1.len; - $$->next = NULL; + + if (merge_prefixspec($$, &$2) == -1) { + free($$); + YYERROR; + } } ; @@ -1611,20 +1624,6 @@ filter_elm : filter_prefix_h { } fmopts.prefix_l = $1; } - | PREFIXLEN prefixlenop { - if (fmopts.aid == 0) { - yyerror("address family needs to be specified " - "before \"prefixlen\""); - YYERROR; - } - if (fmopts.m.prefixlen.aid) { - yyerror("\"prefixlen\" already specified"); - YYERROR; - } - memcpy(&fmopts.m.prefixlen, &$2, - sizeof(fmopts.m.prefixlen)); - fmopts.m.prefixlen.aid = fmopts.aid; - } | filter_as_h { if (fmopts.as_l != NULL) { yyerror("AS filters already specified"); @@ -1686,30 +1685,11 @@ filter_elm : filter_prefix_h { free($2); free($3); } - | IPV4 { - if (fmopts.aid) { - yyerror("address family already specified"); - YYERROR; - } - fmopts.aid = AID_INET; - } - | IPV6 { - if (fmopts.aid) { - yyerror("address family already specified"); - YYERROR; - } - fmopts.aid = AID_INET6; - } | NEXTHOP address { if (fmopts.m.nexthop.flags) { yyerror("nexthop already specified"); YYERROR; } - if (fmopts.aid && fmopts.aid != $2.aid) { - yyerror("nexthop address family doesn't match " - "rule address family"); - YYERROR; - } fmopts.m.nexthop.addr = $2; fmopts.m.nexthop.flags = FILTER_NEXTHOP_ADDR; } @@ -1722,28 +1702,38 @@ filter_elm : filter_prefix_h { } ; -prefixlenop : unaryop NUMBER { +prefixlenop : /* empty */ { bzero(&$$, sizeof($$)); } + | LONGER { bzero(&$$, sizeof($$)); - if ($2 < 0 || $2 > 128) { - yyerror("prefixlen must be < 128"); + $$.op = OP_GE; + $$.len_min = -1; + } + | PREFIXLEN unaryop NUMBER { + bzero(&$$, sizeof($$)); + if ($3 < 0 || $3 > 128) { + yyerror("prefixlen must be >= 0 and <= 128"); YYERROR; } - $$.op = $1; - $$.len_min = $2; + if ($2 == OP_GT && $3 == 0) { + yyerror("prefixlen must be > 0"); + YYERROR; + } + $$.op = $2; + $$.len_min = $3; } - | NUMBER binaryop NUMBER { + | PREFIXLEN NUMBER binaryop NUMBER { bzero(&$$, sizeof($$)); - if ($1 < 0 || $1 > 128 || $3 < 0 || $3 > 128) { + if ($2 < 0 || $2 > 128 || $4 < 0 || $4 > 128) { yyerror("prefixlen must be < 128"); YYERROR; } - if ($1 >= $3) { + if ($2 >= $4) { yyerror("start prefixlen is bigger than end"); YYERROR; } - $$.op = $2; - $$.len_min = $1; - $$.len_max = $3; + $$.op = $3; + $$.len_min = $2; + $$.len_max = $4; } ; @@ -2181,6 +2171,7 @@ lookup(char *s) { "nexthop", NEXTHOP}, { "no-modify", NOMODIFY}, { "on", ON}, + { "or-longer", LONGER}, { "origin", ORIGIN}, { "out", OUT}, { "passive", PASSIVE}, @@ -3229,6 +3220,78 @@ get_id(struct peer *newpeer) } int +merge_prefixspec(struct filter_prefix_l *p, struct filter_prefixlen *pl) +{ + u_int8_t max_len = 0; + + switch (p->p.addr.aid) { + case AID_INET: + case AID_VPN_IPv4: + max_len = 32; + break; + case AID_INET6: + max_len = 128; + break; + } + + switch (pl->op) { + case OP_NONE: + return (0); + case OP_RANGE: + case OP_XRANGE: + if (pl->len_min > max_len || pl->len_max > max_len) { + yyerror("prefixlen %d too big for AF, limit %d", + pl->len_min > max_len ? pl->len_min : pl->len_max, + max_len); + return (-1); + } + if (pl->len_min < p->p.len) { + yyerror("prefixlen %d smaller than prefix, limit %d", + pl->len_min, p->p.len); + return (-1); + } + p->p.len_max = pl->len_max; + break; + case OP_GE: + /* fix up the "or-longer" case */ + if (pl->len_min == -1) + pl->len_min = p->p.len; + /* FALLTHROUGH */ + case OP_EQ: + case OP_NE: + case OP_LE: + case OP_GT: + if (pl->len_min > max_len) { + yyerror("prefixlen %d to big for AF, limit %d", + pl->len_min, max_len); + return (-1); + } + if (pl->len_min < p->p.len) { + yyerror("prefixlen %d smaller than prefix, limit %d", + pl->len_min, p->p.len); + return (-1); + } + break; + case OP_LT: + if (pl->len_min > max_len - 1) { + yyerror("prefixlen %d to big for AF, limit %d", + pl->len_min, max_len - 1); + return (-1); + } + if (pl->len_min < p->p.len + 1) { + yyerror("prefixlen %d too small for prefix, limit %d", + pl->len_min, p->p.len + 1); + return (-1); + } + break; + } + + p->p.op = pl->op; + p->p.len_min = pl->len_min; + return (0); +} + +int expand_rule(struct filter_rule *rule, struct filter_peers_l *peer, struct filter_match_l *match, struct filter_set_head *set) { @@ -3240,9 +3303,9 @@ expand_rule(struct filter_rule *rule, struct filter_peers_l *peer, p = peer; do { - prefix = match->prefix_l; + a = match->as_l; do { - a = match->as_l; + prefix = match->prefix_l; do { if ((r = calloc(1, sizeof(struct filter_rule))) == NULL) { @@ -3270,13 +3333,13 @@ expand_rule(struct filter_rule *rule, struct filter_peers_l *peer, TAILQ_INSERT_TAIL(filter_l, r, entry); - if (a != NULL) - a = a->next; - } while (a != NULL); + if (prefix != NULL) + prefix = prefix->next; + } while (prefix != NULL); - if (prefix != NULL) - prefix = prefix->next; - } while (prefix != NULL); + if (a != NULL) + a = a->next; + } while (a != NULL); if (p != NULL) p = p->next; @@ -3287,16 +3350,16 @@ expand_rule(struct filter_rule *rule, struct filter_peers_l *peer, free(p); } - for (prefix = match->prefix_l; prefix != NULL; prefix = prefix_next) { - prefix_next = prefix->next; - free(prefix); - } - for (a = match->as_l; a != NULL; a = anext) { anext = a->next; free(a); } + for (prefix = match->prefix_l; prefix != NULL; prefix = prefix_next) { + prefix_next = prefix->next; + free(prefix); + } + if (set != NULL) { while ((s = TAILQ_FIRST(set)) != NULL) { TAILQ_REMOVE(set, s, entry); diff --git a/usr.sbin/bgpd/printconf.c b/usr.sbin/bgpd/printconf.c index ab2a4157344..5674838d13d 100644 --- a/usr.sbin/bgpd/printconf.c +++ b/usr.sbin/bgpd/printconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: printconf.c,v 1.90 2013/01/17 02:00:33 claudio Exp $ */ +/* $OpenBSD: printconf.c,v 1.91 2013/10/19 15:04:25 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -548,23 +548,16 @@ print_rule(struct peer *peer_l, struct filter_rule *r) printf("prefix %s/%u ", log_addr(&r->match.prefix.addr), r->match.prefix.len); - if (r->match.prefix.addr.aid == 0 && r->match.prefixlen.aid) { - if (r->match.prefixlen.aid == AID_INET) - printf("inet "); - if (r->match.prefixlen.aid == AID_INET6) - printf("inet6 "); - } - - if (r->match.prefixlen.op) { - if (r->match.prefixlen.op == OP_RANGE || - r->match.prefixlen.op == OP_XRANGE) { - printf("prefixlen %u ", r->match.prefixlen.len_min); - print_op(r->match.prefixlen.op); - printf(" %u ", r->match.prefixlen.len_max); + if (r->match.prefix.op) { + if (r->match.prefix.op == OP_RANGE || + r->match.prefix.op == OP_XRANGE) { + printf("prefixlen %u ", r->match.prefix.len_min); + print_op(r->match.prefix.op); + printf(" %u ", r->match.prefix.len_max); } else { printf("prefixlen "); - print_op(r->match.prefixlen.op); - printf(" %u ", r->match.prefixlen.len_min); + print_op(r->match.prefix.op); + printf(" %u ", r->match.prefix.len_min); } } diff --git a/usr.sbin/bgpd/rde_filter.c b/usr.sbin/bgpd/rde_filter.c index 830702d5a03..e1e2fb35a5b 100644 --- a/usr.sbin/bgpd/rde_filter.c +++ b/usr.sbin/bgpd/rde_filter.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde_filter.c,v 1.69 2013/08/14 20:34:27 claudio Exp $ */ +/* $OpenBSD: rde_filter.c,v 1.70 2013/10/19 15:04:25 claudio Exp $ */ /* * Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org> @@ -329,58 +329,26 @@ rde_filter_match(struct filter_rule *f, struct rde_aspath *asp, return (0); /* test prefixlen stuff too */ - switch (f->match.prefixlen.op) { - case OP_NONE: - /* perfect match */ - return (plen == f->match.prefix.len); - case OP_RANGE: - return ((plen >= f->match.prefixlen.len_min) && - (plen <= f->match.prefixlen.len_max)); - case OP_XRANGE: - return ((plen < f->match.prefixlen.len_min) || - (plen > f->match.prefixlen.len_max)); + switch (f->match.prefix.op) { + case OP_NONE: /* perfect match */ case OP_EQ: - return (plen == f->match.prefixlen.len_min); + return (plen == f->match.prefix.len); case OP_NE: - return (plen != f->match.prefixlen.len_min); - case OP_LE: - return (plen <= f->match.prefixlen.len_min); - case OP_LT: - return (plen < f->match.prefixlen.len_min); - case OP_GE: - return (plen >= f->match.prefixlen.len_min); - case OP_GT: - return (plen > f->match.prefixlen.len_min); - } - /* NOTREACHED */ - } else if (f->match.prefixlen.op != OP_NONE) { - /* only prefixlen without a prefix */ - - if (f->match.prefixlen.aid != prefix->aid) - /* don't use IPv4 rules for IPv6 and vice versa */ - return (0); - - switch (f->match.prefixlen.op) { - case OP_NONE: - fatalx("internal filter bug"); + return (plen != f->match.prefix.len_min); case OP_RANGE: - return ((plen >= f->match.prefixlen.len_min) && - (plen <= f->match.prefixlen.len_max)); + return ((plen >= f->match.prefix.len_min) && + (plen <= f->match.prefix.len_max)); case OP_XRANGE: - return ((plen < f->match.prefixlen.len_min) || - (plen > f->match.prefixlen.len_max)); - case OP_EQ: - return (plen == f->match.prefixlen.len_min); - case OP_NE: - return (plen != f->match.prefixlen.len_min); + return ((plen < f->match.prefix.len_min) || + (plen > f->match.prefix.len_max)); case OP_LE: - return (plen <= f->match.prefixlen.len_min); + return (plen <= f->match.prefix.len_min); case OP_LT: - return (plen < f->match.prefixlen.len_min); + return (plen < f->match.prefix.len_min); case OP_GE: - return (plen >= f->match.prefixlen.len_min); + return (plen >= f->match.prefix.len_min); case OP_GT: - return (plen > f->match.prefixlen.len_min); + return (plen > f->match.prefix.len_min); } /* NOTREACHED */ } diff --git a/usr.sbin/bgpd/util.c b/usr.sbin/bgpd/util.c index c1d9bb07583..d8df024d1c3 100644 --- a/usr.sbin/bgpd/util.c +++ b/usr.sbin/bgpd/util.c @@ -1,4 +1,4 @@ -/* $OpenBSD: util.c,v 1.15 2013/09/27 08:23:11 sthen Exp $ */ +/* $OpenBSD: util.c,v 1.16 2013/10/19 15:04:26 claudio Exp $ */ /* * Copyright (c) 2006 Claudio Jeker <claudio@openbsd.org> @@ -422,6 +422,8 @@ prefix_compare(const struct bgpd_addr *a, const struct bgpd_addr *b, switch (a->aid) { case AID_INET: + if (prefixlen == 0) + return (0); if (prefixlen > 32) fatalx("prefix_cmp: bad IPv4 prefixlen"); mask = htonl(prefixlen2mask(prefixlen)); @@ -431,6 +433,8 @@ prefix_compare(const struct bgpd_addr *a, const struct bgpd_addr *b, return (aa - ba); return (0); case AID_INET6: + if (prefixlen == 0) + return (0); if (prefixlen > 128) fatalx("prefix_cmp: bad IPv6 prefixlen"); for (i = 0; i < prefixlen / 8; i++) |