summaryrefslogtreecommitdiff
path: root/usr.sbin/bgpd
diff options
context:
space:
mode:
authorHenning Brauer <henning@cvs.openbsd.org>2004-02-06 20:18:19 +0000
committerHenning Brauer <henning@cvs.openbsd.org>2004-02-06 20:18:19 +0000
commit32df521252cd6f82edd80623ba50da1fda799d58 (patch)
tree31d5ea23b568c3c1c0ef8350970bc5c2b55ed26b /usr.sbin/bgpd
parentcbf513969d15cf3c78d5c5ea656aabd58d7a19fc (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.c26
-rw-r--r--usr.sbin/bgpd/bgpd.h87
-rw-r--r--usr.sbin/bgpd/parse.y352
-rw-r--r--usr.sbin/bgpd/session.h4
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 *,