summaryrefslogtreecommitdiff
path: root/net/openbgpd/files/patch-bgpd_util.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/openbgpd/files/patch-bgpd_util.c')
-rw-r--r--net/openbgpd/files/patch-bgpd_util.c440
1 files changed, 440 insertions, 0 deletions
diff --git a/net/openbgpd/files/patch-bgpd_util.c b/net/openbgpd/files/patch-bgpd_util.c
new file mode 100644
index 000000000000..54e74ec9805f
--- /dev/null
+++ b/net/openbgpd/files/patch-bgpd_util.c
@@ -0,0 +1,440 @@
+Index: bgpd/util.c
+===================================================================
+RCS file: /home/cvs/private/hrs/openbgpd/bgpd/util.c,v
+retrieving revision 1.1.1.6
+retrieving revision 1.7
+diff -u -p -r1.1.1.6 -r1.7
+--- bgpd/util.c 14 Feb 2010 20:19:57 -0000 1.1.1.6
++++ bgpd/util.c 13 Oct 2012 18:36:00 -0000 1.7
+@@ -1,4 +1,4 @@
+-/* $OpenBSD: util.c,v 1.6 2009/06/12 16:42:53 claudio Exp $ */
++/* $OpenBSD: util.c,v 1.11 2010/03/29 09:04:43 claudio Exp $ */
+
+ /*
+ * Copyright (c) 2006 Claudio Jeker <claudio@openbsd.org>
+@@ -18,6 +18,9 @@
+ */
+ #include <sys/types.h>
+ #include <sys/socket.h>
++#if defined(__FreeBSD__) /* sys/limits.h */
++#include <sys/limits.h>
++#endif /* defined(__FreeBSD__) */
+ #include <netinet/in.h>
+ #include <arpa/inet.h>
+ #include <netdb.h>
+@@ -28,15 +31,30 @@
+ #include "bgpd.h"
+ #include "rde.h"
+
++const char *aspath_delim(u_int8_t, int);
++
+ const char *
+ log_addr(const struct bgpd_addr *addr)
+ {
+ static char buf[48];
++ char tbuf[16];
+
+- if (inet_ntop(addr->af, &addr->ba, buf, sizeof(buf)) == NULL)
+- return ("?");
+- else
++ switch (addr->aid) {
++ case AID_INET:
++ case AID_INET6:
++ if (inet_ntop(aid2af(addr->aid), &addr->ba, buf,
++ sizeof(buf)) == NULL)
++ return ("?");
+ return (buf);
++ case AID_VPN_IPv4:
++ if (inet_ntop(AF_INET, &addr->vpn4.addr, tbuf,
++ sizeof(tbuf)) == NULL)
++ return ("?");
++ snprintf(buf, sizeof(buf), "%s %s", log_rd(addr->vpn4.rd),
++ tbuf);
++ return (buf);
++ }
++ return ("???");
+ }
+
+ const char *
+@@ -90,6 +108,96 @@ log_as(u_int32_t as)
+ return (buf);
+ }
+
++const char *
++log_rd(u_int64_t rd)
++{
++ static char buf[32];
++ struct in_addr addr;
++ u_int32_t u32;
++ u_int16_t u16;
++
++ rd = betoh64(rd);
++ switch (rd >> 48) {
++ case EXT_COMMUNITY_TWO_AS:
++ u32 = rd & 0xffffffff;
++ u16 = (rd >> 32) & 0xffff;
++ snprintf(buf, sizeof(buf), "rd %i:%i", u16, u32);
++ break;
++ case EXT_COMMUNITY_FOUR_AS:
++ u32 = (rd >> 16) & 0xffffffff;
++ u16 = rd & 0xffff;
++ snprintf(buf, sizeof(buf), "rd %s:%i", log_as(u32), u16);
++ break;
++ case EXT_COMMUNITY_IPV4:
++ u32 = (rd >> 16) & 0xffffffff;
++ u16 = rd & 0xffff;
++ addr.s_addr = htonl(u32);
++ snprintf(buf, sizeof(buf), "rd %s:%i", inet_ntoa(addr), u16);
++ break;
++ default:
++ return ("rd ?");
++ }
++ return (buf);
++}
++
++/* NOTE: this function does not check if the type/subtype combo is
++ * actually valid. */
++const char *
++log_ext_subtype(u_int8_t subtype)
++{
++ static char etype[6];
++
++ switch (subtype) {
++ case EXT_COMMUNITY_ROUTE_TGT:
++ return ("rt"); /* route target */
++ case EXT_CUMMUNITY_ROUTE_ORIG:
++ return ("soo"); /* source of origin */
++ case EXT_COMMUNITY_OSPF_DOM_ID:
++ return ("odi"); /* ospf domain id */
++ case EXT_COMMUNITY_OSPF_RTR_TYPE:
++ return ("ort"); /* ospf route type */
++ case EXT_COMMUNITY_OSPF_RTR_ID:
++ return ("ori"); /* ospf router id */
++ case EXT_COMMUNITY_BGP_COLLECT:
++ return ("bdc"); /* bgp data collection */
++ default:
++ snprintf(etype, sizeof(etype), "[%u]", subtype);
++ return (etype);
++ }
++}
++
++const char *
++aspath_delim(u_int8_t seg_type, int closing)
++{
++ static char db[8];
++
++ switch (seg_type) {
++ case AS_SET:
++ if (!closing)
++ return ("{ ");
++ else
++ return (" }");
++ case AS_SEQUENCE:
++ return ("");
++ case AS_CONFED_SEQUENCE:
++ if (!closing)
++ return ("( ");
++ else
++ return (" )");
++ case AS_CONFED_SET:
++ if (!closing)
++ return ("[ ");
++ else
++ return (" ]");
++ default:
++ if (!closing)
++ snprintf(db, sizeof(db), "!%u ", seg_type);
++ else
++ snprintf(db, sizeof(db), " !%u", seg_type);
++ return (db);
++ }
++}
++
+ int
+ aspath_snprint(char *buf, size_t size, void *data, u_int16_t len)
+ {
+@@ -118,16 +226,10 @@ aspath_snprint(char *buf, size_t size, v
+ seg_len = seg[1];
+ seg_size = 2 + sizeof(u_int32_t) * seg_len;
+
+- if (seg_type == AS_SET) {
+- if (total_size != 0)
+- r = snprintf(buf, size, " { ");
+- else
+- r = snprintf(buf, size, "{ ");
+- UPDATE();
+- } else if (total_size != 0) {
+- r = snprintf(buf, size, " ");
+- UPDATE();
+- }
++ r = snprintf(buf, size, "%s%s",
++ total_size != 0 ? " " : "",
++ aspath_delim(seg_type, 0));
++ UPDATE();
+
+ for (i = 0; i < seg_len; i++) {
+ r = snprintf(buf, size, "%s",
+@@ -138,10 +240,8 @@ aspath_snprint(char *buf, size_t size, v
+ UPDATE();
+ }
+ }
+- if (seg_type == AS_SET) {
+- r = snprintf(buf, size, " }");
+- UPDATE();
+- }
++ r = snprintf(buf, size, "%s", aspath_delim(seg_type, 1));
++ UPDATE();
+ }
+ /* ensure that we have a valid C-string especially for empty as path */
+ if (size > 0)
+@@ -235,6 +335,67 @@ aspath_strlen(void *data, u_int16_t len)
+ return (total_size);
+ }
+
++/* we need to be able to search more than one as */
++int
++aspath_match(void *data, u_int16_t len, enum as_spec type, u_int32_t as)
++{
++ u_int8_t *seg;
++ int final;
++ u_int16_t seg_size;
++ u_int8_t i, seg_type, seg_len;
++
++ if (type == AS_EMPTY) {
++ if (len == 0)
++ return (1);
++ else
++ return (0);
++ }
++
++ final = 0;
++ seg = data;
++ for (; len > 0; len -= seg_size, seg += seg_size) {
++ seg_type = seg[0];
++ seg_len = seg[1];
++ seg_size = 2 + sizeof(u_int32_t) * seg_len;
++
++ final = (len == seg_size);
++
++ /* just check the first (leftmost) AS */
++ if (type == AS_PEER) {
++ if (as == aspath_extract(seg, 0))
++ return (1);
++ else
++ return (0);
++ }
++ /* just check the final (rightmost) AS */
++ if (type == AS_SOURCE) {
++ /* not yet in the final segment */
++ if (!final)
++ continue;
++
++ if (as == aspath_extract(seg, seg_len - 1))
++ return (1);
++ else
++ return (0);
++ }
++
++ /* AS_TRANSIT or AS_ALL */
++ for (i = 0; i < seg_len; i++) {
++ if (as == aspath_extract(seg, i)) {
++ /*
++ * the source (rightmost) AS is excluded from
++ * AS_TRANSIT matches.
++ */
++ if (final && i == seg_len - 1 &&
++ type == AS_TRANSIT)
++ return (0);
++ return (1);
++ }
++ }
++ }
++ return (0);
++}
++
+ /*
+ * Extract the asnum out of the as segment at the specified position.
+ * Direct access is not possible because of non-aligned reads.
+@@ -251,6 +412,66 @@ aspath_extract(const void *seg, int pos)
+ return (ntohl(as));
+ }
+
++int
++prefix_compare(const struct bgpd_addr *a, const struct bgpd_addr *b,
++ int prefixlen)
++{
++ in_addr_t mask, aa, ba;
++ int i;
++ u_int8_t m;
++
++ if (a->aid != b->aid)
++ return (a->aid - b->aid);
++
++ switch (a->aid) {
++ case AID_INET:
++ if (prefixlen > 32)
++ fatalx("prefix_cmp: bad IPv4 prefixlen");
++ mask = htonl(prefixlen2mask(prefixlen));
++ aa = ntohl(a->v4.s_addr & mask);
++ ba = ntohl(b->v4.s_addr & mask);
++ if (aa != ba)
++ return (aa - ba);
++ return (0);
++ case AID_INET6:
++ if (prefixlen > 128)
++ fatalx("prefix_cmp: bad IPv6 prefixlen");
++ for (i = 0; i < prefixlen / 8; i++)
++ if (a->v6.s6_addr[i] != b->v6.s6_addr[i])
++ return (a->v6.s6_addr[i] - b->v6.s6_addr[i]);
++ i = prefixlen % 8;
++ if (i) {
++ m = 0xff00 >> i;
++ if ((a->v6.s6_addr[prefixlen / 8] & m) !=
++ (b->v6.s6_addr[prefixlen / 8] & m))
++ return ((a->v6.s6_addr[prefixlen / 8] & m) -
++ (b->v6.s6_addr[prefixlen / 8] & m));
++ }
++ return (0);
++ case AID_VPN_IPv4:
++ if (prefixlen > 32)
++ fatalx("prefix_cmp: bad IPv4 VPN prefixlen");
++ if (betoh64(a->vpn4.rd) > betoh64(b->vpn4.rd))
++ return (1);
++ if (betoh64(a->vpn4.rd) < betoh64(b->vpn4.rd))
++ return (-1);
++ mask = htonl(prefixlen2mask(prefixlen));
++ aa = ntohl(a->vpn4.addr.s_addr & mask);
++ ba = ntohl(b->vpn4.addr.s_addr & mask);
++ if (aa != ba)
++ return (aa - ba);
++ if (a->vpn4.labellen > b->vpn4.labellen)
++ return (1);
++ if (a->vpn4.labellen < b->vpn4.labellen)
++ return (-1);
++ return (memcmp(a->vpn4.labelstack, b->vpn4.labelstack,
++ a->vpn4.labellen));
++ default:
++ fatalx("prefix_cmp: unknown af");
++ }
++ return (-1);
++}
++
+ in_addr_t
+ prefixlen2mask(u_int8_t prefixlen)
+ {
+@@ -276,3 +497,115 @@ inet6applymask(struct in6_addr *dest, co
+ for (i = 0; i < 16; i++)
+ dest->s6_addr[i] = src->s6_addr[i] & mask.s6_addr[i];
+ }
++
++/* address family translation functions */
++const struct aid aid_vals[AID_MAX] = AID_VALS;
++
++const char *
++aid2str(u_int8_t aid)
++{
++ if (aid < AID_MAX)
++ return (aid_vals[aid].name);
++ return ("unknown AID");
++}
++
++int
++aid2afi(u_int8_t aid, u_int16_t *afi, u_int8_t *safi)
++{
++ if (aid < AID_MAX) {
++ *afi = aid_vals[aid].afi;
++ *safi = aid_vals[aid].safi;
++ return (0);
++ }
++ return (-1);
++}
++
++int
++afi2aid(u_int16_t afi, u_int8_t safi, u_int8_t *aid)
++{
++ u_int8_t i;
++
++ for (i = 0; i < AID_MAX; i++)
++ if (aid_vals[i].afi == afi && aid_vals[i].safi == safi) {
++ *aid = i;
++ return (0);
++ }
++
++ return (-1);
++}
++
++sa_family_t
++aid2af(u_int8_t aid)
++{
++ if (aid < AID_MAX)
++ return (aid_vals[aid].af);
++ return (AF_UNSPEC);
++}
++
++int
++af2aid(sa_family_t af, u_int8_t safi, u_int8_t *aid)
++{
++ u_int8_t i;
++
++ if (safi == 0) /* default to unicast subclass */
++ safi = SAFI_UNICAST;
++
++ for (i = 0; i < AID_MAX; i++)
++ if (aid_vals[i].af == af && aid_vals[i].safi == safi) {
++ *aid = i;
++ return (0);
++ }
++
++ return (-1);
++}
++
++struct sockaddr *
++addr2sa(struct bgpd_addr *addr, u_int16_t port)
++{
++ static struct sockaddr_storage ss;
++ struct sockaddr_in *sa_in = (struct sockaddr_in *)&ss;
++ struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)&ss;
++
++ if (addr->aid == AID_UNSPEC)
++ return (NULL);
++
++ bzero(&ss, sizeof(ss));
++ switch (addr->aid) {
++ case AID_INET:
++ sa_in->sin_family = AF_INET;
++ sa_in->sin_len = sizeof(struct sockaddr_in);
++ sa_in->sin_addr.s_addr = addr->v4.s_addr;
++ sa_in->sin_port = htons(port);
++ break;
++ case AID_INET6:
++ sa_in6->sin6_family = AF_INET6;
++ sa_in6->sin6_len = sizeof(struct sockaddr_in6);
++ memcpy(&sa_in6->sin6_addr, &addr->v6,
++ sizeof(sa_in6->sin6_addr));
++ sa_in6->sin6_port = htons(port);
++ sa_in6->sin6_scope_id = addr->scope_id;
++ break;
++ }
++
++ return ((struct sockaddr *)&ss);
++}
++
++void
++sa2addr(struct sockaddr *sa, struct bgpd_addr *addr)
++{
++ struct sockaddr_in *sa_in = (struct sockaddr_in *)sa;
++ struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)sa;
++
++ bzero(addr, sizeof(*addr));
++ switch (sa->sa_family) {
++ case AF_INET:
++ addr->aid = AID_INET;
++ memcpy(&addr->v4, &sa_in->sin_addr, sizeof(addr->v4));
++ break;
++ case AF_INET6:
++ addr->aid = AID_INET6;
++ memcpy(&addr->v6, &sa_in6->sin6_addr, sizeof(addr->v6));
++ addr->scope_id = sa_in6->sin6_scope_id; /* I hate v6 */
++ break;
++ }
++}