summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorclaudio <claudio@openbsd.org>2007-05-29 02:31:42 +0000
committerclaudio <claudio@openbsd.org>2007-05-29 02:31:42 +0000
commit327173d27e182a300a95d3d0d69a5627eedb762d (patch)
tree25bacc079891082eec052a581683f164ea51d28a
parentCorrectly encode the End-of-RIB marker capability. It is just 2 bytes not (diff)
downloadwireguard-openbsd-327173d27e182a300a95d3d0d69a5627eedb762d.tar.xz
wireguard-openbsd-327173d27e182a300a95d3d0d69a5627eedb762d.zip
Correctly fill the MP reach and unreach update messages. Until now
short updateds included a dummy ::/0 route and the withdraws were totaly wrong because the AFI/SAFI header was missing. put it in henning@
-rw-r--r--usr.sbin/bgpd/rde_update.c57
1 files changed, 36 insertions, 21 deletions
diff --git a/usr.sbin/bgpd/rde_update.c b/usr.sbin/bgpd/rde_update.c
index 47bfb911164..b32c2cea701 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.58 2007/05/11 11:27:59 claudio Exp $ */
+/* $OpenBSD: rde_update.c,v 1.59 2007/05/29 02:31:42 claudio Exp $ */
/*
* Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
@@ -890,11 +890,17 @@ up_dump_attrnlri(u_char *buf, int len, struct rde_peer *peer)
u_char *
up_dump_mp_unreach(u_char *buf, u_int16_t *len, struct rde_peer *peer)
{
- int wpos = 8; /* reserve some space for header */
+ int wpos;
u_int16_t datalen, tmp;
u_int16_t attrlen = 2; /* attribute header (without len) */
u_int8_t flags = ATTR_OPTIONAL;
+ /*
+ * reserve space for withdraw len, attr len, the attribute header
+ * and the mp attribute header
+ */
+ wpos = 2 + 2 + 4 + 3;
+
if (*len < wpos)
return (NULL);
@@ -903,6 +909,7 @@ up_dump_mp_unreach(u_char *buf, u_int16_t *len, struct rde_peer *peer)
if (datalen == 0)
return (NULL);
+ datalen += 3; /* afi + safi */
if (datalen > 255) {
attrlen += 2 + datalen;
flags |= ATTR_EXTLEN;
@@ -910,27 +917,36 @@ up_dump_mp_unreach(u_char *buf, u_int16_t *len, struct rde_peer *peer)
attrlen += 1 + datalen;
buf++;
}
- /* prepend header */
- /* no IPv4 withdraws */
- wpos = 0;
- bzero(buf, sizeof(u_int16_t));
- wpos += sizeof(u_int16_t);
-
- /* attribute length */
- tmp = htons(attrlen);
+ /* prepend header, need to do it reverse */
+ /* safi & afi */
+ buf[--wpos] = SAFI_UNICAST;
+ wpos -= sizeof(u_int16_t);
+ tmp = htons(AFI_IPv6);
memcpy(buf + wpos, &tmp, sizeof(u_int16_t));
- wpos += sizeof(u_int16_t);
-
- /* mp attribute */
- buf[wpos++] = flags;
- buf[wpos++] = (u_char)ATTR_MP_UNREACH_NLRI;
+ /* attribute length */
if (datalen > 255) {
+ wpos -= sizeof(u_int16_t);
tmp = htons(datalen);
memcpy(buf + wpos, &tmp, sizeof(u_int16_t));
- wpos += sizeof(u_int16_t);
} else
- buf[wpos++] = (u_char)datalen;
+ buf[--wpos] = (u_char)datalen;
+
+ /* mp attribute */
+ buf[--wpos] = (u_char)ATTR_MP_UNREACH_NLRI;
+ buf[--wpos] = flags;
+
+ /* attribute length */
+ wpos -= sizeof(u_int16_t);
+ tmp = htons(attrlen);
+ memcpy(buf + wpos, &tmp, sizeof(u_int16_t));
+
+ /* no IPv4 withdraws */
+ wpos -= sizeof(u_int16_t);
+ bzero(buf + wpos, sizeof(u_int16_t));
+
+ if (wpos < 0)
+ fatalx("up_dump_mp_unreach: buffer underflow");
/* total length includes the two 2-bytes length fields. */
*len = attrlen + 2 * sizeof(u_int16_t);
@@ -993,7 +1009,6 @@ up_dump_mp_reach(u_char *buf, u_int16_t *len, struct rde_peer *peer)
datalen += 4;
flags |= ATTR_EXTLEN;
} else {
- buf++; wpos--; /* skip one byte */
buf[--wpos] = (u_char)datalen;
datalen += 3;
}
@@ -1004,9 +1019,8 @@ up_dump_mp_reach(u_char *buf, u_int16_t *len, struct rde_peer *peer)
wpos -= upa->attr_len;
memcpy(buf + wpos, upa->attr, upa->attr_len);
- if (wpos != 4)
+ if (wpos < 4)
fatalx("Grrr, mp_reach buffer fucked up");
- *len = datalen + 4;
wpos -= 2;
tmp = htons(datalen);
@@ -1026,6 +1040,7 @@ up_dump_mp_reach(u_char *buf, u_int16_t *len, struct rde_peer *peer)
peer->up_acnt--;
}
- return (buf);
+ *len = datalen + 4;
+ return (buf + wpos);
}