summaryrefslogtreecommitdiff
path: root/usr.sbin/bgpd/rde_attr.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/bgpd/rde_attr.c')
-rw-r--r--usr.sbin/bgpd/rde_attr.c568
1 files changed, 20 insertions, 548 deletions
diff --git a/usr.sbin/bgpd/rde_attr.c b/usr.sbin/bgpd/rde_attr.c
index cbb7e925c35..fe1a6c1c492 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.41 2004/08/05 20:56:12 claudio Exp $ */
+/* $OpenBSD: rde_attr.c,v 1.42 2004/08/06 12:04:08 claudio Exp $ */
/*
* Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
@@ -29,457 +29,6 @@
#include "rde.h"
/* attribute specific functions */
-#define UPD_READ(t, p, plen, n) \
- do { \
- memcpy(t, p, n); \
- p += n; \
- plen += n; \
- } while (0)
-
-#define CHECK_FLAGS(s, t, m) \
- (((s) & ~(ATTR_EXTLEN | (m))) == (t))
-
-#define F_ATTR_ORIGIN 0x01
-#define F_ATTR_ASPATH 0x02
-#define F_ATTR_NEXTHOP 0x04
-#define F_ATTR_LOCALPREF 0x08
-#define F_ATTR_MED 0x10
-#define F_ATTR_MP_REACH 0x20
-#define F_ATTR_MP_UNREACH 0x40
-
-#define WFLAG(s, t) \
- do { \
- if ((s) & (t)) \
- return (-1); \
- (s) |= (t); \
- } while (0)
-void
-attr_init(struct attr_flags *a)
-{
- bzero(a, sizeof(struct attr_flags));
- a->origin = ORIGIN_INCOMPLETE;
- a->lpref = DEFAULT_LPREF;
- TAILQ_INIT(&a->others);
-}
-
-int
-attr_parse(u_char *p, u_int16_t len, struct attr_flags *a, int ebgp,
- enum enforce_as enforce_as, u_int16_t remote_as)
-{
- u_int32_t tmp32;
- u_int16_t attr_len;
- u_int16_t plen = 0;
- u_int8_t flags;
- u_int8_t type;
- u_int8_t tmp8;
-
- if (len < 3)
- return (-1);
-
- UPD_READ(&flags, p, plen, 1);
- UPD_READ(&type, p, plen, 1);
-
- if (flags & ATTR_EXTLEN) {
- if (len - plen < 2)
- return (-1);
- UPD_READ(&attr_len, p, plen, 2);
- attr_len = ntohs(attr_len);
- } else {
- UPD_READ(&tmp8, p, plen, 1);
- attr_len = tmp8;
- }
-
- if (len - plen < attr_len)
- return (-1);
-
- switch (type) {
- case ATTR_UNDEF:
- /* error! */
- return (-1);
- case ATTR_ORIGIN:
- if (attr_len != 1)
- return (-1);
- if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0))
- return (-1);
- UPD_READ(&a->origin, p, plen, 1);
- if (a->origin > ORIGIN_INCOMPLETE)
- return (-1);
- WFLAG(a->wflags, F_ATTR_ORIGIN);
- break;
- case ATTR_ASPATH:
- if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0))
- return (-1);
- if (aspath_verify(p, attr_len) != 0)
- return (-1);
- WFLAG(a->wflags, F_ATTR_ASPATH);
- a->aspath = aspath_get(p, attr_len);
- if (enforce_as == ENFORCE_AS_ON &&
- remote_as != aspath_neighbor(a->aspath))
- return (-1);
-
- plen += attr_len;
- break;
- case ATTR_NEXTHOP:
- if (attr_len != 4)
- return (-1);
- if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0))
- return (-1);
- WFLAG(a->wflags, F_ATTR_NEXTHOP);
- UPD_READ(&a->nexthop, p, plen, 4); /* network byte order */
- /*
- * Check if the nexthop is a valid IP address. We consider
- * multicast and experimental addresses as invalid.
- */
- tmp32 = ntohl(a->nexthop.s_addr);
- if (IN_MULTICAST(tmp32) || IN_BADCLASS(tmp32))
- return (-1);
- break;
- case ATTR_MED:
- if (attr_len != 4)
- return (-1);
- if (!CHECK_FLAGS(flags, ATTR_OPTIONAL, 0))
- return (-1);
- WFLAG(a->wflags, F_ATTR_MED);
- UPD_READ(&tmp32, p, plen, 4);
- a->med = ntohl(tmp32);
- break;
- case ATTR_LOCALPREF:
- if (attr_len != 4)
- return (-1);
- if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0))
- return (-1);
- if (ebgp) {
- /* ignore local-pref attr for non ibgp peers */
- a->lpref = 0; /* set a default value ... */
- plen += 4; /* and ignore the real value */
- break;
- }
- WFLAG(a->wflags, F_ATTR_LOCALPREF);
- UPD_READ(&tmp32, p, plen, 4);
- a->lpref = ntohl(tmp32);
- break;
- case ATTR_ATOMIC_AGGREGATE:
- if (attr_len != 0)
- return (-1);
- if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0))
- return (-1);
- goto optattr;
- case ATTR_AGGREGATOR:
- if (attr_len != 6)
- return (-1);
- if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, 0))
- return (-1);
- goto optattr;
- case ATTR_COMMUNITIES:
- if ((attr_len & 0x3) != 0)
- return (-1);
- if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE,
- ATTR_PARTIAL))
- return (-1);
- goto optattr;
- case ATTR_ORIGINATOR_ID:
- if (attr_len != 4)
- return (-1);
- if (!CHECK_FLAGS(flags, ATTR_OPTIONAL, 0))
- return (-1);
- goto optattr;
- case ATTR_CLUSTER_LIST:
- if ((attr_len & 0x3) != 0)
- return (-1);
- if (!CHECK_FLAGS(flags, ATTR_OPTIONAL, 0))
- return (-1);
- goto optattr;
- case ATTR_MP_REACH_NLRI:
- if (attr_len < 4)
- return (-1);
- if (!CHECK_FLAGS(flags, ATTR_OPTIONAL, 0))
- return (-1);
- /* the actually validity is checked in rde_update_dispatch() */
- WFLAG(a->wflags, F_ATTR_MP_REACH);
- goto optattr;
- case ATTR_MP_UNREACH_NLRI:
- if (attr_len < 3)
- return (-1);
- if (!CHECK_FLAGS(flags, ATTR_OPTIONAL, 0))
- return (-1);
- /* the actually validity is checked in rde_update_dispatch() */
- WFLAG(a->wflags, F_ATTR_MP_UNREACH);
- goto optattr;
- default:
-optattr:
- if (attr_optadd(a, flags, type, p, attr_len) == -1)
- return (-1);
- plen += attr_len;
- break;
- }
-
- return (plen);
-}
-
-u_char *
-attr_error(u_char *p, u_int16_t len, struct attr_flags *attr,
- u_int8_t *suberr, u_int16_t *size)
-{
- struct attr *a;
- u_char *op;
- u_int16_t attr_len;
- u_int16_t plen = 0;
- u_int8_t flags;
- u_int8_t type;
- u_int8_t tmp8;
-
- *suberr = ERR_UPD_ATTRLEN;
- *size = len;
- op = p;
- if (len < 3)
- return (op);
-
- UPD_READ(&flags, p, plen, 1);
- UPD_READ(&type, p, plen, 1);
-
- if (flags & ATTR_EXTLEN) {
- if (len - plen < 2)
- return (op);
- UPD_READ(&attr_len, p, plen, 2);
- } else {
- UPD_READ(&tmp8, p, plen, 1);
- attr_len = tmp8;
- }
-
- if (len - plen < attr_len)
- return (op);
- *size = attr_len;
-
- switch (type) {
- case ATTR_UNDEF:
- /* error! */
- *suberr = ERR_UPD_UNSPECIFIC;
- *size = 0;
- return (NULL);
- case ATTR_ORIGIN:
- if (attr_len != 1)
- return (op);
- if (attr->wflags & F_ATTR_ORIGIN) {
- *suberr = ERR_UPD_ATTRLIST;
- *size = 0;
- return (NULL);
- }
- UPD_READ(&tmp8, p, plen, 1);
- if (tmp8 > ORIGIN_INCOMPLETE) {
- *suberr = ERR_UPD_ORIGIN;
- return (op);
- }
- break;
- case ATTR_ASPATH:
- if (attr->wflags & F_ATTR_ASPATH) {
- *suberr = ERR_UPD_ATTRLIST;
- *size = 0;
- return (NULL);
- }
- if (CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0)) {
- /* malformed aspath detected by exclusion method */
- *size = 0;
- *suberr = ERR_UPD_ASPATH;
- return (NULL);
- }
- break;
- case ATTR_NEXTHOP:
- if (attr_len != 4)
- return (op);
- if (attr->wflags & F_ATTR_NEXTHOP) {
- *suberr = ERR_UPD_ATTRLIST;
- *size = 0;
- return (NULL);
- }
- if (CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0)) {
- /* malformed nexthop detected by exclusion method */
- *suberr = ERR_UPD_NETWORK;
- return (op);
- }
- break;
- case ATTR_MED:
- if (attr_len != 4)
- return (op);
- if (attr->wflags & F_ATTR_MED) {
- *suberr = ERR_UPD_ATTRLIST;
- *size = 0;
- return (NULL);
- }
- break;
- case ATTR_LOCALPREF:
- if (attr_len != 4)
- return (op);
- if (attr->wflags & F_ATTR_LOCALPREF) {
- *suberr = ERR_UPD_ATTRLIST;
- *size = 0;
- return (NULL);
- }
- break;
- case ATTR_ATOMIC_AGGREGATE:
- if (attr_len != 0)
- return (op);
- break;
- case ATTR_AGGREGATOR:
- if (attr_len != 6)
- return (op);
- break;
- case ATTR_COMMUNITIES:
- if ((attr_len & 0x3) != 0)
- return (op);
- goto optattr;
- case ATTR_ORIGINATOR_ID:
- if (attr_len != 4)
- return (op);
- goto optattr;
- case ATTR_CLUSTER_LIST:
- if ((attr_len & 0x3) != 0)
- return (op);
- goto optattr;
- case ATTR_MP_REACH_NLRI:
- if (attr_len < 4)
- return (op);
- goto optattr;
- case ATTR_MP_UNREACH_NLRI:
- if (attr_len < 3)
- return (op);
- goto optattr;
- default:
-optattr:
- if ((flags & ATTR_OPTIONAL) == 0) {
- *suberr = ERR_UPD_UNKNWN_WK_ATTR;
- return (op);
- }
- TAILQ_FOREACH(a, &attr->others, entry)
- if (type == a->type) {
- *size = 0;
- *suberr = ERR_UPD_ATTRLIST;
- return (NULL);
- }
- *suberr = ERR_UPD_OPTATTR;
- return (op);
- }
- /* can only be a attribute flag error */
- *suberr = ERR_UPD_ATTRFLAGS;
- return (op);
-}
-#undef UPD_READ
-#undef WFLAG
-
-u_int8_t
-attr_missing(struct attr_flags *a, int ebgp)
-{
- if ((a->wflags & F_ATTR_ORIGIN) == 0)
- return (ATTR_ORIGIN);
- if ((a->wflags & F_ATTR_ASPATH) == 0)
- return (ATTR_ASPATH);
- if ((a->wflags & F_ATTR_MP_REACH) == 0 &&
- (a->wflags & F_ATTR_NEXTHOP) == 0)
- return (ATTR_NEXTHOP);
- if (!ebgp)
- if ((a->wflags & F_ATTR_LOCALPREF) == 0)
- return (ATTR_LOCALPREF);
- return (0);
-}
-
-int
-attr_compare(struct attr_flags *a, struct attr_flags *b)
-{
- struct attr *oa, *ob;
- int r;
-
- if (a->origin > b->origin)
- return (1);
- if (a->origin < b->origin)
- return (-1);
- if ((a->wflags & F_ATTR_NEXTHOP) && (b->wflags & F_ATTR_NEXTHOP) == 0)
- return (1);
- if ((b->wflags & F_ATTR_NEXTHOP) && (a->wflags & F_ATTR_NEXTHOP) == 0)
- return (-1);
- if (a->nexthop.s_addr > b->nexthop.s_addr)
- return (1);
- if (a->nexthop.s_addr < b->nexthop.s_addr)
- return (-1);
- if (a->med > b->med)
- return (1);
- if (a->med < b->med)
- return (-1);
- if (a->lpref > b->lpref)
- return (1);
- if (a->lpref < b->lpref)
- return (-1);
- r = strcmp(a->pftable, b->pftable);
- if (r == 0)
- r = aspath_compare(a->aspath, b->aspath);
- if (r > 0)
- return (1);
- if (r < 0)
- return (-1);
-
- for (oa = TAILQ_FIRST(&a->others), ob = TAILQ_FIRST(&b->others);
- oa != NULL && ob != NULL;
- oa = TAILQ_NEXT(oa, entry), ob = TAILQ_NEXT(ob, entry)) {
- if (oa->type > ob->type)
- return (1);
- if (oa->type < ob->type)
- return (-1);
- if (oa->len > ob->len)
- return (1);
- if (oa->len < ob->len)
- return (-1);
- r = memcmp(oa->data, ob->data, oa->len);
- if (r > 0)
- return (1);
- if (r < 0)
- return (-1);
- }
- if (oa != NULL)
- return (1);
- if (ob != NULL)
- return (-1);
- return (0);
-}
-
-void
-attr_copy(struct attr_flags *t, struct attr_flags *s)
-{
- struct attr *os;
- /*
- * first copy the full struct, then replace the path and tags with
- * a own copy.
- */
- memcpy(t, s, sizeof(struct attr_flags));
- t->aspath = aspath_get(s->aspath->data, s->aspath->len);
- TAILQ_INIT(&t->others);
- TAILQ_FOREACH(os, &s->others, entry)
- attr_optadd(t, os->flags, os->type, os->data, os->len);
-}
-
-void
-attr_move(struct attr_flags *t, struct attr_flags *s)
-{
- struct attr *os;
- /*
- * first copy the full struct, then move the optional attributes.
- */
- memcpy(t, s, sizeof(struct attr_flags));
- TAILQ_INIT(&t->others);
- while ((os = TAILQ_FIRST(&s->others)) != NULL) {
- TAILQ_REMOVE(&s->others, os, entry);
- TAILQ_INSERT_TAIL(&t->others, os, entry);
- }
-}
-
-void
-attr_free(struct attr_flags *a)
-{
- /*
- * free the aspath and all optional path attributes
- * but not the attr_flags struct.
- */
- aspath_put(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,
@@ -513,7 +62,7 @@ attr_write(void *p, u_int16_t p_len, u_int8_t flags, u_int8_t type,
}
int
-attr_optadd(struct attr_flags *attr, u_int8_t flags, u_int8_t type,
+attr_optadd(struct rde_aspath *asp, u_int8_t flags, u_int8_t type,
void *data, u_int16_t len)
{
struct attr *a, *p;
@@ -522,6 +71,7 @@ attr_optadd(struct attr_flags *attr, u_int8_t flags, u_int8_t type,
a = calloc(1, sizeof(struct attr));
if (a == NULL)
fatal("attr_optadd");
+
a->flags = flags;
a->type = type;
a->len = len;
@@ -529,12 +79,13 @@ attr_optadd(struct attr_flags *attr, u_int8_t flags, u_int8_t type,
a->data = malloc(len);
if (a->data == NULL)
fatal("attr_optadd");
+
memcpy(a->data, data, len);
} else
a->data = NULL;
/* keep a sorted list */
- TAILQ_FOREACH_REVERSE(p, &attr->others, attr_list, entry) {
+ TAILQ_FOREACH_REVERSE(p, &asp->others, attr_list, entry) {
if (type == p->type) {
/* attribute only once allowed */
free(a->data);
@@ -542,20 +93,20 @@ attr_optadd(struct attr_flags *attr, u_int8_t flags, u_int8_t type,
return (-1);
}
if (type > p->type) {
- TAILQ_INSERT_AFTER(&attr->others, p, a, entry);
+ TAILQ_INSERT_AFTER(&asp->others, p, a, entry);
return (0);
}
}
- TAILQ_INSERT_HEAD(&attr->others, a, entry);
+ TAILQ_INSERT_HEAD(&asp->others, a, entry);
return (0);
}
struct attr *
-attr_optget(const struct attr_flags *attr, u_int8_t type)
+attr_optget(const struct rde_aspath *asp, u_int8_t type)
{
struct attr *a;
- TAILQ_FOREACH(a, &attr->others, entry) {
+ TAILQ_FOREACH(a, &asp->others, entry) {
if (type == a->type)
return (a);
if (type < a->type)
@@ -566,103 +117,24 @@ attr_optget(const struct attr_flags *attr, u_int8_t type)
}
void
-attr_optfree(struct attr_flags *attr)
+attr_optcopy(struct rde_aspath *t, struct rde_aspath *s)
{
- struct attr *a;
-
- while ((a = TAILQ_FIRST(&attr->others)) != NULL) {
- TAILQ_REMOVE(&attr->others, a, entry);
- free(a->data);
- free(a);
- }
-}
+ struct attr *os;
-int
-attr_ismp(const struct attr_flags *attr)
-{
- return (attr->wflags & F_ATTR_MP_REACH);
+ TAILQ_FOREACH(os, &s->others, entry)
+ attr_optadd(t, os->flags, os->type, os->data, os->len);
}
-int
-attr_mp_nexthop_check(u_char *data, u_int16_t len, u_int16_t afi)
+void
+attr_optfree(struct rde_aspath *asp)
{
- u_int8_t nh_len;
-
- if (len == 0)
- return (-1);
-
- nh_len = *data++;
- len--;
-
- if (nh_len > len)
- return (-1);
-
- switch (afi) {
- case AFI_IPv6:
- if (nh_len != 16 && nh_len != 32) {
- log_warnx("bad multiprotocol nexthop, bad size");
- return (-1);
- }
- return (nh_len + 1);
- default:
- log_warnx("bad multiprotocol nexthop, bad AF");
- break;
- }
-
- return (-1);
-}
+ struct attr *a;
-/*
- * this function may only be called after attr_mp_nexthop_check()
- */
-struct bgpd_addr *
-attr_mp_nexthop(const struct attr_flags *attrs)
-{
- static struct bgpd_addr address;
- struct attr *mpattr;
- u_int8_t *p;
- u_int16_t afi;
- u_int8_t nhlen;
-
- if ((mpattr = attr_optget(attrs, ATTR_MP_REACH_NLRI)) == NULL) {
- log_warnx("attr_mp_nexthop: no MP_REACH_NLRI available");
- return (NULL);
- }
- p = mpattr->data;
- if (mpattr->len < 4)
- fatalx("Who fucked up the code? King Bula?");
-
- memcpy(&afi, p, 2);
- afi = ntohs(afi);
- p += 3;
-
- nhlen = *p++;
- if (nhlen > mpattr->len)
- fatalx("Who fucked up the code? King Bula?");
-
- bzero(&address, sizeof(address));
- switch (afi) {
- case AFI_IPv6:
- address.af = AF_INET6;
- if (nhlen == 16) {
- memcpy(&address.v6.s6_addr, p, 16);
- return (&address);
- }
- if (nhlen == 32) {
- /*
- * XXX acctually the link lokal address should be used
- * for kroute and the global one updates.
- */
- memcpy(&address.v6.s6_addr, p, 16);
- return (&address);
- }
- fatalx("Who fucked up the code? King Bula?");
- default:
- fatalx("attr_mp_nexthop: unsupported AF");
+ while ((a = TAILQ_FIRST(&asp->others)) != NULL) {
+ TAILQ_REMOVE(&asp->others, a, entry);
+ free(a->data);
+ free(a);
}
-
- /* NOTREACHED */
- return (NULL);
}
/* aspath specific functions */