X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/124d025a425a4184a2e57ce2faa507a438f6d204..6d3b0e4599c5aa922bba42e53b038b51d9024a62:/print-bgp.c diff --git a/print-bgp.c b/print-bgp.c index 88ade46d..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,12 +224,15 @@ 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 static const struct tok bgp_capcode_values[] = { @@ -230,12 +241,15 @@ 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"}, { BGP_CAPCODE_DYN_CAP, "Dynamic Capability"}, { BGP_CAPCODE_MULTISESS, "Multisession BGP"}, { BGP_CAPCODE_ADD_PATH, "Multiple Paths"}, { BGP_CAPCODE_ENH_RR, "Enhanced Route Refresh"}, + { BGP_CAPCODE_LLGR, "Long-lived Graceful Restart"}, { BGP_CAPCODE_RR_CISCO, "Route Refresh (Cisco)"}, { 0, NULL} }; @@ -259,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"}, @@ -378,6 +390,8 @@ static const struct tok bgp_aigp_values[] = { #define SAFNUM_VPLS 65 /* RFC6037 */ #define SAFNUM_MDT 66 +/* RFC7432 */ +#define SAFNUM_EVPN 70 /* RFC4364 */ #define SAFNUM_VPNUNICAST 128 /* RFC6513 */ @@ -397,6 +411,7 @@ static const struct tok bgp_safi_values[] = { { SAFNUM_TUNNEL, "Tunnel"}, { SAFNUM_VPLS, "VPLS"}, { SAFNUM_MDT, "MDT"}, + { SAFNUM_EVPN, "EVPN"}, { SAFNUM_VPNUNICAST, "labeled VPN Unicast"}, { SAFNUM_VPNMULTICAST, "labeled VPN Multicast"}, { SAFNUM_VPNUNIMULTICAST, "labeled VPN Unicast+Multicast"}, @@ -426,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 */ @@ -437,7 +453,7 @@ static const struct tok bgp_safi_values[] = { #define BGP_EXT_COM_L2VPN_RT_0 0x000a /* L2VPN Identifier,Format AS(2bytes):AN(4bytes) */ #define BGP_EXT_COM_L2VPN_RT_1 0xF10a /* L2VPN Identifier,Format IP address:AN(2bytes) */ -/* http://www.cisco.com/en/US/tech/tk436/tk428/technologies_tech_note09186a00801eb09a.shtml */ +/* https://www.cisco.com/en/US/tech/tk436/tk428/technologies_tech_note09186a00801eb09a.shtml */ #define BGP_EXT_COM_EIGRP_GEN 0x8800 #define BGP_EXT_COM_EIGRP_METRIC_AS_DELAY 0x8801 #define BGP_EXT_COM_EIGRP_METRIC_REL_NH_BW 0x8802 @@ -445,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"}, @@ -465,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"}, @@ -481,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 */ @@ -508,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 @@ -524,9 +584,9 @@ as_printf(netdissect_options *ndo, char *str, size_t size, u_int asnum) { if (!ndo->ndo_bflag || asnum <= 0xFFFF) { - nd_snprintf(str, size, "%u", asnum); + snprintf(str, size, "%u", asnum); } else { - nd_snprintf(str, size, "%u.%u", asnum >> 16, asnum & 0xFFFF); + snprintf(str, size, "%u.%u", asnum >> 16, asnum & 0xFFFF); } return str; } @@ -537,10 +597,9 @@ int decode_prefix4(netdissect_options *ndo, const u_char *pptr, u_int itemlen, char *buf, size_t buflen) { - struct in_addr addr; + nd_ipv4 addr; u_int plen, plenbytes; - ND_TCHECK_1(pptr); ITEMCHECK(1); plen = GET_U_1(pptr); if (32 < plen) @@ -549,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); } - nd_snprintf(buf, buflen, "%s/%u", ipaddr_string(ndo, (const u_char *)&addr), plen); + 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 @@ -570,7 +625,7 @@ decode_labeled_prefix4(netdissect_options *ndo, const u_char *pptr, u_int itemlen, char *buf, size_t buflen) { - struct in_addr addr; + nd_ipv4 addr; u_int plen, plenbytes; /* prefix length and label = 4 bytes */ @@ -597,14 +652,13 @@ 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); } /* the label may get offsetted by 4 bits so lets shift it right */ - nd_snprintf(buf, buflen, "%s/%u, label:%u %s", + snprintf(buf, buflen, "%s/%u, label:%u %s", ipaddr_string(ndo, (const u_char *)&addr), plen, GET_BE_U_3(pptr + 1)>>4, @@ -622,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, @@ -635,20 +689,17 @@ bgp_vpn_ip_print(netdissect_options *ndo, switch(addr_length) { case (sizeof(nd_ipv4) << 3): /* 32 */ - ND_TCHECK_LEN(pptr, sizeof(nd_ipv4)); - nd_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)); - nd_snprintf(pos, sizeof(addr), "%s", ip6addr_string(ndo, pptr)); + snprintf(pos, sizeof(addr), "%s", GET_IP6ADDR_STRING(pptr)); break; default: - nd_snprintf(pos, sizeof(addr), "bogus address length %u", addr_length); + snprintf(pos, sizeof(addr), "bogus address length %u", addr_length); break; } pos += strlen(pos); -trunc: *(pos) = '\0'; return (addr); } @@ -681,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++; @@ -690,13 +740,12 @@ bgp_vpn_sg_print(netdissect_options *ndo, total_length += (addr_length >> 3) + 1; offset = (u_int)strlen(buf); if (addr_length) { - nd_snprintf(buf + offset, buflen - offset, ", Source %s", + snprintf(buf + offset, buflen - offset, ", Source %s", bgp_vpn_ip_print(ndo, pptr, addr_length)); pptr += (addr_length >> 3); } /* Group address length, encoded in bits */ - ND_TCHECK_1(pptr); addr_length = GET_U_1(pptr); pptr++; @@ -705,7 +754,7 @@ bgp_vpn_sg_print(netdissect_options *ndo, total_length += (addr_length >> 3) + 1; offset = (u_int)strlen(buf); if (addr_length) { - nd_snprintf(buf + offset, buflen - offset, ", Group %s", + snprintf(buf + offset, buflen - offset, ", Group %s", bgp_vpn_ip_print(ndo, pptr, addr_length)); pptr += (addr_length >> 3); } @@ -720,15 +769,17 @@ 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)) { case 0: /* 2-byte-AS:number fmt */ - nd_snprintf(pos, sizeof(rd) - (pos - rd), "%u:%u (= %u.%u.%u.%u)", + snprintf(pos, sizeof(rd) - (pos - rd), "%u:%u (= %u.%u.%u.%u)", GET_BE_U_2(pptr + 2), GET_BE_U_4(pptr + 4), GET_U_1(pptr + 4), GET_U_1(pptr + 5), @@ -737,7 +788,7 @@ bgp_vpn_rd_print(netdissect_options *ndo, case 1: /* IP-address:AS fmt */ - nd_snprintf(pos, sizeof(rd) - (pos - rd), "%u.%u.%u.%u:%u", + snprintf(pos, sizeof(rd) - (pos - rd), "%u.%u.%u.%u:%u", GET_U_1(pptr + 2), GET_U_1(pptr + 3), GET_U_1(pptr + 4), GET_U_1(pptr + 5), GET_BE_U_2(pptr + 6)); @@ -745,14 +796,14 @@ bgp_vpn_rd_print(netdissect_options *ndo, case 2: /* 4-byte-AS:number fmt */ - nd_snprintf(pos, sizeof(rd) - (pos - rd), "%s:%u (%u.%u.%u.%u:%u)", + snprintf(pos, sizeof(rd) - (pos - rd), "%s:%u (%u.%u.%u.%u:%u)", as_printf(ndo, astostr, sizeof(astostr), GET_BE_U_4(pptr + 2)), GET_BE_U_2(pptr + 6), GET_U_1(pptr + 2), GET_U_1(pptr + 3), GET_U_1(pptr + 4), GET_U_1(pptr + 5), GET_BE_U_2(pptr + 6)); break; default: - nd_snprintf(pos, sizeof(rd) - (pos - rd), "unknown RD format"); + snprintf(pos, sizeof(rd) - (pos - rd), "unknown RD format"); break; } pos += strlen(pos); @@ -771,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)) { @@ -780,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: @@ -788,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; @@ -800,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; @@ -811,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))), @@ -838,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), @@ -850,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 decode_labeled_vpn_prefix4(netdissect_options *ndo, const u_char *pptr, char *buf, size_t buflen) { - struct in_addr addr; + nd_ipv4 addr; u_int plen; - ND_TCHECK_1(pptr); plen = GET_U_1(pptr); /* get prefix length */ if ((24+64) > plen) @@ -919,14 +1073,13 @@ 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); } /* the label may get offsetted by 4 bits so lets shift it right */ - nd_snprintf(buf, buflen, "RD: %s, %s/%u, label:%u %s", + snprintf(buf, buflen, "RD: %s, %s/%u, label:%u %s", bgp_vpn_rd_print(ndo, pptr+4), ipaddr_string(ndo, (const u_char *)&addr), plen, @@ -934,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; } /* @@ -958,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; @@ -971,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)); - - nd_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)); + snprintf(buf, buflen, "RD: %s, VPN IP Address: %s, MC Group Address: %s", + bgp_vpn_rd_print(ndo, rd), GET_IPADDR_STRING(vpn_ip), GET_IPADDR_STRING(pptr)); return MDT_VPN_NLRI_LEN + 1; @@ -1010,17 +1155,18 @@ 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); pptr++; - nd_snprintf(buf, buflen, "Route-Type: %s (%u), length: %u", + snprintf(buf, buflen, "Route-Type: %s (%u), length: %u", tok2str(bgp_multicast_vpn_route_type_values, "Unknown", route_type), route_type, route_length); @@ -1029,7 +1175,7 @@ decode_multicast_vpn(netdissect_options *ndo, case BGP_MULTICAST_VPN_ROUTE_TYPE_INTRA_AS_I_PMSI: ND_TCHECK_LEN(pptr, BGP_VPN_RD_LEN); offset = (u_int)strlen(buf); - nd_snprintf(buf + offset, buflen - offset, ", RD: %s, Originator %s", + snprintf(buf + offset, buflen - offset, ", RD: %s, Originator %s", bgp_vpn_rd_print(ndo, pptr), bgp_vpn_ip_print(ndo, pptr + BGP_VPN_RD_LEN, (route_length - BGP_VPN_RD_LEN) << 3)); @@ -1037,7 +1183,7 @@ decode_multicast_vpn(netdissect_options *ndo, case BGP_MULTICAST_VPN_ROUTE_TYPE_INTER_AS_I_PMSI: ND_TCHECK_LEN(pptr, BGP_VPN_RD_LEN + 4); offset = (u_int)strlen(buf); - nd_snprintf(buf + offset, buflen - offset, ", RD: %s, Source-AS %s", + snprintf(buf + offset, buflen - offset, ", RD: %s, Source-AS %s", bgp_vpn_rd_print(ndo, pptr), as_printf(ndo, astostr, sizeof(astostr), GET_BE_U_4(pptr + BGP_VPN_RD_LEN))); @@ -1046,7 +1192,7 @@ decode_multicast_vpn(netdissect_options *ndo, case BGP_MULTICAST_VPN_ROUTE_TYPE_S_PMSI: ND_TCHECK_LEN(pptr, BGP_VPN_RD_LEN); offset = (u_int)strlen(buf); - nd_snprintf(buf + offset, buflen - offset, ", RD: %s", + snprintf(buf + offset, buflen - offset, ", RD: %s", bgp_vpn_rd_print(ndo, pptr)); pptr += BGP_VPN_RD_LEN; @@ -1055,14 +1201,14 @@ decode_multicast_vpn(netdissect_options *ndo, ND_TCHECK_LEN(pptr, addr_length); offset = (u_int)strlen(buf); - nd_snprintf(buf + offset, buflen - offset, ", Originator %s", + snprintf(buf + offset, buflen - offset, ", Originator %s", bgp_vpn_ip_print(ndo, pptr, addr_length << 3)); break; case BGP_MULTICAST_VPN_ROUTE_TYPE_SOURCE_ACTIVE: ND_TCHECK_LEN(pptr, BGP_VPN_RD_LEN); offset = (u_int)strlen(buf); - nd_snprintf(buf + offset, buflen - offset, ", RD: %s", + snprintf(buf + offset, buflen - offset, ", RD: %s", bgp_vpn_rd_print(ndo, pptr)); pptr += BGP_VPN_RD_LEN; @@ -1073,7 +1219,7 @@ decode_multicast_vpn(netdissect_options *ndo, case BGP_MULTICAST_VPN_ROUTE_TYPE_SOURCE_TREE_JOIN: ND_TCHECK_LEN(pptr, BGP_VPN_RD_LEN + 4); offset = (u_int)strlen(buf); - nd_snprintf(buf + offset, buflen - offset, ", RD: %s, Source-AS %s", + snprintf(buf + offset, buflen - offset, ", RD: %s, Source-AS %s", bgp_vpn_rd_print(ndo, pptr), as_printf(ndo, astostr, sizeof(astostr), GET_BE_U_4(pptr + BGP_VPN_RD_LEN))); @@ -1123,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; @@ -1135,9 +1280,9 @@ decode_labeled_vpn_l2(netdissect_options *ndo, /* assume AD-only with RD, BGPNH */ ND_TCHECK_LEN(pptr, 12); buf[0] = '\0'; - stringlen = nd_snprintf(buf, buflen, "RD: %s, BGPNH: %s", + 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; @@ -1148,7 +1293,7 @@ decode_labeled_vpn_l2(netdissect_options *ndo, ND_TCHECK_LEN(pptr, 15); buf[0] = '\0'; - stringlen = nd_snprintf(buf, buflen, "RD: %s, CE-ID: %u, Label-Block Offset: %u, Label Base %u", + stringlen = snprintf(buf, buflen, "RD: %s, CE-ID: %u, Label-Block Offset: %u, Label Base %u", bgp_vpn_rd_print(ndo, pptr), GET_BE_U_2(pptr + 8), GET_BE_U_2(pptr + 10), @@ -1161,12 +1306,11 @@ decode_labeled_vpn_l2(netdissect_options *ndo, while (tlen != 0) { if (tlen < 3) { if (buflen != 0) { - stringlen=nd_snprintf(buf,buflen, "\n\t\tran past the end"); + stringlen=snprintf(buf,buflen, "\n\t\tran past the end"); UPDATE_BUF_BUFLEN(buf, buflen, stringlen); } return plen + 2; } - ND_TCHECK_3(pptr); tlv_type = GET_U_1(pptr); pptr++; tlv_len = GET_BE_U_2(pptr); /* length, in *bits* */ @@ -1176,7 +1320,7 @@ decode_labeled_vpn_l2(netdissect_options *ndo, switch(tlv_type) { case 1: if (buflen != 0) { - stringlen=nd_snprintf(buf,buflen, "\n\t\tcircuit status vector (%u) length: %u: 0x", + stringlen=snprintf(buf,buflen, "\n\t\tcircuit status vector (%u) length: %u: 0x", tlv_type, tlv_len); UPDATE_BUF_BUFLEN(buf, buflen, stringlen); @@ -1184,14 +1328,14 @@ decode_labeled_vpn_l2(netdissect_options *ndo, while (ttlv_len != 0) { if (tlen < 1) { if (buflen != 0) { - stringlen=nd_snprintf(buf,buflen, " (ran past the end)"); + stringlen=snprintf(buf,buflen, " (ran past the end)"); UPDATE_BUF_BUFLEN(buf, buflen, stringlen); } return plen + 2; } ND_TCHECK_1(pptr); if (buflen != 0) { - stringlen=nd_snprintf(buf,buflen, "%02x", + stringlen=snprintf(buf,buflen, "%02x", GET_U_1(pptr)); pptr++; UPDATE_BUF_BUFLEN(buf, buflen, stringlen); @@ -1202,14 +1346,14 @@ decode_labeled_vpn_l2(netdissect_options *ndo, break; default: if (buflen != 0) { - stringlen=nd_snprintf(buf,buflen, "\n\t\tunknown TLV #%u, length: %u", + stringlen=snprintf(buf,buflen, "\n\t\tunknown TLV #%u, length: %u", tlv_type, tlv_len); UPDATE_BUF_BUFLEN(buf, buflen, stringlen); } if (tlen < ttlv_len) { if (buflen != 0) { - stringlen=nd_snprintf(buf,buflen, " (ran past the end)"); + stringlen=snprintf(buf,buflen, " (ran past the end)"); UPDATE_BUF_BUFLEN(buf, buflen, stringlen); } return plen + 2; @@ -1233,10 +1377,9 @@ int decode_prefix6(netdissect_options *ndo, const u_char *pd, u_int itemlen, char *buf, size_t buflen) { - struct in6_addr addr; + nd_ipv6 addr; u_int plen, plenbytes; - ND_TCHECK_1(pd); ITEMCHECK(1); plen = GET_U_1(pd); if (128 < plen) @@ -1245,28 +1388,24 @@ 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.s6_addr[plenbytes - 1] &= + addr[plenbytes - 1] &= ((0xff00 >> (plen % 8)) & 0xff); } - nd_snprintf(buf, buflen, "%s/%u", ip6addr_string(ndo, (const u_char *)&addr), plen); + 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 decode_labeled_prefix6(netdissect_options *ndo, const u_char *pptr, u_int itemlen, char *buf, size_t buflen) { - struct in6_addr addr; + nd_ipv6 addr; u_int plen, plenbytes; /* prefix length and label = 4 bytes */ @@ -1285,14 +1424,13 @@ 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.s6_addr[plenbytes - 1] &= + addr[plenbytes - 1] &= ((0xff00 >> (plen % 8)) & 0xff); } /* the label may get offsetted by 4 bits so lets shift it right */ - nd_snprintf(buf, buflen, "%s/%u, label:%u %s", + snprintf(buf, buflen, "%s/%u, label:%u %s", ip6addr_string(ndo, (const u_char *)&addr), plen, GET_BE_U_3(pptr + 1)>>4, @@ -1311,10 +1449,9 @@ static int decode_labeled_vpn_prefix6(netdissect_options *ndo, const u_char *pptr, char *buf, size_t buflen) { - struct in6_addr addr; + nd_ipv6 addr; u_int plen; - ND_TCHECK_1(pptr); plen = GET_U_1(pptr); /* get prefix length */ if ((24+64) > plen) @@ -1326,14 +1463,13 @@ 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.s6_addr[(plen + 7) / 8 - 1] &= + addr[(plen + 7) / 8 - 1] &= ((0xff00 >> (plen % 8)) & 0xff); } /* the label may get offsetted by 4 bits so lets shift it right */ - nd_snprintf(buf, buflen, "RD: %s, %s/%u, label:%u %s", + snprintf(buf, buflen, "RD: %s, %s/%u, label:%u %s", bgp_vpn_rd_print(ndo, pptr+4), ip6addr_string(ndo, (const u_char *)&addr), plen, @@ -1341,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 @@ -1353,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); } - nd_snprintf(buf, buflen, "%s/%u", + /* 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 @@ -1383,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) @@ -1395,13 +1523,13 @@ 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 */ - nd_snprintf(buf, buflen, "RD: %s, %s/%u, label:%u %s", + /* 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), plen, @@ -1409,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; } /* @@ -1441,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; } @@ -1621,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); @@ -1648,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): @@ -1689,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); @@ -1716,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; @@ -1739,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; @@ -1750,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; @@ -1771,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; @@ -1792,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))); @@ -1824,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 ", @@ -1836,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; @@ -1847,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: @@ -1856,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; @@ -1878,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: @@ -1890,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) { @@ -1932,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) { @@ -1941,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; @@ -1961,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(", " ); } @@ -1983,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: @@ -2089,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"); @@ -2193,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), @@ -2207,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: @@ -2249,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; @@ -2271,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; @@ -2350,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; @@ -2365,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), @@ -2401,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; @@ -2426,6 +2555,22 @@ bgp_capabilities_print(netdissect_options *ndo, tok2str(bgp_safi_values, "Unknown", GET_U_1(opt + i + 5)), GET_U_1(opt + i + 5)); break; + case BGP_CAPCODE_ML: + cap_offset = 2; + tcap_len = cap_len; + while (tcap_len >= 4) { + ND_PRINT( "\n\t\tAFI %s (%u), SAFI %s (%u), Count: %u", + tok2str(af_values, "Unknown", + GET_BE_U_2(opt + i + cap_offset)), + GET_BE_U_2(opt + i + cap_offset), + tok2str(bgp_safi_values, "Unknown", + GET_U_1(opt + i + cap_offset + 2)), + GET_U_1(opt + i + cap_offset + 2), + GET_U_1(opt + i + cap_offset + 3)); + tcap_len -= 4; + cap_offset += 4; + } + break; case BGP_CAPCODE_RESTART: /* Restart Flags (4 bits), Restart Time in seconds (12 bits) */ if (cap_len < 2) { @@ -2452,7 +2597,10 @@ bgp_capabilities_print(netdissect_options *ndo, } break; 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: /* @@ -2512,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) @@ -2530,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; @@ -2562,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; @@ -2572,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: @@ -2633,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); @@ -2668,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; @@ -2725,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; @@ -2750,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); @@ -2775,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), @@ -2843,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) { @@ -2864,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; } @@ -2900,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);