X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/6cf3ea7d0f7c43440f74c93b95a7864f30fc68b4..HEAD:/print-icmp.c diff --git a/print-icmp.c b/print-icmp.c index a4564b53..771cb6e8 100644 --- a/print-icmp.c +++ b/print-icmp.c @@ -21,9 +21,7 @@ /* \summary: Internet Control Message Protocol (ICMP) printer */ -#ifdef HAVE_CONFIG_H #include -#endif #include "netdissect-stdinc.h" @@ -36,6 +34,7 @@ #include "extract.h" #include "ip.h" +#include "icmp.h" #include "udp.h" #include "ipproto.h" #include "mpls.h" @@ -59,12 +58,19 @@ struct icmp { nd_uint16_t icd_id; nd_uint16_t icd_seq; } ih_idseq; + struct ih_idseqx { /* RFC8335 */ + nd_uint16_t icdx_id; + nd_uint8_t icdx_seq; + nd_uint8_t icdx_info; + } ih_idseqx; nd_uint32_t ih_void; } icmp_hun; #define icmp_pptr icmp_hun.ih_pptr #define icmp_gwaddr icmp_hun.ih_gwaddr #define icmp_id icmp_hun.ih_idseq.icd_id #define icmp_seq icmp_hun.ih_idseq.icd_seq +#define icmp_xseq icmp_hun.ih_idseqx.icdx_seq +#define icmp_xinfo icmp_hun.ih_idseqx.icdx_info #define icmp_void icmp_hun.ih_void union { struct id_ts { @@ -142,7 +148,12 @@ struct icmp { #define ICMP_MASKREQ 17 /* address mask request */ #define ICMP_MASKREPLY 18 /* address mask reply */ -#define ICMP_MAXTYPE 18 +#define ICMP_EXTENDED_ECHO_REQUEST 42 /* extended echo request */ +#define ICMP_EXTENDED_ECHO_REPLY 43 /* extended echo reply */ +#define ICMP_ECHO_X_MALFORMED_QUERY 1 /* malformed query */ +#define ICMP_ECHO_X_NO_SUCH_INTERFACE 2 /* no such interface */ +#define ICMP_ECHO_X_NO_SUCH_TABLE_ENTRY 3 /* no such table entry */ +#define ICMP_ECHO_X_MULTIPLE_INTERFACES 4 /* multiple interfaces satisfy query */ #define ICMP_ERRTYPE(type) \ ((type) == ICMP_UNREACH || (type) == ICMP_SOURCEQUENCH || \ @@ -152,6 +163,9 @@ struct icmp { ((type) == ICMP_UNREACH || \ (type) == ICMP_TIMXCEED || \ (type) == ICMP_PARAMPROB) +#define ICMP_EXTENDED_ECHO_TYPE(type) \ + ((type) == ICMP_EXTENDED_ECHO_REQUEST || \ + (type) == ICMP_EXTENDED_ECHO_REPLY) /* rfc1700 */ #ifndef ICMP_UNREACH_NET_UNKNOWN #define ICMP_UNREACH_NET_UNKNOWN 6 /* destination net unknown */ @@ -197,6 +211,28 @@ static const struct tok icmp2str[] = { { ICMP_IREQ, "information request" }, { ICMP_IREQREPLY, "information reply" }, { ICMP_MASKREQ, "address mask request" }, + { ICMP_EXTENDED_ECHO_REQUEST, "extended echo request" }, + { ICMP_EXTENDED_ECHO_REPLY, "extended echo reply" }, + { 0, NULL } +}; + +static const struct tok icmp_extended_echo_reply_code_str[] = { + { 0, "No error" }, + { ICMP_ECHO_X_MALFORMED_QUERY, "Malformed Query" }, + { ICMP_ECHO_X_NO_SUCH_INTERFACE, "No Such Interface" }, + { ICMP_ECHO_X_NO_SUCH_TABLE_ENTRY, "No Such Table Entry" }, + { ICMP_ECHO_X_MULTIPLE_INTERFACES, "Multiple Interfaces Satisfy Query" }, + { 0, NULL } +}; + +static const struct tok icmp_extended_echo_reply_state_str[] = { + { 0, "Reserved" }, + { 1, "Incomplete" }, + { 2, "Reachable" }, + { 3, "Stale" }, + { 4, "Delay" }, + { 5, "Probe" }, + { 6, "Failed" }, { 0, NULL } }; @@ -280,12 +316,16 @@ struct icmp_ext_t { * contained bytes of the payload beyond the first 128 bytes, in * draft-bonica-icmp-mpls-02; it was reassigned to an "Interface * Information Object" in RFC 5837. + * + * Class 3 is defined by RFC8335. */ /* rfc4950 */ #define MPLS_STACK_ENTRY_OBJECT_CLASS 1 /* rfc5837 */ #define INTERFACE_INFORMATION_OBJECT_CLASS 2 +/* rfc8335 */ +#define INTERFACE_IDENTIFICATION_OBJECT_CLASS 3 struct icmp_multipart_ext_object_header_t { nd_uint16_t length; @@ -294,8 +334,9 @@ struct icmp_multipart_ext_object_header_t { }; static const struct tok icmp_multipart_ext_obj_values[] = { - { 1, "MPLS Stack Entry Object" }, - { 2, "Interface Information Object" }, + { MPLS_STACK_ENTRY_OBJECT_CLASS, "MPLS Stack Entry Object" }, + { INTERFACE_INFORMATION_OBJECT_CLASS, "Interface Information Object" }, + { INTERFACE_IDENTIFICATION_OBJECT_CLASS, "Interface Identification Object" }, { 0, NULL} }; @@ -319,7 +360,7 @@ Interface IP Address Sub-Object struct icmp_interface_information_ipaddr_subobject_t { nd_uint16_t afi; nd_uint16_t reserved; - nd_uint32_t ip_addr; + nd_byte ip_addr[1]; }; /* @@ -334,6 +375,22 @@ struct icmp_interface_information_ifname_subobject_t { nd_byte if_name[63]; }; +/* + * Interface Identification IP Address Sub-Object + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | AFI | Address Length| Reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Address .... + */ +struct icmp_interface_identification_ipaddr_subobject_t { + nd_uint16_t afi; + nd_uint8_t addrlen; + nd_uint8_t reserved; + nd_byte ip_addr[1]; +}; + /* prototypes */ const char *icmp_tstamp_print(u_int); @@ -482,6 +539,45 @@ print_icmp_multipart_ext_object(netdissect_options *ndo, const uint8_t *obj_tptr break; } + case INTERFACE_IDENTIFICATION_OBJECT_CLASS: + switch (obj_ctype) { + case 1: + ND_PRINT("\n\t Interface Name, length %d: ", obj_tlen); + nd_printjnp(ndo, obj_tptr, obj_tlen); + break; + case 2: + ND_PRINT("\n\t Interface Index: %u", GET_BE_U_4(obj_tptr)); + break; + case 3: + { + const struct icmp_interface_identification_ipaddr_subobject_t *id_ipaddr_subobj; + ND_PRINT("\n\t IP Address sub-object: "); + id_ipaddr_subobj = (const struct icmp_interface_identification_ipaddr_subobject_t *) obj_tptr; + switch (GET_BE_U_2(id_ipaddr_subobj->afi)) { + case 1: + if (GET_U_1(id_ipaddr_subobj->addrlen) != 4) { + ND_PRINT("[length %d != 4] ", GET_U_1(id_ipaddr_subobj->addrlen)); + } + ND_PRINT("%s", GET_IPADDR_STRING(id_ipaddr_subobj->ip_addr)); + break; + case 2: + if (GET_U_1(id_ipaddr_subobj->addrlen) != 16) { + ND_PRINT("[length %d != 16] ", GET_U_1(id_ipaddr_subobj->addrlen)); + } + ND_PRINT("%s", GET_IP6ADDR_STRING(id_ipaddr_subobj->ip_addr)); + break; + default: + ND_PRINT("Unknown Address Family Identifier"); + return -1; + } + break; + } + default: + print_unknown_data(ndo, obj_tptr, "\n\t ", obj_tlen); + break; + } + break; + default: print_unknown_data(ndo, obj_tptr, "\n\t ", obj_tlen); break; @@ -489,6 +585,44 @@ print_icmp_multipart_ext_object(netdissect_options *ndo, const uint8_t *obj_tptr return obj_tlen + sizeof(struct icmp_multipart_ext_object_header_t); } +void +print_icmp_rfc8335(netdissect_options *ndo, uint8_t xinfo, int isrequest, uint8_t icmp_code, const uint8_t *data) { + struct cksum_vec vec[1]; + + if (isrequest) { + ND_PRINT("\n\t%s Interface", xinfo & 1 ? "Local" : "Remote"); + if (ICMP_EXT_EXTRACT_VERSION(GET_U_1(data)) != ICMP_EXT_VERSION) { + nd_print_invalid(ndo); + } else { + // A single extended object. The extended header is not + // located at offset 128 in this case, so we can not use + // icmp_ext_checksum. + uint16_t sum = GET_BE_U_2(data + 2); + uint16_t len = GET_BE_U_2(data + 4); + // The checksum is over the extended header and the single + // object + len += 4; + vec[0].ptr = data; + vec[0].len = len; + if (ND_TTEST_LEN(vec[0].ptr, vec[0].len)) { + ND_PRINT(", checksum 0x%04x (%scorrect), length %u", + sum, + in_cksum(vec, 1) ? "in" : "", + len); + } + print_icmp_multipart_ext_object(ndo, data + 4); + } + } else { + int state = ( xinfo & 0xe0 ) >> 5; + ND_PRINT("\n\tCode %d (%s), State %d (%s), active %d ipv4 %d ipv6 %d", + icmp_code, tok2str(icmp_extended_echo_reply_code_str, "Unknown", icmp_code), + state, tok2str(icmp_extended_echo_reply_state_str, "Unknown", state), + xinfo & 4 ? 1 : 0, + xinfo & 2 ? 1 : 0, + xinfo & 1 ? 1 : 0); + } +} + void icmp_print(netdissect_options *ndo, const u_char *bp, u_int plen, int fragmented) @@ -754,7 +888,7 @@ icmp_print(netdissect_options *ndo, const u_char *bp, u_int plen, break; } idp = (const struct id_rdiscovery *)&dp->icmp_data; - while (num > 0) { + while (num != 0) { (void)snprintf(cp, sizeof(buf) - (cp - buf), " {%s %u}", GET_IPADDR_STRING(idp->ird_addr), GET_BE_U_4(idp->ird_pref)); @@ -820,6 +954,16 @@ icmp_print(netdissect_options *ndo, const u_char *bp, u_int plen, icmp_tstamp_print(GET_BE_U_4(dp->icmp_ttime))); break; + case ICMP_EXTENDED_ECHO_REQUEST: + case ICMP_EXTENDED_ECHO_REPLY: + /* brief info here due to limited buf; more info below */ + (void)snprintf(buf, sizeof(buf), "extended echo %s, id %u, seq %u", + icmp_type == ICMP_EXTENDED_ECHO_REQUEST ? + "request" : "reply", + GET_BE_U_2(dp->icmp_id), + GET_U_1(dp->icmp_xseq)); + break; + default: str = tok2str(icmp2str, "type-#%u", icmp_type); break; @@ -929,4 +1073,12 @@ icmp_print(netdissect_options *ndo, const u_char *bp, u_int plen, obj_tptr += obj_tlen; } } + + if (ndo->ndo_vflag >= 1 && ICMP_EXTENDED_ECHO_TYPE(icmp_type)) { + uint8_t xinfo = GET_U_1(dp->icmp_xinfo); + // RFC8335 printing is shared between ICMP and ICMPv6 + print_icmp_rfc8335( ndo, xinfo, icmp_type == ICMP_EXTENDED_ECHO_REQUEST, icmp_code, dp->icmp_data ); + } + + return; }