diff options
Diffstat (limited to 'usr.sbin/bgpd/rde_attr.c')
-rw-r--r-- | usr.sbin/bgpd/rde_attr.c | 568 |
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 */ |