diff options
author | Henning Brauer <henning@cvs.openbsd.org> | 2004-02-06 20:18:19 +0000 |
---|---|---|
committer | Henning Brauer <henning@cvs.openbsd.org> | 2004-02-06 20:18:19 +0000 |
commit | 32df521252cd6f82edd80623ba50da1fda799d58 (patch) | |
tree | 31d5ea23b568c3c1c0ef8350970bc5c2b55ed26b /usr.sbin/bgpd | |
parent | cbf513969d15cf3c78d5c5ea656aabd58d7a19fc (diff) |
initial cut at the filtering language.
structs etc to describe a rule, filter rule list management
parser groks filter defs now.
claudio ok, discussion & help also jakob theo
Diffstat (limited to 'usr.sbin/bgpd')
-rw-r--r-- | usr.sbin/bgpd/bgpd.c | 26 | ||||
-rw-r--r-- | usr.sbin/bgpd/bgpd.h | 87 | ||||
-rw-r--r-- | usr.sbin/bgpd/parse.y | 352 | ||||
-rw-r--r-- | usr.sbin/bgpd/session.h | 4 |
4 files changed, 449 insertions, 20 deletions
diff --git a/usr.sbin/bgpd/bgpd.c b/usr.sbin/bgpd/bgpd.c index 0089eea2a53..d865bf70957 100644 --- a/usr.sbin/bgpd/bgpd.c +++ b/usr.sbin/bgpd/bgpd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bgpd.c,v 1.73 2004/02/03 17:36:30 henning Exp $ */ +/* $OpenBSD: bgpd.c,v 1.74 2004/02/06 20:18:18 henning Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -41,7 +41,7 @@ void usage(void); int main(int, char *[]); int check_child(pid_t, const char *); int reconfigure(char *, struct bgpd_config *, struct mrt_head *, - struct peer **); + struct peer **, struct filter_head *); int dispatch_imsg(struct imsgbuf *, int, struct mrt_head *); int rfd = -1; @@ -96,7 +96,9 @@ main(int argc, char *argv[]) struct peer *peer_l; struct mrt_head mrt_l; struct network_head net_l; + struct filter_head rules_l; struct network *net; + struct filter_rule *r; struct mrt *(mrt[POLL_MAX]); struct pollfd pfd[POLL_MAX]; pid_t io_pid = 0, rde_pid = 0, pid; @@ -115,6 +117,7 @@ main(int argc, char *argv[]) bzero(&conf, sizeof(conf)); LIST_INIT(&mrt_l); TAILQ_INIT(&net_l); + TAILQ_INIT(&rules_l); peer_l = NULL; while ((ch = getopt(argc, argv, "dD:f:nv")) != -1) { @@ -144,7 +147,7 @@ main(int argc, char *argv[]) } } - if (parse_config(conffile, &conf, &mrt_l, &peer_l, &net_l)) + if (parse_config(conffile, &conf, &mrt_l, &peer_l, &net_l, &rules_l)) exit(1); if (conf.opts & BGPD_OPT_NOACTION) { @@ -216,6 +219,11 @@ main(int argc, char *argv[]) free(net); } + for (r = TAILQ_FIRST(&rules_l); r != NULL; r = TAILQ_FIRST(&rules_l)) { + TAILQ_REMOVE(&rules_l, r, entries); + free(r); + } + while (quit == 0) { pfd[PFD_PIPE_SESSION].fd = ibuf_se.sock; pfd[PFD_PIPE_SESSION].events = POLLIN; @@ -278,7 +286,7 @@ main(int argc, char *argv[]) if (reconfig) { log_info("rereading config"); - reconfigure(conffile, &conf, &mrt_l, &peer_l); + reconfigure(conffile, &conf, &mrt_l, &peer_l, &rules_l); reconfig = 0; } @@ -337,13 +345,14 @@ check_child(pid_t pid, const char *pname) int reconfigure(char *conffile, struct bgpd_config *conf, struct mrt_head *mrt_l, - struct peer **peer_l) + struct peer **peer_l, struct filter_head *rules_l) { struct network_head net_l; struct network *n; struct peer *p; + struct filter_rule *r; - if (parse_config(conffile, conf, mrt_l, peer_l, &net_l)) { + if (parse_config(conffile, conf, mrt_l, peer_l, &net_l, rules_l)) { log_warnx("config file %s has errors, not reloading", conffile); return (-1); @@ -371,6 +380,11 @@ reconfigure(char *conffile, struct bgpd_config *conf, struct mrt_head *mrt_l, TAILQ_REMOVE(&net_l, n, network_l); free(n); } + for (r = TAILQ_FIRST(rules_l); r != NULL; r = TAILQ_FIRST(rules_l)) { + /* XXX imsg_compose... */ + TAILQ_REMOVE(rules_l, r, entries); + free(r); + } if (imsg_compose(&ibuf_se, IMSG_RECONF_DONE, 0, NULL, 0) == -1 || imsg_compose(&ibuf_rde, IMSG_RECONF_DONE, 0, NULL, 0) == -1) return (-1); diff --git a/usr.sbin/bgpd/bgpd.h b/usr.sbin/bgpd/bgpd.h index df8597e3126..cf24aad2b1e 100644 --- a/usr.sbin/bgpd/bgpd.h +++ b/usr.sbin/bgpd/bgpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: bgpd.h,v 1.90 2004/02/05 14:29:09 henning Exp $ */ +/* $OpenBSD: bgpd.h,v 1.91 2004/02/06 20:18:18 henning Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -266,6 +266,91 @@ struct ctl_show_nexthop { u_int8_t valid; }; +enum filter_actions { + ACTION_NONE, + ACTION_ALLOW, + ACTION_DENY +}; + +enum directions { + DIR_IN=1, + DIR_OUT +}; + +enum from_spec { + FROM_ALL, + FROM_ADDRESS, + FROM_DESCR, + FROM_GROUP +}; + +enum as_spec { + AS_NONE, + AS_ALL, + AS_SOURCE, + AS_TRANSIT +}; + +enum comp_ops { + OP_NONE, + OP_RANGE, + OP_EQ, + OP_NE, + OP_LE, + OP_LT, + OP_GE, + OP_GT +}; + +/* set flags */ +#define SET_LOCALPREF 0x01 +#define SET_MED 0x02 +#define SET_NEXTHOP 0x04 +#define SET_NEXTHOP6 0x08 +#define SET_PREPEND 0x10 + +struct filter_peers { + u_int32_t peerid; + u_int32_t groupid; +}; + +struct filter_match { + struct { + struct bgpd_addr addr; + u_int8_t len; + } prefix; + struct { + enum comp_ops op; + u_int8_t len_min; + u_int8_t len_max; + } prefixlen; + struct { + u_int16_t as; + enum as_spec type; + } as; +}; + +struct filter_set { + u_int8_t flags; + u_int32_t localpref; + u_int32_t med; + struct in_addr nexthop; + struct in6_addr nexthop6; + u_int8_t prepend; +}; + +TAILQ_HEAD(filter_head, filter_rule); + +struct filter_rule { + TAILQ_ENTRY(filter_rule) entries; + enum filter_actions action; + enum directions dir; + u_int8_t quick; + struct filter_peers peer; + struct filter_match match; + struct filter_set set; +}; + /* prototypes */ /* bgpd.c */ void send_nexthop_update(struct kroute_nexthop *); diff --git a/usr.sbin/bgpd/parse.y b/usr.sbin/bgpd/parse.y index ef2388027f7..69e6c94d378 100644 --- a/usr.sbin/bgpd/parse.y +++ b/usr.sbin/bgpd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.50 2004/02/05 23:50:54 henning Exp $ */ +/* $OpenBSD: parse.y,v 1.51 2004/02/06 20:18:18 henning Exp $ */ /* * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -43,6 +43,7 @@ static struct network_head *netconf; static struct peer *peer_l, *peer_l_old; static struct peer *curpeer; static struct peer *curgroup; +static struct filter_head *filter_l; static FILE *fin = NULL; static int lineno = 1; static int errors = 0; @@ -64,6 +65,10 @@ struct peer *new_peer(void); struct peer *new_group(void); int add_mrtconfig(enum mrt_type, char *, time_t); int get_id(struct peer *); +int expand_rule(struct filter_rule *, struct filter_peers *, + struct filter_match *, struct filter_set *); +void print_op(enum comp_ops); +void print_rule(struct filter_rule *); TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); struct sym { @@ -80,9 +85,13 @@ int atoul(char *, u_long *); typedef struct { union { - u_int32_t number; - char *string; - struct in_addr addr; + u_int32_t number; + char *string; + struct in_addr addr; + u_int8_t u8; + struct filter_peers filter_peers; + struct filter_match filter_match; + struct filter_set filter_set; } v; int lineno; } YYSTYPE; @@ -95,11 +104,21 @@ typedef struct { %token DUMP MSG IN TABLE %token LOG UPDATES %token TCP MD5SIG PASSWORD KEY +%token ALLOW DENY MATCH +%token QUICK +%token FROM TO ANY +%token PREFIX PREFIXLEN SOURCEAS TRANSITAS +%token SET LOCALPREF MED NEXTHOP PREPEND %token ERROR -%token <v.string> STRING -%type <v.number> number optnumber yesno -%type <v.string> string -%type <v.addr> address +%token <v.string> STRING +%type <v.number> number optnumber yesno +%type <v.string> string +%type <v.addr> address +%type <v.u8> action quick direction +%type <v.filter_peers> filter_peer +%type <v.filter_match> filter_match +%type <v.filter_set> filter_set filter_set_l filter_set_opt +%type <v.u8> unaryop filter_as %% grammar : /* empty */ @@ -108,6 +127,7 @@ grammar : /* empty */ | grammar varset '\n' | grammar neighbor '\n' | grammar group '\n' + | grammar filterrule '\n' | grammar error '\n' { errors++; } ; @@ -392,6 +412,158 @@ peeropts : REMOTEAS number { } ; +filterrule : action quick direction filter_peer filter_match filter_set + { + struct filter_rule r; + + bzero(&r, sizeof(r)); + r.action = $1; + r.quick = $2; + r.dir = $3; + + if (expand_rule(&r, &$4, &$5, &$6) == -1) + YYERROR; + } + ; + +action : ALLOW { $$ = ACTION_ALLOW; } + | DENY { $$ = ACTION_DENY; } + | MATCH { $$ = ACTION_NONE; } + ; + +quick : /* empty */ { $$ = 0; } + | QUICK { $$ = 1; } + ; + +direction : FROM { $$ = DIR_IN; } + | TO { $$ = DIR_OUT; } + ; + +filter_peer : ANY { $$.peerid = $$.groupid = 0; } + | address { + struct peer *p; + + $$.groupid = $$.peerid = 0; + for (p = peer_l; p != NULL; p = p->next) + if (!memcmp(&p->conf.remote_addr.v4, + &$1, sizeof(p->conf.remote_addr.v4))) { + $$.peerid = p->conf.id; + break; + } + if ($$.peerid == 0) { + yyerror("no such peer: %s", inet_ntoa($1)); + YYERROR; + } + } + | GROUP string { + struct peer *p; + + $$.peerid = 0; + for (p = peer_l; p != NULL; p = p->next) + if (!strcmp(p->conf.group, $2)) { + $$.groupid = p->conf.groupid; + break; + } + if ($$.groupid == 0) { + yyerror("no such group: \"%s\"", $2); + YYERROR; + } + } + ; + +filter_match : /* empty */ { bzero(&$$, sizeof($$)); } + | PREFIX address '/' number { + bzero(&$$, sizeof($$)); + $$.prefix.addr.af = AF_INET; + $$.prefix.addr.v4.s_addr = $2.s_addr; + if ($4 > 32) { + yyerror("prefixlength must be <= 32"); + YYERROR; + } + $$.prefix.len = $4; + } + | PREFIXLEN unaryop number { + bzero(&$$, sizeof($$)); + if ($3 > 128) { + yyerror("prefixlen must be < 128"); + YYERROR; + } + $$.prefixlen.op = $2; + $$.prefixlen.len_min = $3; + } + | filter_as number { + bzero(&$$, sizeof($$)); + if ($2 > 0xffff) { + yyerror("AS out of range, max %u", 0xffff); + YYERROR; + } + $$.as.as = $2; + $$.as.type = $1; + } + ; + +filter_as : AS { $$ = AS_ALL; } + | SOURCEAS { $$ = AS_SOURCE; } + | TRANSITAS { $$ = AS_TRANSIT; } + ; + +filter_set : /* empty */ { + bzero(&$$, sizeof($$)); + } + | SET filter_set_opt { $$ = $2; } + | SET "{" filter_set_l "}" { $$ = $3; } + ; + +filter_set_l : filter_set_l comma filter_set_opt { + $$ = $1; + if ($$.flags & $3.flags) { + yyerror("redefining set shitz is not fluffy"); + YYERROR; + } + $$.flags |= $3.flags; + if ($3.flags & SET_LOCALPREF) + $$.localpref = $3.localpref; + if ($3.flags & SET_MED) + $$.med = $3.med; + if ($3.flags & SET_NEXTHOP) + memcpy(&$$.nexthop, &$3.nexthop, + sizeof($$.nexthop)); + if ($3.flags & SET_PREPEND) + $$.prepend = $3.prepend; + } + | filter_set_opt + ; + +filter_set_opt : LOCALPREF number { + $$.flags = SET_LOCALPREF; + $$.localpref = $2; + } + | MED number { + $$.flags = SET_MED; + $$.med = $2; + } + | NEXTHOP address { + $$.flags = SET_NEXTHOP; + $$.nexthop.s_addr = $2.s_addr; + } + | PREPEND number { + $$.flags = SET_PREPEND; + $$.prepend = $2; + } + ; + +comma : "," + | /* empty */ + ; + +unaryop : '=' { $$ = OP_EQ; } + | '!' '=' { $$ = OP_NE; } + | '<' '=' { $$ = OP_LE; } + | '<' { $$ = OP_LT; } + | '>' '=' { $$ = OP_GE; } + | '>' { $$ = OP_GT; } + ; + %% struct keywords { @@ -427,31 +599,47 @@ lookup(char *s) /* this has to be sorted always */ static const struct keywords keywords[] = { { "AS", AS}, + { "allow", ALLOW}, { "announce", ANNOUNCE}, + { "any", ANY}, + { "deny", DENY}, { "descr", DESCR}, { "dump", DUMP}, { "fib-update", FIBUPDATE}, + { "from", FROM}, { "group", GROUP}, { "holdtime", HOLDTIME}, { "in", IN}, { "key", KEY}, { "listen", LISTEN}, { "local-address", LOCALADDR}, + { "localpref", LOCALPREF}, { "log", LOG}, + { "match", MATCH}, { "max-prefix", MAXPREFIX}, { "md5sig", MD5SIG}, + { "med", MED}, { "min", YMIN}, { "msg", MSG}, { "multihop", MULTIHOP}, { "neighbor", NEIGHBOR}, { "network", NETWORK}, + { "nexthop", NEXTHOP}, { "on", ON}, { "passive", PASSIVE}, { "password", PASSWORD}, + { "prefix", PREFIX}, + { "prefixlen", PREFIXLEN}, + { "prepend-self", PREPEND}, + { "quick", QUICK}, { "remote-as", REMOTEAS}, { "router-id", ROUTERID}, + { "set", SET}, + { "source-AS", SOURCEAS}, { "table", TABLE}, { "tcp", TCP}, + { "to", TO}, + { "transit-AS", TRANSITAS}, { "updates", UPDATES}, }; const struct keywords *p; @@ -660,10 +848,12 @@ top: int parse_config(char *filename, struct bgpd_config *xconf, - struct mrt_head *xmconf, struct peer **xpeers, struct network_head* nc) + struct mrt_head *xmconf, struct peer **xpeers, struct network_head *nc, + struct filter_head *xfilter_l) { - struct sym *sym, *next; - struct peer *p, *pnext; + struct sym *sym, *next; + struct peer *p, *pnext; + struct filter_rule *r; if ((conf = calloc(1, sizeof(struct bgpd_config))) == NULL) fatal(NULL); @@ -680,6 +870,8 @@ parse_config(char *filename, struct bgpd_config *xconf, lineno = 1; errors = 0; id = 1; + filter_l = xfilter_l; + TAILQ_INIT(filter_l); conf->listen_addr.sin_len = sizeof(conf->listen_addr); conf->listen_addr.sin_family = AF_INET; @@ -712,6 +904,10 @@ parse_config(char *filename, struct bgpd_config *xconf, } } + if (xconf->opts & BGPD_OPT_VERBOSE) + TAILQ_FOREACH(r, filter_l, entries) + print_rule(r); + errors += merge_config(xconf, conf, peer_l); errors += mrt_mergeconfig(xmconf, mrtconf); *xpeers = peer_l; @@ -919,3 +1115,137 @@ get_id(struct peer *newpeer) return (-1); } + +int +expand_rule(struct filter_rule *rule, struct filter_peers *peer, + struct filter_match *match, struct filter_set *set) +{ + struct filter_rule *r; + + if ((r = calloc(1, sizeof(struct filter_rule))) == NULL) { + log_warn("expand_rule"); + return (-1); + } + + memcpy(r, rule, sizeof(struct filter_rule)); + memcpy(&r->peer, peer, sizeof(struct filter_peers)); + memcpy(&r->match, match, sizeof(struct filter_match)); + memcpy(&r->set, set, sizeof(struct filter_set)); + + TAILQ_INSERT_TAIL(filter_l, r, entries); + + return (0); +} + +void +print_op(enum comp_ops op) +{ + switch (op) { + case OP_EQ: + printf("="); + break; + case OP_NE: + printf("!="); + break; + case OP_LE: + printf("<="); + break; + case OP_LT: + printf("<"); + break; + case OP_GE: + printf(">="); + break; + case OP_GT: + printf(">"); + break; + default: + printf("?"); + break; + } +} + +void +print_rule(struct filter_rule *r) +{ + struct peer *p; + + if (r->action == ACTION_ALLOW) + printf("allow "); + else if (r->action == ACTION_DENY) + printf("deny "); + else + printf("match "); + + if (r->quick) + printf("quick "); + + if (r->dir == DIR_IN) + printf("from "); + else if (r->dir == DIR_OUT) + printf("to "); + else + printf("eeeeeeeps. "); + + if (r->peer.peerid) { + for (p = peer_l; p != NULL && p->conf.id != r->peer.peerid; + p = p->next) + ; /* nothing */ + if (p == NULL) + printf("?"); + else + printf("%s ", log_addr(&p->conf.remote_addr)); + } else if (r->peer.groupid) { + for (p = peer_l; p != NULL && + p->conf.groupid != r->peer.groupid; p = p->next) + ; /* nothing */ + if (p == NULL) + printf("group ? "); + else + printf("group %s ", p->conf.group); + } else + printf("any "); + + if (r->match.prefix.addr.af) + printf("prefix %s/%u ", log_addr(&r->match.prefix.addr), + r->match.prefix.len); + + if (r->match.prefixlen.op) { + if (r->match.prefixlen.op == OP_RANGE) + printf("prefixlen %u - %u ", r->match.prefixlen.len_min, + r->match.prefixlen.len_max); + else { + printf("prefixlen "); + print_op(r->match.prefixlen.op); + printf(" %u ", r->match.prefixlen.len_min); + } + } + + if (r->match.as.type) { + if (r->match.as.type == AS_ALL) + printf("AS %u ", r->match.as.as); + else if (r->match.as.type == AS_SOURCE) + printf("source-AS %u ", r->match.as.as); + else if (r->match.as.type == AS_TRANSIT) + printf("transit-AS %u ", r->match.as.as); + else + printf("unfluffy-AS %u ", r->match.as.as); + } + + if (r->set.flags) { + printf("set { "); + if (r->set.flags & SET_LOCALPREF) + printf("localpref %u ", r->set.localpref); + if (r->set.flags & SET_MED) + printf("med %u ", r->set.med); + if (r->set.flags & SET_NEXTHOP) + printf("nexthop %s ", inet_ntoa(r->set.nexthop)); + if (r->set.flags & SET_PREPEND) + printf("prepend-self %u ", r->set.prepend); + + + printf("}"); + } + + printf("\n"); +} diff --git a/usr.sbin/bgpd/session.h b/usr.sbin/bgpd/session.h index 50d07614001..3f19f3941d4 100644 --- a/usr.sbin/bgpd/session.h +++ b/usr.sbin/bgpd/session.h @@ -1,4 +1,4 @@ -/* $OpenBSD: session.h,v 1.24 2004/01/28 17:57:08 henning Exp $ */ +/* $OpenBSD: session.h,v 1.25 2004/02/06 20:18:18 henning Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -176,7 +176,7 @@ void log_conn_attempt(const struct peer *, struct in_addr); /* parse.y */ int parse_config(char *, struct bgpd_config *, struct mrt_head *, - struct peer **, struct network_head *); + struct peer **, struct network_head *, struct filter_head *); /* config.c */ int merge_config(struct bgpd_config *, struct bgpd_config *, |