X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/43104d3f8a89543f6fe51115e28d4630b7fa8b87..6d3b0e4599c5aa922bba42e53b038b51d9024a62:/print-bgp.c diff --git a/print-bgp.c b/print-bgp.c index 97f3bbee..ba927e4b 100644 --- a/print-bgp.c +++ b/print-bgp.c @@ -80,13 +80,15 @@ struct bgp_open { nd_uint16_t bgpo_holdtime; nd_uint32_t bgpo_id; nd_uint8_t bgpo_optlen; + nd_uint8_t bgpo_opttype; /* RFC9072 */ + nd_uint16_t bgpo_optlen_extended; /* RFC9072 */ /* options should follow */ }; #define BGP_OPEN_SIZE 29 /* unaligned */ struct bgp_opt { - nd_uint8_t bgpopt_type; - nd_uint8_t bgpopt_len; + nd_uint8_t bgpopt_type; + nd_uint16_t bgpopt_len; /* Can be one or two bytes, depending on RFC9072 */ /* variable length */ }; #define BGP_OPT_SIZE 2 /* some compilers may pad to 4 bytes */ @@ -106,10 +108,22 @@ struct bgp_route_refresh { nd_uint16_t len; nd_uint8_t type; /* No padding after this; afi is, in fact, not aligned */ nd_uint16_t afi; - nd_uint8_t res; + nd_uint8_t subtype; nd_uint8_t safi; }; #define BGP_ROUTE_REFRESH_SIZE 23 +#define BGP_ROUTE_REFRESH_SUBTYPE_NORMAL 0 +#define BGP_ROUTE_REFRESH_SUBTYPE_BORR 1 +#define BGP_ROUTE_REFRESH_SUBTYPE_EORR 2 +#define BGP_ROUTE_REFRESH_SUBTYPE_RESERVED 255 + +static const struct tok bgp_route_refresh_subtype_values[] = { + {BGP_ROUTE_REFRESH_SUBTYPE_NORMAL, "Normal route refresh request"}, + {BGP_ROUTE_REFRESH_SUBTYPE_BORR, + "Demarcation of the beginning of a route refresh"}, + {BGP_ROUTE_REFRESH_SUBTYPE_EORR, + "Demarcation of the ending of a route refresh"}, + {0, NULL}}; #define bgp_attr_lenlen(flags, p) \ (((flags) & 0x10) ? 2U : 1U) @@ -126,9 +140,6 @@ struct bgp_route_refresh { #define BGPTYPE_COMMUNITIES 8 /* RFC1997 */ #define BGPTYPE_ORIGINATOR_ID 9 /* RFC4456 */ #define BGPTYPE_CLUSTER_LIST 10 /* RFC4456 */ -#define BGPTYPE_DPA 11 /* deprecated, draft-ietf-idr-bgp-dpa */ -#define BGPTYPE_ADVERTISERS 12 /* deprecated RFC1863 */ -#define BGPTYPE_RCID_PATH 13 /* deprecated RFC1863 */ #define BGPTYPE_MP_REACH_NLRI 14 /* RFC4760 */ #define BGPTYPE_MP_UNREACH_NLRI 15 /* RFC4760 */ #define BGPTYPE_EXTD_COMMUNITIES 16 /* RFC4360 */ @@ -159,9 +170,6 @@ static const struct tok bgp_attr_values[] = { { BGPTYPE_COMMUNITIES, "Community"}, { BGPTYPE_ORIGINATOR_ID, "Originator ID"}, { BGPTYPE_CLUSTER_LIST, "Cluster List"}, - { BGPTYPE_DPA, "DPA"}, - { BGPTYPE_ADVERTISERS, "Advertisers"}, - { BGPTYPE_RCID_PATH, "RCID Path / Cluster ID"}, { BGPTYPE_MP_REACH_NLRI, "Multi-Protocol Reach NLRI"}, { BGPTYPE_MP_UNREACH_NLRI, "Multi-Protocol Unreach NLRI"}, { BGPTYPE_EXTD_COMMUNITIES, "Extended Community"}, @@ -216,13 +224,14 @@ static const struct tok bgp_opt_values[] = { #define BGP_CAPCODE_ORF 3 /* RFC5291 */ #define BGP_CAPCODE_MR 4 /* RFC3107 */ #define BGP_CAPCODE_EXT_NH 5 /* RFC5549 */ +#define BGP_CAPCODE_EXT_MSG 6 /* RFC8654 */ #define BGP_CAPCODE_ML 8 /* RFC8277 */ #define BGP_CAPCODE_RESTART 64 /* RFC4724 */ #define BGP_CAPCODE_AS_NEW 65 /* RFC6793 */ #define BGP_CAPCODE_DYN_CAP 67 /* draft-ietf-idr-dynamic-cap */ #define BGP_CAPCODE_MULTISESS 68 /* draft-ietf-idr-bgp-multisession */ #define BGP_CAPCODE_ADD_PATH 69 /* RFC7911 */ -#define BGP_CAPCODE_ENH_RR 70 /* draft-keyur-bgp-enhanced-route-refresh */ +#define BGP_CAPCODE_ENH_RR 70 /* RFC7313 */ #define BGP_CAPCODE_LLGR 71 /* draft-uttaro-idr-bgp-persistence-05 */ #define BGP_CAPCODE_RR_CISCO 128 @@ -232,6 +241,7 @@ static const struct tok bgp_capcode_values[] = { { BGP_CAPCODE_ORF, "Cooperative Route Filtering"}, { BGP_CAPCODE_MR, "Multiple Routes to a Destination"}, { BGP_CAPCODE_EXT_NH, "Extended Next Hop Encoding"}, + { BGP_CAPCODE_EXT_MSG, "BGP Extended Message"}, { BGP_CAPCODE_ML, "Multiple Labels"}, { BGP_CAPCODE_RESTART, "Graceful Restart"}, { BGP_CAPCODE_AS_NEW, "32-Bit AS Number"}, @@ -263,12 +273,10 @@ static const struct tok bgp_notify_major_values[] = { { 0, NULL} }; -/* draft-ietf-idr-cease-subcode-02 */ +/* RFC 4486 */ #define BGP_NOTIFY_MINOR_CEASE_MAXPRFX 1 -/* draft-ietf-idr-shutdown-07 */ #define BGP_NOTIFY_MINOR_CEASE_SHUT 2 #define BGP_NOTIFY_MINOR_CEASE_RESET 4 -#define BGP_NOTIFY_MINOR_CEASE_ADMIN_SHUTDOWN_LEN 128 static const struct tok bgp_notify_minor_cease_values[] = { { BGP_NOTIFY_MINOR_CEASE_MAXPRFX, "Maximum Number of Prefixes Reached"}, { BGP_NOTIFY_MINOR_CEASE_SHUT, "Administrative Shutdown"}, @@ -433,6 +441,7 @@ static const struct tok bgp_safi_values[] = { #define BGP_EXT_COM_OSPF_RTYPE 0x0306 /* OSPF Route Type,Format Area(4B):RouteType(1B):Options(1B) */ #define BGP_EXT_COM_OSPF_RTYPE2 0x8000 /* duplicate - keep for backwards compatibility */ +#define BGP_EXT_COM_ENCAP 0x030c /* rfc5512 */ #define BGP_EXT_COM_OSPF_RID 0x0107 /* OSPF Router ID,Format RouterID(4B):Unused(2B) */ #define BGP_EXT_COM_OSPF_RID2 0x8001 /* duplicate - keep for backwards compatibility */ @@ -452,6 +461,9 @@ static const struct tok bgp_safi_values[] = { #define BGP_EXT_COM_EIGRP_EXT_REMAS_REMID 0x8804 #define BGP_EXT_COM_EIGRP_EXT_REMPROTO_REMMETRIC 0x8805 +/* Optional Parameters */ +#define BGP_OPEN_NON_EXT_OPT_TYPE_EXTENDED_LENGTH 255 /* Non-Ext OP Type */ + static const struct tok bgp_extd_comm_flag_values[] = { { 0x8000, "vendor-specific"}, { 0x4000, "non-transitive"}, @@ -472,6 +484,7 @@ static const struct tok bgp_extd_comm_subtype_values[] = { { BGP_EXT_COM_VPN_ORIGIN4, "ospf-domain"}, { BGP_EXT_COM_OSPF_RTYPE, "ospf-route-type"}, { BGP_EXT_COM_OSPF_RTYPE2, "ospf-route-type"}, + { BGP_EXT_COM_ENCAP, "encapsulation"}, { BGP_EXT_COM_OSPF_RID, "ospf-router-id"}, { BGP_EXT_COM_OSPF_RID2, "ospf-router-id"}, { BGP_EXT_COM_L2INFO, "layer2-info"}, @@ -488,6 +501,46 @@ static const struct tok bgp_extd_comm_subtype_values[] = { { 0, NULL}, }; +/* RFC RFC5512 BGP Tunnel Encapsulation Attribute Tunnel Types */ +#define BGP_ENCAP_TUNNEL_L2TPV3_IP 1 +#define BGP_ENCAP_TUNNEL_GRE 2 +#define BGP_ENCAP_TUNNEL_TRANSMIT 3 +#define BGP_ENCAP_TUNNEL_IPSEC 4 +#define BGP_ENCAP_TUNNEL_IP_IPSEC 5 +#define BGP_ENCAP_TUNNEL_MPLS_IP 6 +#define BGP_ENCAP_TUNNEL_IP_IP 7 +#define BGP_ENCAP_TUNNEL_VXLAN 8 +#define BGP_ENCAP_TUNNEL_NVGRE 9 +#define BGP_ENCAP_TUNNEL_MPLS 10 +#define BGP_ENCAP_TUNNEL_MPLS_GRE 11 +#define BGP_ENCAP_TUNNEL_VXLAN_GPE 12 +#define BGP_ENCAP_TUNNEL_MPLS_UDP 13 +#define BGP_ENCAP_TUNNEL_IPV6 14 +#define BGP_ENCAP_TUNNEL_SR_TE 15 +#define BGP_ENCAP_TUNNEL_BARE 16 +#define BGP_ENCAP_TUNNEL_SR 17 + +static const struct tok bgp_extd_comm_encap_tunnel_values[] = { + { BGP_ENCAP_TUNNEL_L2TPV3_IP, "L2TPv3 over IP"}, + { BGP_ENCAP_TUNNEL_GRE, "GRE"}, + { BGP_ENCAP_TUNNEL_TRANSMIT, "Transmit Tunnel"}, + { BGP_ENCAP_TUNNEL_IPSEC, "IPsec"}, + { BGP_ENCAP_TUNNEL_IP_IPSEC, "IP in IP with IPsec"}, + { BGP_ENCAP_TUNNEL_MPLS_IP, "MPLS in IP with IPsec"}, + { BGP_ENCAP_TUNNEL_IP_IP, "IP in IP"}, + { BGP_ENCAP_TUNNEL_VXLAN, "VXLAN"}, + { BGP_ENCAP_TUNNEL_NVGRE, "NVGRE"}, + { BGP_ENCAP_TUNNEL_MPLS, "MPLS"}, + { BGP_ENCAP_TUNNEL_MPLS_GRE, "MPLS in GRE"}, + { BGP_ENCAP_TUNNEL_VXLAN_GPE, "VXLAN GPE"}, + { BGP_ENCAP_TUNNEL_MPLS_UDP, "MPLS in UDP"}, + { BGP_ENCAP_TUNNEL_IPV6, "IPv6"}, + { BGP_ENCAP_TUNNEL_SR_TE, "SR TE"}, + { BGP_ENCAP_TUNNEL_BARE, "Bare"}, + { BGP_ENCAP_TUNNEL_SR, "SR"}, + { 0, NULL}, +}; + /* OSPF codes for BGP_EXT_COM_OSPF_RTYPE draft-rosen-vpns-ospf-bgp-mpls */ #define BGP_OSPF_RTYPE_RTR 1 /* OSPF Router LSA */ #define BGP_OSPF_RTYPE_NET 2 /* OSPF Network LSA */ @@ -515,7 +568,7 @@ static const struct tok bgp_add_path_recvsend[] = { { 0, NULL }, }; -static char astostr[20]; +#define AS_STR_SIZE sizeof("xxxxx.xxxxx") /* * as_printf @@ -547,7 +600,6 @@ decode_prefix4(netdissect_options *ndo, nd_ipv4 addr; u_int plen, plenbytes; - ND_TCHECK_1(pptr); ITEMCHECK(1); plen = GET_U_1(pptr); if (32 < plen) @@ -556,20 +608,16 @@ decode_prefix4(netdissect_options *ndo, memset(&addr, 0, sizeof(addr)); plenbytes = (plen + 7) / 8; - ND_TCHECK_LEN(pptr + 1, plenbytes); ITEMCHECK(plenbytes); - memcpy(&addr, pptr + 1, plenbytes); + GET_CPY_BYTES(&addr, pptr + 1, plenbytes); if (plen % 8) { ((u_char *)&addr)[plenbytes - 1] &= ((0xff00 >> (plen % 8)) & 0xff); } snprintf(buf, buflen, "%s/%u", ipaddr_string(ndo, (const u_char *)&addr), plen); return 1 + plenbytes; -trunc: - return -2; - badtlv: - return -3; + return -2; } static int @@ -604,9 +652,8 @@ decode_labeled_prefix4(netdissect_options *ndo, memset(&addr, 0, sizeof(addr)); plenbytes = (plen + 7) / 8; - ND_TCHECK_LEN(pptr + 4, plenbytes); ITEMCHECK(plenbytes); - memcpy(&addr, pptr + 4, plenbytes); + GET_CPY_BYTES(&addr, pptr + 4, plenbytes); if (plen % 8) { ((u_char *)&addr)[plenbytes - 1] &= ((0xff00 >> (plen % 8)) & 0xff); } @@ -629,7 +676,7 @@ badtlv: /* * bgp_vpn_ip_print * - * print an ipv4 or ipv6 address into a buffer dependend on address length. + * print an ipv4 or ipv6 address into a buffer dependent on address length. */ static char * bgp_vpn_ip_print(netdissect_options *ndo, @@ -642,12 +689,10 @@ bgp_vpn_ip_print(netdissect_options *ndo, switch(addr_length) { case (sizeof(nd_ipv4) << 3): /* 32 */ - ND_TCHECK_LEN(pptr, sizeof(nd_ipv4)); - snprintf(pos, sizeof(addr), "%s", ipaddr_string(ndo, pptr)); + snprintf(pos, sizeof(addr), "%s", GET_IPADDR_STRING(pptr)); break; case (sizeof(nd_ipv6) << 3): /* 128 */ - ND_TCHECK_LEN(pptr, sizeof(nd_ipv6)); - snprintf(pos, sizeof(addr), "%s", ip6addr_string(ndo, pptr)); + snprintf(pos, sizeof(addr), "%s", GET_IP6ADDR_STRING(pptr)); break; default: snprintf(pos, sizeof(addr), "bogus address length %u", addr_length); @@ -655,7 +700,6 @@ bgp_vpn_ip_print(netdissect_options *ndo, } pos += strlen(pos); -trunc: *(pos) = '\0'; return (addr); } @@ -688,7 +732,6 @@ bgp_vpn_sg_print(netdissect_options *ndo, total_length = 0; /* Source address length, encoded in bits */ - ND_TCHECK_1(pptr); addr_length = GET_U_1(pptr); pptr++; @@ -703,7 +746,6 @@ bgp_vpn_sg_print(netdissect_options *ndo, } /* Group address length, encoded in bits */ - ND_TCHECK_1(pptr); addr_length = GET_U_1(pptr); pptr++; @@ -727,8 +769,10 @@ bgp_vpn_rd_print(netdissect_options *ndo, const u_char *pptr) { /* allocate space for the largest possible string */ - static char rd[sizeof("xxxxxxxxxx:xxxxx (xxx.xxx.xxx.xxx:xxxxx)")]; + static char rd[sizeof("xxxxx.xxxxx:xxxxx (xxx.xxx.xxx.xxx:xxxxx)")]; char *pos = rd; + /* allocate space for the largest possible string */ + char astostr[AS_STR_SIZE]; /* ok lets load the RD format */ switch (GET_BE_U_2(pptr)) { @@ -778,6 +822,8 @@ bgp_extended_community_print(netdissect_options *ndo, float f; uint32_t i; } bw; + /* allocate space for the largest possible string */ + char astostr[AS_STR_SIZE]; switch (GET_BE_U_2(pptr)) { @@ -787,7 +833,7 @@ bgp_extended_community_print(netdissect_options *ndo, ND_PRINT("%u:%u (= %s)", GET_BE_U_2(pptr + 2), GET_BE_U_4(pptr + 4), - ipaddr_string(ndo, pptr+4)); + GET_IPADDR_STRING(pptr+4)); break; case BGP_EXT_COM_RT_1: @@ -795,7 +841,7 @@ bgp_extended_community_print(netdissect_options *ndo, case BGP_EXT_COM_L2VPN_RT_1: case BGP_EXT_COM_VRF_RT_IMP: ND_PRINT("%s:%u", - ipaddr_string(ndo, pptr+2), + GET_IPADDR_STRING(pptr+2), GET_BE_U_2(pptr + 6)); break; @@ -807,7 +853,7 @@ bgp_extended_community_print(netdissect_options *ndo, break; case BGP_EXT_COM_LINKBAND: - bw.i = GET_BE_U_4(pptr + 2); + bw.i = GET_BE_U_4(pptr + 4); ND_PRINT("bandwidth: %.3f Mbps", bw.f*8/1000000); break; @@ -818,13 +864,13 @@ bgp_extended_community_print(netdissect_options *ndo, case BGP_EXT_COM_VPN_ORIGIN4: case BGP_EXT_COM_OSPF_RID: case BGP_EXT_COM_OSPF_RID2: - ND_PRINT("%s", ipaddr_string(ndo, pptr+2)); + ND_PRINT("%s", GET_IPADDR_STRING(pptr+2)); break; case BGP_EXT_COM_OSPF_RTYPE: case BGP_EXT_COM_OSPF_RTYPE2: ND_PRINT("area:%s, router-type:%s, metric-type:%s%s", - ipaddr_string(ndo, pptr+2), + GET_IPADDR_STRING(pptr+2), tok2str(bgp_extd_comm_ospf_rtype_values, "unknown (0x%02x)", GET_U_1((pptr + 6))), @@ -845,6 +891,12 @@ bgp_extended_community_print(netdissect_options *ndo, ND_PRINT("AS %u", GET_BE_U_2(pptr + 2)); break; + case BGP_EXT_COM_ENCAP: + ND_PRINT("Tunnel type: %s", tok2str(bgp_extd_comm_encap_tunnel_values, + "unknown encaps", + GET_BE_U_2(pptr + 6))); + break; + default: ND_PRINT("%02x%02x%02x%02x%02x%02x", GET_U_1(pptr + 2), @@ -857,16 +909,106 @@ bgp_extended_community_print(netdissect_options *ndo, } } +/* + * RFC4684 (Section 4)/RFC2858 (Section 4). + * RTC membership prefix is structured as follows + * [prefix-len] [origin-as] [route-target] + * The route-target is encoded as RT ext-comms. + * Prefix-len may be 0, 32..96 + * + * Note that pptr is not packet data - it is + * a buffer owned by our caller - therefore GET_* + * macros can not be used. + */ +static char * +bgp_rt_prefix_print(netdissect_options *ndo, + const u_char *pptr, + u_int plen) +{ + /* allocate space for the largest possible string */ + char rtc_prefix_in_hex[sizeof("0000 0000 0000 0000")] = ""; + u_int rtc_prefix_in_hex_len = 0; + static char output[61]; /* max response string */ + /* allocate space for the largest possible string */ + char astostr[AS_STR_SIZE]; + uint16_t ec_type = 0; + u_int octet_count; + u_int i; + + if (plen == 0) { + snprintf(output, sizeof(output), "route-target: 0:0/0"); + return (output); + } + + /* hex representation of the prefix */ + octet_count = (plen+7)/8; + for (i=0; i> (plen % 8)) & 0xff); + } + ND_PRINT("\n\t origin AS: %s, %s", + astostr, + bgp_rt_prefix_print(ndo, (u_char *)&route_target, plen)); -trunc: - return -2; + return 5 + num_octets; } static int @@ -914,7 +1062,6 @@ decode_labeled_vpn_prefix4(netdissect_options *ndo, nd_ipv4 addr; u_int plen; - ND_TCHECK_1(pptr); plen = GET_U_1(pptr); /* get prefix length */ if ((24+64) > plen) @@ -926,8 +1073,7 @@ decode_labeled_vpn_prefix4(netdissect_options *ndo, return -1; memset(&addr, 0, sizeof(addr)); - ND_TCHECK_LEN(pptr + 12, (plen + 7) / 8); - memcpy(&addr, pptr + 12, (plen + 7) / 8); + GET_CPY_BYTES(&addr, pptr + 12, (plen + 7) / 8); if (plen % 8) { ((u_char *)&addr)[(plen + 7) / 8 - 1] &= ((0xff00 >> (plen % 8)) & 0xff); @@ -941,9 +1087,6 @@ decode_labeled_vpn_prefix4(netdissect_options *ndo, ((GET_U_1(pptr + 3) & 1) == 0) ? "(BOGUS: Bottom of Stack NOT set!)" : "(bottom)" ); return 12 + (plen + 7) / 8; - -trunc: - return -2; } /* @@ -965,8 +1108,6 @@ decode_mdt_vpn_nlri(netdissect_options *ndo, const u_char *rd; const u_char *vpn_ip; - ND_TCHECK_1(pptr); - /* if the NLRI is not predefined length, quit.*/ if (GET_U_1(pptr) != MDT_VPN_NLRI_LEN * 8) return -1; @@ -978,15 +1119,12 @@ decode_mdt_vpn_nlri(netdissect_options *ndo, pptr += 8; /* IPv4 address */ - ND_TCHECK_LEN(pptr, sizeof(nd_ipv4)); vpn_ip = pptr; pptr += sizeof(nd_ipv4); /* MDT Group Address */ - ND_TCHECK_LEN(pptr, sizeof(nd_ipv4)); - snprintf(buf, buflen, "RD: %s, VPN IP Address: %s, MC Group Address: %s", - bgp_vpn_rd_print(ndo, rd), ipaddr_string(ndo, vpn_ip), ipaddr_string(ndo, pptr)); + bgp_vpn_rd_print(ndo, rd), GET_IPADDR_STRING(vpn_ip), GET_IPADDR_STRING(pptr)); return MDT_VPN_NLRI_LEN + 1; @@ -1017,11 +1155,12 @@ static int decode_multicast_vpn(netdissect_options *ndo, const u_char *pptr, char *buf, size_t buflen) { + /* allocate space for the largest possible string */ + char astostr[AS_STR_SIZE]; uint8_t route_type, route_length; u_int addr_length, sg_length; u_int offset; - ND_TCHECK_2(pptr); route_type = GET_U_1(pptr); pptr++; route_length = GET_U_1(pptr); @@ -1130,7 +1269,6 @@ decode_labeled_vpn_l2(netdissect_options *ndo, u_int plen, tlen, tlv_type, tlv_len, ttlv_len; int stringlen; - ND_TCHECK_2(pptr); plen = GET_BE_U_2(pptr); tlen = plen; pptr += 2; @@ -1144,7 +1282,7 @@ decode_labeled_vpn_l2(netdissect_options *ndo, buf[0] = '\0'; stringlen = snprintf(buf, buflen, "RD: %s, BGPNH: %s", bgp_vpn_rd_print(ndo, pptr), - ipaddr_string(ndo, pptr+8)); + GET_IPADDR_STRING(pptr+8)); UPDATE_BUF_BUFLEN(buf, buflen, stringlen); pptr += 12; tlen -= 12; @@ -1173,7 +1311,6 @@ decode_labeled_vpn_l2(netdissect_options *ndo, } return plen + 2; } - ND_TCHECK_3(pptr); tlv_type = GET_U_1(pptr); pptr++; tlv_len = GET_BE_U_2(pptr); /* length, in *bits* */ @@ -1243,7 +1380,6 @@ decode_prefix6(netdissect_options *ndo, nd_ipv6 addr; u_int plen, plenbytes; - ND_TCHECK_1(pd); ITEMCHECK(1); plen = GET_U_1(pd); if (128 < plen) @@ -1252,9 +1388,8 @@ decode_prefix6(netdissect_options *ndo, memset(&addr, 0, sizeof(addr)); plenbytes = (plen + 7) / 8; - ND_TCHECK_LEN(pd + 1, plenbytes); ITEMCHECK(plenbytes); - memcpy(&addr, pd + 1, plenbytes); + GET_CPY_BYTES(&addr, pd + 1, plenbytes); if (plen % 8) { addr[plenbytes - 1] &= ((0xff00 >> (plen % 8)) & 0xff); @@ -1262,11 +1397,8 @@ decode_prefix6(netdissect_options *ndo, snprintf(buf, buflen, "%s/%u", ip6addr_string(ndo, (const u_char *)&addr), plen); return 1 + plenbytes; -trunc: - return -2; - badtlv: - return -3; + return -2; } static int @@ -1292,8 +1424,7 @@ decode_labeled_prefix6(netdissect_options *ndo, memset(&addr, 0, sizeof(addr)); plenbytes = (plen + 7) / 8; - ND_TCHECK_LEN(pptr + 4, plenbytes); - memcpy(&addr, pptr + 4, plenbytes); + GET_CPY_BYTES(&addr, pptr + 4, plenbytes); if (plen % 8) { addr[plenbytes - 1] &= ((0xff00 >> (plen % 8)) & 0xff); @@ -1321,7 +1452,6 @@ decode_labeled_vpn_prefix6(netdissect_options *ndo, nd_ipv6 addr; u_int plen; - ND_TCHECK_1(pptr); plen = GET_U_1(pptr); /* get prefix length */ if ((24+64) > plen) @@ -1333,8 +1463,7 @@ decode_labeled_vpn_prefix6(netdissect_options *ndo, return -1; memset(&addr, 0, sizeof(addr)); - ND_TCHECK_LEN(pptr + 12, (plen + 7) / 8); - memcpy(&addr, pptr + 12, (plen + 7) / 8); + GET_CPY_BYTES(&addr, pptr + 12, (plen + 7) / 8); if (plen % 8) { addr[(plen + 7) / 8 - 1] &= ((0xff00 >> (plen % 8)) & 0xff); @@ -1348,9 +1477,6 @@ decode_labeled_vpn_prefix6(netdissect_options *ndo, ((GET_U_1(pptr + 3) & 1) == 0) ? "(BOGUS: Bottom of Stack NOT set!)" : "(bottom)" ); return 12 + (plen + 7) / 8; - -trunc: - return -2; } static int @@ -1360,27 +1486,23 @@ decode_clnp_prefix(netdissect_options *ndo, uint8_t addr[19]; u_int plen; - ND_TCHECK_1(pptr); plen = GET_U_1(pptr); /* get prefix length */ if (152 < plen) return -1; memset(&addr, 0, sizeof(addr)); - ND_TCHECK_LEN(pptr + 4, (plen + 7) / 8); - memcpy(&addr, pptr + 4, (plen + 7) / 8); + GET_CPY_BYTES(&addr, pptr + 4, (plen + 7) / 8); if (plen % 8) { addr[(plen + 7) / 8 - 1] &= ((0xff00 >> (plen % 8)) & 0xff); } + /* Cannot use GET_ISONSAP_STRING (not packet buffer pointer) */ snprintf(buf, buflen, "%s/%u", isonsap_string(ndo, addr,(plen + 7) / 8), plen); return 1 + (plen + 7) / 8; - -trunc: - return -2; } static int @@ -1390,7 +1512,6 @@ decode_labeled_vpn_clnp_prefix(netdissect_options *ndo, uint8_t addr[19]; u_int plen; - ND_TCHECK_1(pptr); plen = GET_U_1(pptr); /* get prefix length */ if ((24+64) > plen) @@ -1402,12 +1523,12 @@ decode_labeled_vpn_clnp_prefix(netdissect_options *ndo, return -1; memset(&addr, 0, sizeof(addr)); - ND_TCHECK_LEN(pptr + 12, (plen + 7) / 8); - memcpy(&addr, pptr + 12, (plen + 7) / 8); + GET_CPY_BYTES(&addr, pptr + 12, (plen + 7) / 8); if (plen % 8) { addr[(plen + 7) / 8 - 1] &= ((0xff00 >> (plen % 8)) & 0xff); } /* the label may get offsetted by 4 bits so lets shift it right */ + /* Cannot use GET_ISONSAP_STRING (not packet buffer pointer) */ snprintf(buf, buflen, "RD: %s, %s/%u, label:%u %s", bgp_vpn_rd_print(ndo, pptr+4), isonsap_string(ndo, addr,(plen + 7) / 8), @@ -1416,9 +1537,6 @@ decode_labeled_vpn_clnp_prefix(netdissect_options *ndo, ((GET_U_1(pptr + 3) & 1) == 0) ? "(BOGUS: Bottom of Stack NOT set!)" : "(bottom)" ); return 12 + (plen + 7) / 8; - -trunc: - return -2; } /* @@ -1448,15 +1566,12 @@ bgp_attr_get_as_size(netdissect_options *ndo, * each. */ while (tptr < pptr + len) { - ND_TCHECK_1(tptr); - /* * If we do not find a valid segment type, our guess might be wrong. */ if (GET_U_1(tptr) < BGP_AS_SEG_TYPE_MIN || GET_U_1(tptr) > BGP_AS_SEG_TYPE_MAX) { goto trunc; } - ND_TCHECK_1(tptr + 1); tptr += 2 + GET_U_1(tptr + 1) * 2; } @@ -1628,8 +1743,6 @@ bgp_nlri_print(netdissect_options *ndo, uint16_t af, uint8_t safi, if (advance == -1) ND_PRINT("\n\t (illegal prefix length)"); else if (advance == -2) - goto trunc; - else if (advance == -3) break; /* bytes left, but not enough */ else ND_PRINT("\n\t %s", buf); @@ -1655,15 +1768,11 @@ bgp_nlri_print(netdissect_options *ndo, uint16_t af, uint8_t safi, advance = decode_labeled_vpn_prefix4(ndo, tptr, buf, buflen); if (advance == -1) ND_PRINT("\n\t (illegal prefix length)"); - else if (advance == -2) - goto trunc; else ND_PRINT("\n\t %s", buf); break; case (AFNUM_INET<<8 | SAFNUM_RT_ROUTING_INFO): advance = decode_rt_routing_info(ndo, tptr); - if (advance == -2) - goto trunc; break; case (AFNUM_INET<<8 | SAFNUM_MULTICAST_VPN): /* fall through */ case (AFNUM_INET6<<8 | SAFNUM_MULTICAST_VPN): @@ -1696,8 +1805,6 @@ bgp_nlri_print(netdissect_options *ndo, uint16_t af, uint8_t safi, if (advance == -1) ND_PRINT("\n\t (illegal prefix length)"); else if (advance == -2) - goto trunc; - else if (advance == -3) break; /* bytes left, but not enough */ else ND_PRINT("\n\t %s", buf); @@ -1723,8 +1830,6 @@ bgp_nlri_print(netdissect_options *ndo, uint16_t af, uint8_t safi, advance = decode_labeled_vpn_prefix6(ndo, tptr, buf, buflen); if (advance == -1) ND_PRINT("\n\t (illegal prefix length)"); - else if (advance == -2) - goto trunc; else ND_PRINT("\n\t %s", buf); break; @@ -1746,8 +1851,6 @@ bgp_nlri_print(netdissect_options *ndo, uint16_t af, uint8_t safi, advance = decode_clnp_prefix(ndo, tptr, buf, buflen); if (advance == -1) ND_PRINT("\n\t (illegal prefix length)"); - else if (advance == -2) - goto trunc; else ND_PRINT("\n\t %s", buf); break; @@ -1757,8 +1860,6 @@ bgp_nlri_print(netdissect_options *ndo, uint16_t af, uint8_t safi, advance = decode_labeled_vpn_clnp_prefix(ndo, tptr, buf, buflen); if (advance == -1) ND_PRINT("\n\t (illegal prefix length)"); - else if (advance == -2) - goto trunc; else ND_PRINT("\n\t %s", buf); break; @@ -1778,8 +1879,11 @@ trunc: /* we rely on the caller to recognize -2 return value */ static int bgp_attr_print(netdissect_options *ndo, - uint8_t atype, const u_char *pptr, u_int len) + uint8_t atype, const u_char *pptr, u_int len, + const unsigned attr_set_level) { + /* allocate space for the largest possible string */ + char astostr[AS_STR_SIZE]; u_int i; uint16_t af; uint8_t safi, snpa, nhlen; @@ -1799,7 +1903,6 @@ bgp_attr_print(netdissect_options *ndo, if (len != 1) ND_PRINT("invalid len"); else { - ND_TCHECK_1(tptr); ND_PRINT("%s", tok2str(bgp_origin_values, "Unknown Origin Typecode", GET_U_1(tptr))); @@ -1831,10 +1934,8 @@ bgp_attr_print(netdissect_options *ndo, as_size = bgp_attr_get_as_size(ndo, atype, pptr, len); while (tptr < pptr + len) { - ND_TCHECK_1(tptr); ND_PRINT("%s", tok2str(bgp_as_path_segment_open_values, "?", GET_U_1(tptr))); - ND_TCHECK_1(tptr + 1); for (i = 0; i < GET_U_1(tptr + 1) * as_size; i += as_size) { ND_TCHECK_LEN(tptr + 2 + i, as_size); ND_PRINT("%s ", @@ -1843,10 +1944,8 @@ bgp_attr_print(netdissect_options *ndo, GET_BE_U_2(tptr + i + 2) : GET_BE_U_4(tptr + i + 2))); } - ND_TCHECK_1(tptr); ND_PRINT("%s", tok2str(bgp_as_path_segment_close_values, "?", GET_U_1(tptr))); - ND_TCHECK_1(tptr + 1); tptr += 2 + GET_U_1(tptr + 1) * as_size; } break; @@ -1854,8 +1953,7 @@ bgp_attr_print(netdissect_options *ndo, if (len != 4) ND_PRINT("invalid len"); else { - ND_TCHECK_4(tptr); - ND_PRINT("%s", ipaddr_string(ndo, tptr)); + ND_PRINT("%s", GET_IPADDR_STRING(tptr)); } break; case BGPTYPE_MULTI_EXIT_DISC: @@ -1863,7 +1961,6 @@ bgp_attr_print(netdissect_options *ndo, if (len != 4) ND_PRINT("invalid len"); else { - ND_TCHECK_4(tptr); ND_PRINT("%u", GET_BE_U_4(tptr)); } break; @@ -1885,11 +1982,11 @@ bgp_attr_print(netdissect_options *ndo, if (len == 6) { ND_PRINT(" AS #%s, origin %s", as_printf(ndo, astostr, sizeof(astostr), GET_BE_U_2(tptr)), - ipaddr_string(ndo, tptr + 2)); + GET_IPADDR_STRING(tptr + 2)); } else { ND_PRINT(" AS #%s, origin %s", as_printf(ndo, astostr, sizeof(astostr), - GET_BE_U_4(tptr)), ipaddr_string(ndo, tptr + 4)); + GET_BE_U_4(tptr)), GET_IPADDR_STRING(tptr + 4)); } break; case BGPTYPE_AGGREGATOR4: @@ -1897,10 +1994,9 @@ bgp_attr_print(netdissect_options *ndo, ND_PRINT("invalid len"); break; } - ND_TCHECK_8(tptr); ND_PRINT(" AS #%s, origin %s", as_printf(ndo, astostr, sizeof(astostr), GET_BE_U_4(tptr)), - ipaddr_string(ndo, tptr + 4)); + GET_IPADDR_STRING(tptr + 4)); break; case BGPTYPE_COMMUNITIES: if (len % 4) { @@ -1939,8 +2035,7 @@ bgp_attr_print(netdissect_options *ndo, ND_PRINT("invalid len"); break; } - ND_TCHECK_4(tptr); - ND_PRINT("%s",ipaddr_string(ndo, tptr)); + ND_PRINT("%s",GET_IPADDR_STRING(tptr)); break; case BGPTYPE_CLUSTER_LIST: if (len % 4) { @@ -1948,11 +2043,10 @@ bgp_attr_print(netdissect_options *ndo, break; } while (tlen != 0) { - ND_TCHECK_4(tptr); if (tlen < 4) goto trunc; ND_PRINT("%s%s", - ipaddr_string(ndo, tptr), + GET_IPADDR_STRING(tptr), (tlen>4) ? ", " : ""); tlen -=4; tptr +=4; @@ -1968,17 +2062,23 @@ bgp_attr_print(netdissect_options *ndo, if (ret < 0) break; - tptr +=3; + tptr += 3; + tlen -= 3; ND_TCHECK_1(tptr); + if (tlen < 1) + goto trunc; nhlen = GET_U_1(tptr); - tlen = nhlen; tptr++; + tlen--; - if (tlen) { + if (nhlen) { u_int nnh = 0; + uint8_t tnhlen = nhlen; + if (tlen < tnhlen) + goto trunc; ND_PRINT("\n\t nexthop: "); - while (tlen != 0) { + while (tnhlen != 0) { if (nnh++ > 0) { ND_PRINT(", " ); } @@ -1990,104 +2090,115 @@ bgp_attr_print(netdissect_options *ndo, case (AFNUM_INET<<8 | SAFNUM_RT_ROUTING_INFO): case (AFNUM_INET<<8 | SAFNUM_MULTICAST_VPN): case (AFNUM_INET<<8 | SAFNUM_MDT): - if (tlen < sizeof(nd_ipv4)) { + if (tnhlen < sizeof(nd_ipv4)) { ND_PRINT("invalid len"); - tlen = 0; + tptr += tnhlen; + tlen -= tnhlen; + tnhlen = 0; } else { - ND_TCHECK_LEN(tptr, sizeof(nd_ipv4)); - ND_PRINT("%s",ipaddr_string(ndo, tptr)); - tlen -= sizeof(nd_ipv4); + ND_PRINT("%s",GET_IPADDR_STRING(tptr)); tptr += sizeof(nd_ipv4); + tnhlen -= sizeof(nd_ipv4); + tlen -= sizeof(nd_ipv4); } break; case (AFNUM_INET<<8 | SAFNUM_VPNUNICAST): case (AFNUM_INET<<8 | SAFNUM_VPNMULTICAST): case (AFNUM_INET<<8 | SAFNUM_VPNUNIMULTICAST): - if (tlen < sizeof(nd_ipv4)+BGP_VPN_RD_LEN) { + if (tnhlen < sizeof(nd_ipv4)+BGP_VPN_RD_LEN) { ND_PRINT("invalid len"); - tlen = 0; + tptr += tnhlen; + tlen -= tnhlen; + tnhlen = 0; } else { - ND_TCHECK_LEN(tptr, - sizeof(nd_ipv4) + BGP_VPN_RD_LEN); ND_PRINT("RD: %s, %s", bgp_vpn_rd_print(ndo, tptr), - ipaddr_string(ndo, tptr+BGP_VPN_RD_LEN)); - tlen -= (sizeof(nd_ipv4)+BGP_VPN_RD_LEN); + GET_IPADDR_STRING(tptr+BGP_VPN_RD_LEN)); tptr += (sizeof(nd_ipv4)+BGP_VPN_RD_LEN); + tlen -= (sizeof(nd_ipv4)+BGP_VPN_RD_LEN); + tnhlen -= (sizeof(nd_ipv4)+BGP_VPN_RD_LEN); } break; case (AFNUM_INET6<<8 | SAFNUM_UNICAST): case (AFNUM_INET6<<8 | SAFNUM_MULTICAST): case (AFNUM_INET6<<8 | SAFNUM_UNIMULTICAST): case (AFNUM_INET6<<8 | SAFNUM_LABUNICAST): - if (tlen < sizeof(nd_ipv6)) { + if (tnhlen < sizeof(nd_ipv6)) { ND_PRINT("invalid len"); - tlen = 0; + tptr += tnhlen; + tlen -= tnhlen; + tnhlen = 0; } else { - ND_TCHECK_LEN(tptr, sizeof(nd_ipv6)); - ND_PRINT("%s", ip6addr_string(ndo, tptr)); - tlen -= sizeof(nd_ipv6); + ND_PRINT("%s", GET_IP6ADDR_STRING(tptr)); tptr += sizeof(nd_ipv6); + tlen -= sizeof(nd_ipv6); + tnhlen -= sizeof(nd_ipv6); } break; case (AFNUM_INET6<<8 | SAFNUM_VPNUNICAST): case (AFNUM_INET6<<8 | SAFNUM_VPNMULTICAST): case (AFNUM_INET6<<8 | SAFNUM_VPNUNIMULTICAST): - if (tlen < sizeof(nd_ipv6)+BGP_VPN_RD_LEN) { + if (tnhlen < sizeof(nd_ipv6)+BGP_VPN_RD_LEN) { ND_PRINT("invalid len"); - tlen = 0; + tptr += tnhlen; + tlen -= tnhlen; + tnhlen = 0; } else { - ND_TCHECK_LEN(tptr, - sizeof(nd_ipv6) + BGP_VPN_RD_LEN); ND_PRINT("RD: %s, %s", bgp_vpn_rd_print(ndo, tptr), - ip6addr_string(ndo, tptr+BGP_VPN_RD_LEN)); - tlen -= (sizeof(nd_ipv6)+BGP_VPN_RD_LEN); + GET_IP6ADDR_STRING(tptr+BGP_VPN_RD_LEN)); tptr += (sizeof(nd_ipv6)+BGP_VPN_RD_LEN); + tlen -= (sizeof(nd_ipv6)+BGP_VPN_RD_LEN); + tnhlen -= (sizeof(nd_ipv6)+BGP_VPN_RD_LEN); } break; case (AFNUM_VPLS<<8 | SAFNUM_VPLS): case (AFNUM_L2VPN<<8 | SAFNUM_VPNUNICAST): case (AFNUM_L2VPN<<8 | SAFNUM_VPNMULTICAST): case (AFNUM_L2VPN<<8 | SAFNUM_VPNUNIMULTICAST): - if (tlen < sizeof(nd_ipv4)) { + if (tnhlen < sizeof(nd_ipv4)) { ND_PRINT("invalid len"); - tlen = 0; + tptr += tnhlen; + tlen -= tnhlen; + tnhlen = 0; } else { - ND_TCHECK_LEN(tptr, sizeof(nd_ipv4)); - ND_PRINT("%s", ipaddr_string(ndo, tptr)); - tlen -= (sizeof(nd_ipv4)); + ND_PRINT("%s", GET_IPADDR_STRING(tptr)); tptr += (sizeof(nd_ipv4)); + tlen -= (sizeof(nd_ipv4)); + tnhlen -= (sizeof(nd_ipv4)); } break; case (AFNUM_NSAP<<8 | SAFNUM_UNICAST): case (AFNUM_NSAP<<8 | SAFNUM_MULTICAST): case (AFNUM_NSAP<<8 | SAFNUM_UNIMULTICAST): - ND_TCHECK_LEN(tptr, tlen); - ND_PRINT("%s", isonsap_string(ndo, tptr, tlen)); - tptr += tlen; - tlen = 0; + ND_PRINT("%s", GET_ISONSAP_STRING(tptr, tnhlen)); + tptr += tnhlen; + tlen -= tnhlen; + tnhlen = 0; break; case (AFNUM_NSAP<<8 | SAFNUM_VPNUNICAST): case (AFNUM_NSAP<<8 | SAFNUM_VPNMULTICAST): case (AFNUM_NSAP<<8 | SAFNUM_VPNUNIMULTICAST): - if (tlen < BGP_VPN_RD_LEN+1) { + if (tnhlen < BGP_VPN_RD_LEN+1) { ND_PRINT("invalid len"); - tlen = 0; + tptr += tnhlen; + tlen -= tnhlen; + tnhlen = 0; } else { - ND_TCHECK_LEN(tptr, tlen); + ND_TCHECK_LEN(tptr, tnhlen); ND_PRINT("RD: %s, %s", bgp_vpn_rd_print(ndo, tptr), - isonsap_string(ndo, tptr+BGP_VPN_RD_LEN,tlen-BGP_VPN_RD_LEN)); + GET_ISONSAP_STRING(tptr+BGP_VPN_RD_LEN,tnhlen-BGP_VPN_RD_LEN)); /* rfc986 mapped IPv4 address ? */ if (GET_BE_U_4(tptr + BGP_VPN_RD_LEN) == 0x47000601) - ND_PRINT(" = %s", ipaddr_string(ndo, tptr+BGP_VPN_RD_LEN+4)); + ND_PRINT(" = %s", GET_IPADDR_STRING(tptr+BGP_VPN_RD_LEN+4)); /* rfc1888 mapped IPv6 address ? */ else if (GET_BE_U_3(tptr + BGP_VPN_RD_LEN) == 0x350000) - ND_PRINT(" = %s", ip6addr_string(ndo, tptr+BGP_VPN_RD_LEN+3)); - tptr += tlen; - tlen = 0; + ND_PRINT(" = %s", GET_IP6ADDR_STRING(tptr+BGP_VPN_RD_LEN+3)); + tptr += tnhlen; + tlen -= tnhlen; + tnhlen = 0; } break; default: @@ -2096,26 +2207,38 @@ bgp_attr_print(netdissect_options *ndo, * an unsupported AFI/SAFI. */ ND_PRINT("ERROR: no AFI %u/SAFI %u nexthop decoder", af, safi); - tptr += tlen; - tlen = 0; + tptr += tnhlen; + tlen -= tnhlen; + tnhlen = 0; goto done; break; } } } ND_PRINT(", nh-length: %u", nhlen); - tptr += tlen; - ND_TCHECK_1(tptr); + /* As per RFC 2858; this is reserved in RFC 4760 */ + if (tlen < 1) + goto trunc; snpa = GET_U_1(tptr); tptr++; + tlen--; if (snpa) { ND_PRINT("\n\t %u SNPA", snpa); for (/*nothing*/; snpa != 0; snpa--) { - ND_TCHECK_1(tptr); - ND_PRINT("\n\t %u bytes", GET_U_1(tptr)); - tptr += GET_U_1(tptr) + 1; + uint8_t snpalen; + if (tlen < 1) + goto trunc; + snpalen = GET_U_1(tptr); + ND_PRINT("\n\t %u bytes", snpalen); + tptr++; + tlen--; + if (tlen < snpalen) + goto trunc; + ND_TCHECK_LEN(tptr, snpalen); + tptr += snpalen; + tlen -= snpalen; } } else { ND_PRINT(", no SNPA"); @@ -2200,7 +2323,6 @@ bgp_attr_print(netdissect_options *ndo, goto trunc; flags = GET_U_1(tptr); tunnel_type = GET_U_1(tptr + 1); - tlen = len; ND_PRINT("\n\t Tunnel-type %s (%u), Flags [%s], MPLS Label %u", tok2str(bgp_pmsi_tunnel_values, "Unknown", tunnel_type), @@ -2214,34 +2336,29 @@ bgp_attr_print(netdissect_options *ndo, switch (tunnel_type) { case BGP_PMSI_TUNNEL_PIM_SM: /* fall through */ case BGP_PMSI_TUNNEL_PIM_BIDIR: - ND_TCHECK_8(tptr); ND_PRINT("\n\t Sender %s, P-Group %s", - ipaddr_string(ndo, tptr), - ipaddr_string(ndo, tptr+4)); + GET_IPADDR_STRING(tptr), + GET_IPADDR_STRING(tptr+4)); break; case BGP_PMSI_TUNNEL_PIM_SSM: - ND_TCHECK_8(tptr); ND_PRINT("\n\t Root-Node %s, P-Group %s", - ipaddr_string(ndo, tptr), - ipaddr_string(ndo, tptr+4)); + GET_IPADDR_STRING(tptr), + GET_IPADDR_STRING(tptr+4)); break; case BGP_PMSI_TUNNEL_INGRESS: - ND_TCHECK_4(tptr); ND_PRINT("\n\t Tunnel-Endpoint %s", - ipaddr_string(ndo, tptr)); + GET_IPADDR_STRING(tptr)); break; case BGP_PMSI_TUNNEL_LDP_P2MP: /* fall through */ case BGP_PMSI_TUNNEL_LDP_MP2MP: - ND_TCHECK_8(tptr); ND_PRINT("\n\t Root-Node %s, LSP-ID 0x%08x", - ipaddr_string(ndo, tptr), + GET_IPADDR_STRING(tptr), GET_BE_U_4(tptr + 4)); break; case BGP_PMSI_TUNNEL_RSVP_P2MP: - ND_TCHECK_8(tptr); ND_PRINT("\n\t Extended-Tunnel-ID %s, P2MP-ID 0x%08x", - ipaddr_string(ndo, tptr), + GET_IPADDR_STRING(tptr), GET_BE_U_4(tptr + 4)); break; default: @@ -2256,12 +2373,7 @@ bgp_attr_print(netdissect_options *ndo, uint8_t type; uint16_t length; - tlen = len; - while (tlen >= 3) { - - ND_TCHECK_3(tptr); - type = GET_U_1(tptr); length = GET_BE_U_2(tptr + 1); tptr += 3; @@ -2278,7 +2390,6 @@ bgp_attr_print(netdissect_options *ndo, /* * Check if we can read the TLV data. */ - ND_TCHECK_LEN(tptr + 3, length); if (tlen < length) goto trunc; @@ -2357,8 +2468,18 @@ bgp_attr_print(netdissect_options *ndo, tptr += len; break; } - /* FIXME check for recursion */ - if (!bgp_attr_print(ndo, atype, tptr, alen)) + /* + * The protocol encoding per se allows ATTR_SET to be nested + * as many times as the message can accommodate. This printer + * used to be able to recurse into ATTR_SET contents until the + * stack exhaustion, but now there is a limit on that (if live + * protocol exchange goes that many levels deep, something is + * probably wrong anyway). Feel free to refine this value if + * you can find the spec with respective normative text. + */ + if (attr_set_level == 10) + ND_PRINT("(too many nested levels, not recursing)"); + else if (!bgp_attr_print(ndo, atype, tptr, alen, attr_set_level + 1)) return 0; tptr += alen; len -= alen; @@ -2372,7 +2493,6 @@ bgp_attr_print(netdissect_options *ndo, } ND_PRINT("\n\t "); while (len != 0) { - ND_TCHECK_LEN(tptr, 12); ND_PRINT("%u:%u:%u%s", GET_BE_U_4(tptr), GET_BE_U_4(tptr + 4), @@ -2408,6 +2528,8 @@ static void bgp_capabilities_print(netdissect_options *ndo, const u_char *opt, u_int caps_len) { + /* allocate space for the largest possible string */ + char astostr[AS_STR_SIZE]; u_int cap_type, cap_len, tcap_len, cap_offset; u_int i = 0; @@ -2477,6 +2599,8 @@ bgp_capabilities_print(netdissect_options *ndo, case BGP_CAPCODE_RR: case BGP_CAPCODE_LLGR: case BGP_CAPCODE_RR_CISCO: + case BGP_CAPCODE_EXT_MSG: + case BGP_CAPCODE_ENH_RR: break; case BGP_CAPCODE_AS_NEW: /* @@ -2536,11 +2660,17 @@ static void bgp_open_print(netdissect_options *ndo, const u_char *dat, u_int length) { + /* allocate space for the largest possible string */ + char astostr[AS_STR_SIZE]; const struct bgp_open *bgp_open_header; u_int optslen; + uint8_t opsttype; const struct bgp_opt *bgpopt; const u_char *opt; u_int i; + uint8_t extended_opt_params = 0; + u_int open_size = BGP_OPEN_SIZE; + u_int opt_size = BGP_OPT_SIZE; ND_TCHECK_LEN(dat, BGP_OPEN_SIZE); if (length < BGP_OPEN_SIZE) @@ -2554,24 +2684,34 @@ bgp_open_print(netdissect_options *ndo, as_printf(ndo, astostr, sizeof(astostr), GET_BE_U_2(bgp_open_header->bgpo_myas))); ND_PRINT("Holdtime %us, ", GET_BE_U_2(bgp_open_header->bgpo_holdtime)); - ND_PRINT("ID %s", ipaddr_string(ndo, bgp_open_header->bgpo_id)); + ND_PRINT("ID %s", GET_IPADDR_STRING(bgp_open_header->bgpo_id)); optslen = GET_U_1(bgp_open_header->bgpo_optlen); - ND_PRINT("\n\t Optional parameters, length: %u", optslen); + opsttype = GET_U_1(bgp_open_header->bgpo_opttype); + if (opsttype == BGP_OPEN_NON_EXT_OPT_TYPE_EXTENDED_LENGTH) { + optslen = GET_BE_U_2(bgp_open_header->bgpo_optlen_extended); + extended_opt_params = 1; + open_size += 3; + opt_size += 1; + } + ND_PRINT("\n\t Optional parameters%s, length: %u", + extended_opt_params ? " (Extended)" : "", optslen); - opt = dat + BGP_OPEN_SIZE; - length -= BGP_OPEN_SIZE; + opt = dat + open_size; + length -= open_size; i = 0; while (i < optslen) { - uint8_t opt_type, opt_len; + uint8_t opt_type; + uint16_t opt_len; - ND_TCHECK_LEN(opt + i, BGP_OPT_SIZE); - if (length < BGP_OPT_SIZE + i) + ND_TCHECK_LEN(opt + i, opt_size); + if (length < opt_size + i) goto trunc; bgpopt = (const struct bgp_opt *)(opt + i); opt_type = GET_U_1(bgpopt->bgpopt_type); - opt_len = GET_U_1(bgpopt->bgpopt_len); - if (BGP_OPT_SIZE + i + opt_len > optslen) { + opt_len = extended_opt_params ? GET_BE_U_2(bgpopt->bgpopt_len) + : GET_U_1(bgpopt->bgpopt_len); + if (opt_size + i + opt_len > optslen) { ND_PRINT("\n\t Option %u, length: %u, goes past the end of the options", opt_type, opt_len); break; @@ -2586,7 +2726,7 @@ bgp_open_print(netdissect_options *ndo, switch(opt_type) { case BGP_OPT_CAP: - bgp_capabilities_print(ndo, opt + BGP_OPT_SIZE + i, + bgp_capabilities_print(ndo, opt + opt_size + i, opt_len); break; @@ -2596,7 +2736,7 @@ bgp_open_print(netdissect_options *ndo, opt_type); break; } - i += BGP_OPT_SIZE + opt_len; + i += opt_size + opt_len; } return; trunc: @@ -2657,8 +2797,6 @@ bgp_update_print(netdissect_options *ndo, ND_PRINT("\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("\n\t %s", buf); @@ -2692,6 +2830,9 @@ bgp_update_print(netdissect_options *ndo, } if (len) { + /* Make sure the path attributes don't go past the end of the packet */ + if (length < len) + goto trunc; /* do something more useful!*/ while (len) { uint8_t aflags, atype, alenlen; @@ -2749,7 +2890,7 @@ bgp_update_print(netdissect_options *ndo, } if (length < alen) goto trunc; - if (!bgp_attr_print(ndo, atype, p, alen)) + if (!bgp_attr_print(ndo, atype, p, alen, 0)) goto trunc; p += alen; len -= alen; @@ -2774,8 +2915,6 @@ bgp_update_print(netdissect_options *ndo, ND_PRINT("\n\t (illegal prefix length)"); break; } else if (i == -2) - goto trunc; - else if (i == -3) goto trunc; /* bytes left, but not enough */ else { ND_PRINT("\n\t %s", buf); @@ -2799,8 +2938,6 @@ bgp_notification_print(netdissect_options *ndo, const struct bgp_notification *bgp_notification_header; const u_char *tptr; uint8_t bgpn_major, bgpn_minor; - uint8_t shutdown_comm_length; - uint8_t remainder_offset; ND_TCHECK_LEN(dat, BGP_NOTIFICATION_SIZE); if (length= BGP_NOTIFICATION_SIZE + 7) { tptr = dat + BGP_NOTIFICATION_SIZE; - ND_TCHECK_7(tptr); ND_PRINT(", AFI %s (%u), SAFI %s (%u), Max Prefixes: %u", tok2str(af_values, "Unknown", GET_BE_U_2(tptr)), GET_BE_U_2(tptr), @@ -2867,19 +3003,17 @@ bgp_notification_print(netdissect_options *ndo, GET_BE_U_4(tptr + 3)); } /* - * draft-ietf-idr-shutdown describes a method to send a communication + * RFC 9003 describes a method to send a communication * intended for human consumption regarding the Administrative Shutdown */ if ((bgpn_minor == BGP_NOTIFY_MINOR_CEASE_SHUT || bgpn_minor == BGP_NOTIFY_MINOR_CEASE_RESET) && length >= BGP_NOTIFICATION_SIZE + 1) { tptr = dat + BGP_NOTIFICATION_SIZE; - ND_TCHECK_1(tptr); - shutdown_comm_length = GET_U_1(tptr); - remainder_offset = 0; + uint8_t shutdown_comm_length = GET_U_1(tptr); + uint8_t remainder_offset = 0; /* garbage, hexdump it all */ - if (shutdown_comm_length > BGP_NOTIFY_MINOR_CEASE_ADMIN_SHUTDOWN_LEN || - shutdown_comm_length > length - (BGP_NOTIFICATION_SIZE + 1)) { + if (shutdown_comm_length > length - (BGP_NOTIFICATION_SIZE + 1)) { ND_PRINT(", invalid Shutdown Communication length"); } else if (shutdown_comm_length == 0) { @@ -2888,9 +3022,8 @@ bgp_notification_print(netdissect_options *ndo, } /* a proper shutdown communication */ else { - ND_TCHECK_LEN(tptr + 1, shutdown_comm_length); ND_PRINT(", Shutdown Communication (length: %u): \"", shutdown_comm_length); - (void)nd_printn(ndo, tptr+1, shutdown_comm_length, NULL); + nd_printjn(ndo, tptr+1, shutdown_comm_length); ND_PRINT("\""); remainder_offset += shutdown_comm_length + 1; } @@ -2924,13 +3057,16 @@ bgp_route_refresh_print(netdissect_options *ndo, bgp_route_refresh_header = (const struct bgp_route_refresh *)pptr; - ND_PRINT("\n\t AFI %s (%u), SAFI %s (%u)", - tok2str(af_values,"Unknown", - GET_BE_U_2(bgp_route_refresh_header->afi)), - GET_BE_U_2(bgp_route_refresh_header->afi), - tok2str(bgp_safi_values,"Unknown", - GET_U_1(bgp_route_refresh_header->safi)), - GET_U_1(bgp_route_refresh_header->safi)); + ND_PRINT("\n\t AFI %s (%u), SAFI %s (%u), Subtype %s (%u)", + tok2str(af_values, "Unknown", + GET_BE_U_2(bgp_route_refresh_header->afi)), + GET_BE_U_2(bgp_route_refresh_header->afi), + tok2str(bgp_safi_values, "Unknown", + GET_U_1(bgp_route_refresh_header->safi)), + GET_U_1(bgp_route_refresh_header->safi), + tok2str(bgp_route_refresh_subtype_values, "Unknown", + GET_U_1(bgp_route_refresh_header->subtype)), + GET_U_1(bgp_route_refresh_header->subtype)); if (ndo->ndo_vflag > 1) { ND_TCHECK_LEN(pptr, len);