return 4;
}
+/*
+ * The only way to know that a BGP UPDATE message is using add path is
+ * by checking if the capability is in the OPEN message which we may have missed.
+ * So this function checks if it is possible that the update could contain add path
+ * and if so it checks that standard BGP doesn't make sense.
+ */
+
+static int
+check_add_path(const u_char *pptr, u_int length, u_int max_prefix_length) {
+
+ u_int offset, prefix_length;
+ if (length < 5) {
+ return 0;
+ }
+
+ /* check if it could be add path */
+ for(offset = 0; offset < length;) {
+ offset += 4;
+ prefix_length = pptr[offset];
+ /*
+ * Add 4 to cover the path id
+ * and check the prefix length isn't greater than 32/128.
+ */
+ if (prefix_length > max_prefix_length) {
+ return 0;
+ }
+ /* Add 1 for the prefix_length byte and prefix_length to cover the address */
+ offset += 1 + ((prefix_length + 7) / 8);
+ }
+ /* check we haven't gone past the end of the section */
+ if (offset > length) {
+ return 0;
+ }
+
+ /* check it's not standard BGP */
+ for(offset = 0; offset < length; ) {
+ prefix_length = pptr[offset];
+ /*
+ * If the prefix_length is zero (0.0.0.0/0)
+ * and since it's not the only address (length >= 5)
+ * then it is add-path
+ */
+ if (prefix_length < 1 || prefix_length > max_prefix_length) {
+ return 1;
+ }
+ offset += 1 + ((prefix_length + 7) / 8);
+ }
+ if (offset > length) {
+ return 1;
+ }
+
+ /* assume not add-path by default */
+ return 0;
+}
+
+
static int
bgp_attr_print(netdissect_options *ndo,
u_int atype, const u_char *pptr, u_int len)
const u_char *tptr;
char buf[MAXHOSTNAMELEN + 100];
int as_size;
+ int add_path4, add_path6, path_id;
tptr = pptr;
tlen=len;
ND_PRINT((ndo, ", no SNPA"));
}
+ add_path4 = check_add_path(tptr, (len-(tptr - pptr)), 32);
+ add_path6 = check_add_path(tptr, (len-(tptr - pptr)), 128);
+
while (tptr < pptr + len) {
switch (af<<8 | safi) {
case (AFNUM_INET<<8 | SAFNUM_UNICAST):
case (AFNUM_INET<<8 | SAFNUM_MULTICAST):
case (AFNUM_INET<<8 | SAFNUM_UNIMULTICAST):
+ if (add_path4) {
+ path_id = EXTRACT_32BITS(tptr);
+ tptr += 4;
+ }
advance = decode_prefix4(ndo, tptr, len, buf, sizeof(buf));
if (advance == -1)
ND_PRINT((ndo, "\n\t (illegal prefix length)"));
break; /* bytes left, but not enough */
else
ND_PRINT((ndo, "\n\t %s", buf));
+ if (add_path4) {
+ ND_PRINT((ndo, " Path Id: %d", path_id));
+ }
break;
case (AFNUM_INET<<8 | SAFNUM_LABUNICAST):
advance = decode_labeled_prefix4(ndo, tptr, len, buf, sizeof(buf));
case (AFNUM_INET6<<8 | SAFNUM_UNICAST):
case (AFNUM_INET6<<8 | SAFNUM_MULTICAST):
case (AFNUM_INET6<<8 | SAFNUM_UNIMULTICAST):
+ if (add_path6) {
+ path_id = EXTRACT_32BITS(tptr);
+ tptr += 4;
+ }
advance = decode_prefix6(ndo, tptr, len, buf, sizeof(buf));
if (advance == -1)
ND_PRINT((ndo, "\n\t (illegal prefix length)"));
break; /* bytes left, but not enough */
else
ND_PRINT((ndo, "\n\t %s", buf));
+ if (add_path6) {
+ ND_PRINT((ndo, " Path Id: %d", path_id));
+ }
break;
case (AFNUM_INET6<<8 | SAFNUM_LABUNICAST):
advance = decode_labeled_prefix6(ndo, tptr, len, buf, sizeof(buf));
tptr += 3;
+ add_path4 = check_add_path(tptr, (len-(tptr - pptr)), 32);
+ add_path6 = check_add_path(tptr, (len-(tptr - pptr)), 128);
+
while (tptr < pptr + len) {
switch (af<<8 | safi) {
case (AFNUM_INET<<8 | SAFNUM_UNICAST):
case (AFNUM_INET<<8 | SAFNUM_MULTICAST):
case (AFNUM_INET<<8 | SAFNUM_UNIMULTICAST):
+ if (add_path4) {
+ path_id = EXTRACT_32BITS(tptr);
+ tptr += 4;
+ }
advance = decode_prefix4(ndo, tptr, len, buf, sizeof(buf));
if (advance == -1)
ND_PRINT((ndo, "\n\t (illegal prefix length)"));
break; /* bytes left, but not enough */
else
ND_PRINT((ndo, "\n\t %s", buf));
+ if (add_path4) {
+ ND_PRINT((ndo, " Path Id: %d", path_id));
+ }
break;
case (AFNUM_INET<<8 | SAFNUM_LABUNICAST):
advance = decode_labeled_prefix4(ndo, tptr, len, buf, sizeof(buf));
case (AFNUM_INET6<<8 | SAFNUM_UNICAST):
case (AFNUM_INET6<<8 | SAFNUM_MULTICAST):
case (AFNUM_INET6<<8 | SAFNUM_UNIMULTICAST):
+ if (add_path6) {
+ path_id = EXTRACT_32BITS(tptr);
+ tptr += 4;
+ }
advance = decode_prefix6(ndo, tptr, len, buf, sizeof(buf));
if (advance == -1)
ND_PRINT((ndo, "\n\t (illegal prefix length)"));
break; /* bytes left, but not enough */
else
ND_PRINT((ndo, "\n\t %s", buf));
+ if (add_path6) {
+ ND_PRINT((ndo, " Path Id: %d", path_id));
+ }
break;
case (AFNUM_INET6<<8 | SAFNUM_LABUNICAST):
advance = decode_labeled_prefix6(ndo, tptr, len, buf, sizeof(buf));
struct bgp bgp;
const u_char *p;
int withdrawn_routes_len;
+ char buf[MAXHOSTNAMELEN + 100];
+ int wpfx;
int len;
int i;
p += 2;
length -= 2;
if (withdrawn_routes_len) {
- /*
- * Without keeping state from the original NLRI message,
- * it's not possible to tell if this a v4 or v6 route,
- * so only try to decode it if we're not v6 enabled.
- */
ND_TCHECK2(p[0], withdrawn_routes_len);
if (length < withdrawn_routes_len)
goto trunc;
- ND_PRINT((ndo, "\n\t Withdrawn routes: %d bytes", withdrawn_routes_len));
- p += withdrawn_routes_len;
- length -= withdrawn_routes_len;
+ if (withdrawn_routes_len < 2)
+ goto trunc;
+
+ ND_PRINT((ndo, "\n\t Withdrawn routes:"));
+ int add_path, path_id;
+ add_path = check_add_path(p, withdrawn_routes_len, 32);
+ while(withdrawn_routes_len > 0) {
+ if (add_path) {
+ path_id = EXTRACT_32BITS(p);
+ p += 4;
+ length -= 4;
+ withdrawn_routes_len -= 4;
+ }
+ wpfx = decode_prefix4(ndo, p, withdrawn_routes_len, buf, sizeof(buf));
+ if (wpfx == -1) {
+ ND_PRINT((ndo, "\n\t (illegal prefix length)"));
+ break;
+ } else if (wpfx == -2)
+ goto trunc;
+ else if (wpfx == -3)
+ goto trunc; /* bytes left, but not enough */
+ else {
+ ND_PRINT((ndo, "\n\t %s", buf));
+ if (add_path) {
+ ND_PRINT((ndo, " Path Id: %d", path_id));
+ }
+ p += wpfx;
+ length -= wpfx;
+ withdrawn_routes_len -= wpfx;
+ }
+ }
}
ND_TCHECK2(p[0], 2);
}
if (length) {
- /*
- * XXX - what if they're using the "Advertisement of
- * Multiple Paths in BGP" feature:
- *
- * https://datatracker.ietf.org/doc/draft-ietf-idr-add-paths/
- *
- * http://tools.ietf.org/html/draft-ietf-idr-add-paths-06
- */
+ int add_path = check_add_path(p, length, 32);
+ int path_id;
ND_PRINT((ndo, "\n\t Updated routes:"));
- while (length) {
- char buf[MAXHOSTNAMELEN + 100];
+ while (length > 0) {
+ if (add_path) {
+ path_id = EXTRACT_32BITS(p);
+ p += 4;
+ length -= 4;
+ }
i = decode_prefix4(ndo, p, length, buf, sizeof(buf));
if (i == -1) {
ND_PRINT((ndo, "\n\t (illegal prefix length)"));
else if (i == -3)
goto trunc; /* bytes left, but not enough */
else {
- ND_PRINT((ndo, "\n\t %s", buf));
- p += i;
- length -= i;
+ ND_PRINT((ndo, "\n\t %s", buf));
+ if (add_path) {
+ ND_PRINT((ndo, " Path Id: %d", path_id));
+ }
+ p += i;
+ length -= i;
}
}
}
--- /dev/null
+IP truncated-ip - 38 bytes missing! (tos 0x0, ttl 64, id 1, offset 0, flags [none], proto TCP (6), length 309)
+ 127.0.0.1.179 > 127.0.0.1.80: Flags [S], seq 0:269, win 8192, length 269: BGP
+ Update Message (2), length: 231
+ Withdrawn routes:
+ 8.2.0.0/24 Path Id: 20
+ 8.2.1.0/24 Path Id: 21
+ Origin (1), length: 1, Flags [T]: EGP
+ Next Hop (3), length: 0, Flags [T]: invalid len
+ AS Path (2), length: 6, Flags [T]: 100 200
+ Multi-Protocol Reach NLRI (14), length: 25, Flags [T]:
+ AFI: IPv4 (1), SAFI: Unicast (1)
+ nexthop: 1.2.3.4, nh-length: 4, no SNPA
+ 120.4.0.0/24 Path Id: 40
+ 120.4.1.0/24 Path Id: 41
+ Multi-Protocol Unreach NLRI (15), length: 19, Flags [T]:
+ AFI: IPv4 (1), SAFI: Unicast (1)
+ 32.45.0.0/24 Path Id: 700
+ 32.45.1.0/24 Path Id: 701
+ Multi-Protocol Reach NLRI (14), length: 61, Flags [T]:
+ AFI: IPv6 (2), SAFI: Unicast (1)
+ nexthop: 2000:0:0:40::1, nh-length: 16, no SNPA
+ 2002::1400:0/120 Path Id: 1
+ 2002::1400:100/120 Path Id: 2
+ Multi-Protocol Unreach NLRI (15), length: 43, Flags [T]:
+ AFI: IPv6 (2), SAFI: Unicast (1)
+ 2002::2800:0/120 Path Id: 100
+ 2002::2800:100/120 Path Id: 101
+ Updated routes:
+ 6.2.0.0/24 Path Id: 10
+ 6.2.1.0/24 Path Id: 11