summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
authorClaudio Jeker <claudio@cvs.openbsd.org>2004-02-19 23:07:01 +0000
committerClaudio Jeker <claudio@cvs.openbsd.org>2004-02-19 23:07:01 +0000
commit49f8c3fdbbe774bfbfa3545849045a6c406ed026 (patch)
tree7d170651e7f9d33ac46f5de5e58fdc0d76a504b3 /usr.sbin
parente45a0a2546dfa029ffe0b93d1a4bc268f2e37c42 (diff)
Add support for basic filters. Nothing optimized and it has some issues but
this is a huge step forward. OK henning@
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/bgpd/Makefile4
-rw-r--r--usr.sbin/bgpd/rde.c41
-rw-r--r--usr.sbin/bgpd/rde.h12
-rw-r--r--usr.sbin/bgpd/rde_attr.c21
-rw-r--r--usr.sbin/bgpd/rde_filter.c157
-rw-r--r--usr.sbin/bgpd/rde_rib.c7
-rw-r--r--usr.sbin/bgpd/rde_update.c32
7 files changed, 244 insertions, 30 deletions
diff --git a/usr.sbin/bgpd/Makefile b/usr.sbin/bgpd/Makefile
index 063080ab23c..4e0aecdf3d1 100644
--- a/usr.sbin/bgpd/Makefile
+++ b/usr.sbin/bgpd/Makefile
@@ -1,11 +1,11 @@
-# $OpenBSD: Makefile,v 1.16 2004/02/08 23:44:57 henning Exp $
+# $OpenBSD: Makefile,v 1.17 2004/02/19 23:07:00 claudio Exp $
.PATH: ${.CURDIR}/..
PROG= bgpd
SRCS= bgpd.c buffer.c session.c log.c parse.y config.c imsg.c \
rde.c rde_rib.c rde_decide.c rde_prefix.c mrt.c kroute.c \
- control.c pfkey.c rde_update.c rde_attr.c printconf.c
+ control.c pfkey.c rde_update.c rde_attr.c printconf.c rde_filter.c
CFLAGS+= -Wall -I${.CURDIR}
CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes
CLFAGS+= -Wmissing-declarations -Wredundant-decls
diff --git a/usr.sbin/bgpd/rde.c b/usr.sbin/bgpd/rde.c
index 6f0636d4535..7f337846c8f 100644
--- a/usr.sbin/bgpd/rde.c
+++ b/usr.sbin/bgpd/rde.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.c,v 1.82 2004/02/19 13:54:58 claudio Exp $ */
+/* $OpenBSD: rde.c,v 1.83 2004/02/19 23:07:00 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -377,6 +377,7 @@ rde_update_dispatch(struct imsg *imsg)
return (-1);
}
+ /* withdraw prefix */
while (withdrawn_len > 0) {
if ((pos = rde_update_get_prefix(p, withdrawn_len, &prefix,
&prefixlen)) == -1) {
@@ -398,6 +399,12 @@ rde_update_dispatch(struct imsg *imsg)
p += pos;
withdrawn_len -= pos;
+
+ /* input filter */
+ if (rde_filter(peer, NULL, &prefix, prefixlen,
+ DIR_IN) == ACTION_DENY)
+ continue;
+
rde_update_log("withdraw", peer, NULL, &prefix, prefixlen);
prefix_remove(peer, &prefix, prefixlen);
}
@@ -415,6 +422,7 @@ rde_update_dispatch(struct imsg *imsg)
if (attrpath_len == 0) /* 0 = no NLRI information in this message */
return (0);
+ /* parse path attributes */
attr_init(&attrs);
while (attrpath_len > 0) {
if ((pos = attr_parse(p, attrpath_len, &attrs,
@@ -422,19 +430,18 @@ rde_update_dispatch(struct imsg *imsg)
emsg = attr_error(p, attrpath_len, &attrs,
&subtype, &size);
rde_update_err(peer, ERR_UPDATE, subtype, emsg, size);
- aspath_destroy(attrs.aspath);
- attr_optfree(&attrs);
+ attr_free(&attrs);
return (-1);
}
p += pos;
attrpath_len -= pos;
}
+ /* check for missing but necessary attributes */
if ((subtype = attr_missing(&attrs, peer->conf.ebgp)) != 0) {
rde_update_err(peer, ERR_UPDATE, ERR_UPD_MISSNG_WK_ATTR,
&subtype, sizeof(u_int8_t));
- aspath_destroy(attrs.aspath);
- attr_optfree(&attrs);
+ attr_free(&attrs);
return (-1);
}
@@ -449,13 +456,13 @@ rde_update_dispatch(struct imsg *imsg)
return (0);
}
+ /* parse nlri prefix */
while (nlri_len > 0) {
if ((pos = rde_update_get_prefix(p, nlri_len, &prefix,
&prefixlen)) == -1) {
rde_update_err(peer, ERR_UPDATE, ERR_UPD_NETWORK,
NULL, 0);
- aspath_destroy(attrs.aspath);
- attr_optfree(&attrs);
+ attr_free(&attrs);
return (-1);
}
if (prefixlen > 32) {
@@ -468,22 +475,32 @@ rde_update_dispatch(struct imsg *imsg)
p += pos;
nlri_len -= pos;
- rde_update_log("update", peer, &attrs, &prefix, prefixlen);
+
+ /* input filter */
+ /*
+ * XXX we need to copy attrs befor calling the filter
+ * but that stinks, because we copy it again in path_update.
+ */
+ if (rde_filter(peer, &attrs, &prefix, prefixlen,
+ DIR_IN) == ACTION_DENY)
+ continue;
+
+ /* max prefix checker */
if (peer->conf.max_prefix &&
peer->prefix_cnt >= peer->conf.max_prefix) {
log_peer_warnx(&peer->conf, "prefix limit reached");
rde_update_err(peer, ERR_CEASE, ERR_CEASE_MAX_PREFIX,
NULL, 0);
- aspath_destroy(attrs.aspath);
- attr_optfree(&attrs);
+ attr_free(&attrs);
return (-1);
}
+
+ rde_update_log("update", peer, &attrs, &prefix, prefixlen);
path_update(peer, &attrs, &prefix, prefixlen);
}
/* need to free allocated attribute memory that is no longer used */
- aspath_destroy(attrs.aspath);
- attr_optfree(&attrs);
+ attr_free(&attrs);
return (0);
}
diff --git a/usr.sbin/bgpd/rde.h b/usr.sbin/bgpd/rde.h
index b1428b28a1f..eb12f60dae2 100644
--- a/usr.sbin/bgpd/rde.h
+++ b/usr.sbin/bgpd/rde.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.h,v 1.28 2004/02/18 23:18:16 claudio Exp $ */
+/* $OpenBSD: rde.h,v 1.29 2004/02/19 23:07:00 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> and
@@ -82,9 +82,8 @@ struct rde_peer {
struct aspath_hdr {
u_int16_t len; /* total length of aspath
in octets */
- u_int16_t as_cnt; /* total number of AS's */
- /* probably we should switch these to int or something similar */
- /* char *str; string representation of aspath for regex search. */
+ u_int16_t as_cnt; /* number of AS's in data */
+ u_int16_t prepend;
};
struct aspath {
@@ -220,6 +219,7 @@ u_char *attr_error(u_char *, u_int16_t, struct attr_flags *,
u_int8_t attr_missing(struct attr_flags *, int);
int attr_compare(struct attr_flags *, struct attr_flags *);
void attr_copy(struct attr_flags *, struct attr_flags *);
+void attr_free(struct attr_flags *);
int attr_write(void *, u_int16_t, u_int8_t, u_int8_t, void *,
u_int16_t);
int attr_optadd(struct attr_flags *, u_int8_t, u_int8_t,
@@ -291,5 +291,9 @@ void pt_remove(struct pt_entry *);
struct pt_entry *pt_lookup(struct bgpd_addr *);
void pt_dump(void (*)(struct pt_entry *, void *), void *);
+/* rde_filter.c */
+enum filter_actions rde_filter(struct rde_peer *, struct attr_flags *,
+ struct bgpd_addr *, u_int8_t, enum directions);
+void rde_apply_set(struct attr_flags *, struct filter_set *);
#endif /* __RDE_H__ */
diff --git a/usr.sbin/bgpd/rde_attr.c b/usr.sbin/bgpd/rde_attr.c
index e4185f45923..98279164539 100644
--- a/usr.sbin/bgpd/rde_attr.c
+++ b/usr.sbin/bgpd/rde_attr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde_attr.c,v 1.11 2004/02/19 13:54:58 claudio Exp $ */
+/* $OpenBSD: rde_attr.c,v 1.12 2004/02/19 23:07:00 claudio Exp $ */
/*
* Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
@@ -377,6 +377,18 @@ attr_copy(struct attr_flags *t, struct attr_flags *s)
attr_optadd(t, os->flags, os->type, os->data, os->len);
}
+void
+attr_free(struct attr_flags *a)
+{
+ /*
+ * free the aspath and all optional path attributes
+ * but not the attr_flags struct.
+ */
+ aspath_destroy(a->aspath);
+ a->aspath = NULL;
+ attr_optfree(a);
+}
+
int
attr_write(void *p, u_int16_t p_len, u_int8_t flags, u_int8_t type,
void *data, u_int16_t data_len)
@@ -534,19 +546,22 @@ aspath_create(void *data, u_int16_t len)
memcpy(aspath->data, data, len);
aspath->hdr.as_cnt = aspath_count(aspath);
+ aspath->hdr.prepend = 0;
return aspath;
}
int
aspath_write(void *p, u_int16_t len, struct aspath *aspath, u_int16_t myAS,
- int prepend)
+ int ebgp)
{
u_char *b = p;
- int tot_len, as_len, size, wpos = 0;
+ int tot_len, as_len, prepend, size, wpos = 0;
u_int16_t tmp;
u_int8_t type, attr_flag = ATTR_WELL_KNOWN;
+ prepend = aspath->hdr.prepend + (ebgp ? 1 : 0);
+
if (prepend > 255)
/* lunatic prepends need to be blocked in the parser */
return (-1);
diff --git a/usr.sbin/bgpd/rde_filter.c b/usr.sbin/bgpd/rde_filter.c
new file mode 100644
index 00000000000..b6e10347188
--- /dev/null
+++ b/usr.sbin/bgpd/rde_filter.c
@@ -0,0 +1,157 @@
+/* $OpenBSD: rde_filter.c,v 1.1 2004/02/19 23:07:00 claudio Exp $ */
+
+/*
+ * Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include "bgpd.h"
+#include "rde.h"
+
+extern struct filter_head *rules_l; /* XXX ugly */
+
+int rde_filter_match(struct filter_rule *, struct attr_flags *,
+ struct bgpd_addr *, u_int8_t);
+
+enum filter_actions
+rde_filter(struct rde_peer *peer, struct attr_flags *attrs,
+ struct bgpd_addr *prefix, u_int8_t prefixlen, enum directions dir)
+{
+ struct filter_rule *f;
+ enum filter_actions action = ACTION_ALLOW; /* default allow */
+
+ TAILQ_FOREACH(f, rules_l, entries) {
+ if (dir != f->dir)
+ continue;
+ if (f->peer.groupid != 0 &&
+ f->peer.groupid != peer->conf.groupid)
+ continue;
+ if (f->peer.peerid != 0 &&
+ f->peer.peerid != peer->conf.id)
+ continue;
+ if (rde_filter_match(f, attrs, prefix, prefixlen)) {
+ rde_apply_set(attrs, &f->set);
+ if (f->action != ACTION_NONE)
+ action = f->action;
+ if (f->quick)
+ return (action);
+ }
+ }
+ return (action);
+}
+
+void
+rde_apply_set(struct attr_flags *attrs, struct filter_set *set)
+{
+ if (attrs == NULL)
+ return;
+
+ if (set->flags & SET_LOCALPREF)
+ attrs->lpref = set->localpref;
+ if (set->flags & SET_MED)
+ attrs->med = set->med;
+ if (set->flags & SET_NEXTHOP)
+ /* TODO switch attr->nexthop to struct in_addr */
+ attrs->nexthop = set->nexthop.s_addr;
+ if (set->flags & SET_PREPEND) {
+ /*
+ * The acctual prepending is done afterwards because
+ * This could overflow but somebody that uses that many
+ * prepends is loony and needs professional help.
+ */
+ attrs->aspath->hdr.prepend += set->prepend;
+ attrs->aspath->hdr.as_cnt += set->prepend;
+ }
+}
+
+int
+rde_filter_match(struct filter_rule *f, struct attr_flags *attrs,
+ struct bgpd_addr *prefix, u_int8_t plen)
+{
+ in_addr_t mask;
+
+ if (attrs != NULL && f->match.as.type != AS_NONE)
+ if (aspath_match(attrs->aspath, f->match.as.type,
+ f->match.as.as) == 0)
+ return (0);
+
+ if (f->match.prefix.addr.af != 0 &&
+ f->match.prefix.addr.af == prefix->af) {
+ switch (f->match.prefix.addr.af) {
+ case AF_INET:
+ mask = 0xffffffff << (32 - f->match.prefix.len);
+ mask = htonl(mask);
+ if ((prefix->v4.s_addr & mask) !=
+ (f->match.prefix.addr.v4.s_addr & mask))
+ return (0);
+ break;
+ default:
+ fatalx("rde_filter_match: unsupported address family");
+ }
+
+ /* 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_EQ:
+ return (plen == f->match.prefixlen.len_min);
+ 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 */
+ /*
+ * XXX IPv4 and IPv6 will cause trouble here.
+ * XXX need to store the af.
+ */
+ switch (f->match.prefixlen.op) {
+ case OP_NONE:
+ fatalx("internal filter bug");
+ case OP_RANGE:
+ 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);
+ 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 */
+ }
+
+ /* matched somewhen or is anymatch rule */
+ return (1);
+}
diff --git a/usr.sbin/bgpd/rde_rib.c b/usr.sbin/bgpd/rde_rib.c
index 3c2948dc2a6..31268f03876 100644
--- a/usr.sbin/bgpd/rde_rib.c
+++ b/usr.sbin/bgpd/rde_rib.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde_rib.c,v 1.34 2004/02/19 13:54:58 claudio Exp $ */
+/* $OpenBSD: rde_rib.c,v 1.35 2004/02/19 23:07:00 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org>
@@ -250,10 +250,7 @@ path_unlink(struct rde_aspath *asp)
asp->peer = NULL;
asp->nexthop = NULL;
- /* free the aspath and all other path attributes */
- aspath_destroy(asp->flags.aspath);
- asp->flags.aspath = NULL;
- attr_optfree(&asp->flags);
+ attr_free(&asp->flags);
}
/* alloc and initialize new entry. May not fail. */
diff --git a/usr.sbin/bgpd/rde_update.c b/usr.sbin/bgpd/rde_update.c
index 7af1146a6ac..828e9ec2b5f 100644
--- a/usr.sbin/bgpd/rde_update.c
+++ b/usr.sbin/bgpd/rde_update.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde_update.c,v 1.5 2004/02/18 23:25:17 claudio Exp $ */
+/* $OpenBSD: rde_update.c,v 1.6 2004/02/19 23:07:00 claudio Exp $ */
/*
* Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
@@ -201,6 +201,7 @@ up_generate_updates(struct rde_peer *peer,
{
struct update_attr *a;
struct update_prefix *p;
+ struct attr_flags attrs;
ENSURE(peer->state == PEER_UP);
/*
@@ -246,6 +247,17 @@ up_generate_updates(struct rde_peer *peer,
break;
}
+ /* copy attributes for output filter */
+ attr_copy(&attrs, &old->aspath->flags);
+
+ if (rde_filter(peer, &attrs, &old->prefix->prefix,
+ old->prefix->prefixlen, DIR_OUT) == ACTION_DENY) {
+ attr_free(&attrs);
+ return;
+ }
+
+ attr_free(&attrs);
+
/* withdraw prefix */
p = calloc(1, sizeof(struct update_prefix));
if (p == NULL)
@@ -290,6 +302,15 @@ up_generate_updates(struct rde_peer *peer,
break;
}
+ /* copy attributes for output filter */
+ attr_copy(&attrs, &new->aspath->flags);
+
+ if (rde_filter(peer, &attrs, &new->prefix->prefix,
+ new->prefix->prefixlen, DIR_OUT) == ACTION_DENY) {
+ attr_free(&attrs);
+ return;
+ }
+
/* generate update */
p = calloc(1, sizeof(struct update_prefix));
if (p == NULL)
@@ -299,7 +320,7 @@ up_generate_updates(struct rde_peer *peer,
if (a == NULL)
fatal("up_queue_update");
- if (up_generate_attr(peer, a, &new->aspath->flags,
+ if (up_generate_attr(peer, a, &attrs,
new->aspath->nexthop) == -1)
log_warnx("generation of bgp path attributes failed");
@@ -307,10 +328,13 @@ up_generate_updates(struct rde_peer *peer,
* use aspath_hash as attr_hash, this may be unoptimal
* but currently I don't care.
*/
- a->attr_hash = aspath_hash(new->aspath->flags.aspath);
+ a->attr_hash = aspath_hash(attrs.aspath);
p->prefix = new->prefix->prefix;
p->prefixlen = new->prefix->prefixlen;
+ /* no longer needed */
+ attr_free(&attrs);
+
if (up_add(peer, p, a) == -1)
log_warnx("queuing update failed.");
}
@@ -336,7 +360,7 @@ up_generate_attr(struct rde_peer *peer, struct update_attr *upa,
/* aspath */
if ((r = aspath_write(up_attr_buf + wlen, len, a->aspath,
- rde_local_as(), peer->conf.ebgp == 0 ? 0 : 1)) == -1)
+ rde_local_as(), peer->conf.ebgp)) == -1)
return (-1);
wlen += r; len -= r;