From: Bill Fenner Date: Mon, 5 Feb 2024 05:13:09 +0000 (-0800) Subject: ICMPv6: print RFC8335 PROBE extended echo/reply messages X-Git-Url: https://git.tcpdump.org/tcpdump/commitdiff_plain/f5877da285f3e030d59a28236295573f27e344bc ICMPv6: print RFC8335 PROBE extended echo/reply messages The ICMP types are different, but everything else about PROBE, including the RFC4884-based parsing, is the same, so we share the implementation from print-icmp.c using the new icmp.h. --- diff --git a/Makefile.in b/Makefile.in index cad9e4bb..7046a020 100644 --- a/Makefile.in +++ b/Makefile.in @@ -282,6 +282,7 @@ HDR = \ getservent.h \ gmpls.h \ gre.h \ + icmp.h \ interface.h \ ip.h \ ip6.h \ diff --git a/icmp.h b/icmp.h new file mode 100644 index 00000000..1e7b12ea --- /dev/null +++ b/icmp.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994, 1995, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef netdissect_icmp_h +#define netdissect_icmp_h + +/* common data structures and functions to be shared between ICMP and ICMPv6 */ + +/* + * RFC8335 - PROBE + */ +void +print_icmp_rfc8335(netdissect_options *, uint8_t, int, uint8_t, const uint8_t *); + +#endif /* netdissect_icmp_h */ + diff --git a/print-icmp.c b/print-icmp.c index b4b50ea4..771cb6e8 100644 --- a/print-icmp.c +++ b/print-icmp.c @@ -34,6 +34,7 @@ #include "extract.h" #include "ip.h" +#include "icmp.h" #include "udp.h" #include "ipproto.h" #include "mpls.h" @@ -584,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) @@ -1036,44 +1075,9 @@ icmp_print(netdissect_options *ndo, const u_char *bp, u_int plen, } if (ndo->ndo_vflag >= 1 && ICMP_EXTENDED_ECHO_TYPE(icmp_type)) { - int xinfo = GET_U_1(dp->icmp_xinfo); - switch (icmp_type) { - case ICMP_EXTENDED_ECHO_REQUEST: - ND_PRINT("\n\t%s Interface", xinfo & 1 ? "Local" : "Remote"); - if (ICMP_EXT_EXTRACT_VERSION(GET_U_1(dp->icmp_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(dp->icmp_data + 2); - uint16_t len = GET_BE_U_2(dp->icmp_data + 4); - // The checksum is over the extended header and the single - // object - len += 4; - vec[0].ptr = dp->icmp_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, dp->icmp_data + 4); - } - break; - case ICMP_EXTENDED_ECHO_REPLY: - { - 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); - } - break; - } + 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; diff --git a/print-icmp6.c b/print-icmp6.c index 86083f58..5ab6a46e 100644 --- a/print-icmp6.c +++ b/print-icmp6.c @@ -35,6 +35,7 @@ #include "ip6.h" #include "ipproto.h" +#include "icmp.h" #include "udp.h" #include "ah.h" @@ -92,6 +93,8 @@ struct icmp6_hdr { #define icmp6_id icmp6_data16[0] /* echo request/reply */ #define icmp6_seq icmp6_data16[1] /* echo request/reply */ #define icmp6_maxdelay icmp6_data16[0] /* mcast group membership */ +#define icmp6_xseq icmp6_data8[2] /* extended echo request/reply */ +#define icmp6_xinfo icmp6_data8[3] /* extended echo request/reply */ #define ICMP6_DST_UNREACH 1 /* dest unreachable, codes: */ #define ICMP6_PACKET_TOO_BIG 2 /* packet too big */ @@ -130,6 +133,8 @@ struct icmp6_hdr { #define ICMP6_HADISCOV_REPLY 145 #define ICMP6_MOBILEPREFIX_SOLICIT 146 #define ICMP6_MOBILEPREFIX_ADVERT 147 +#define ICMP6_EXTENDED_ECHO_REQUEST 160 /* extended echo request */ +#define ICMP6_EXTENDED_ECHO_REPLY 161 /* extended echo reply */ #define MLD6_MTRACE_RESP 200 /* mtrace response(to sender) */ #define MLD6_MTRACE 201 /* mtrace messages */ @@ -666,6 +671,8 @@ static const struct tok icmp6_type_values[] = { { MLD6_MTRACE, "mtrace message"}, { MLD6_MTRACE_RESP, "mtrace response"}, { ND_RPL_MESSAGE, "RPL"}, + { ICMP6_EXTENDED_ECHO_REQUEST, "extended echo request"}, + { ICMP6_EXTENDED_ECHO_REPLY, "extended echo reply"}, { 0, NULL } }; @@ -1283,6 +1290,17 @@ icmp6_print(netdissect_options *ndo, /* plus 4, because struct icmp6_hdr contains 4 bytes of icmp payload */ rpl_print(ndo, icmp6_code, dp->icmp6_data, length-sizeof(struct icmp6_hdr)+4); break; + case ICMP6_EXTENDED_ECHO_REQUEST: + case ICMP6_EXTENDED_ECHO_REPLY: + ND_PRINT(", id %u, seq %u", GET_BE_U_2(dp->icmp6_id), + GET_U_1(dp->icmp6_xseq)); + // The content of the message is the same as ICMP, so use the + // function defined in print-icmp.c + if (ndo->ndo_vflag) { + uint8_t xinfo = GET_U_1(dp->icmp6_xinfo); + print_icmp_rfc8335(ndo, xinfo, icmp6_type == ICMP6_EXTENDED_ECHO_REQUEST, icmp6_code, dp->icmp6_data + 4); + } + break; default: ND_PRINT(", length %u", length); if (ndo->ndo_vflag <= 1) diff --git a/tests/TESTLIST b/tests/TESTLIST index 47d6dfa0..e1730a93 100644 --- a/tests/TESTLIST +++ b/tests/TESTLIST @@ -224,6 +224,8 @@ icmp_inft_name_length_zero icmp_inft_name_length_zero.pcap icmp_inft_name_length icmp-rfc8335 icmp-rfc8335.pcap icmp-rfc8335.out icmp-rfc8335-v icmp-rfc8335.pcap icmp-rfc8335-v.out -v icmp-rfc8335-missing-bytes icmp-rfc8335-missing-bytes.pcap icmp-rfc8335-missing-bytes.out -v +icmp6-rfc8335 icmp6-rfc8335.pcap icmp6-rfc8335.out +icmp6-rfc8335-v icmp6-rfc8335.pcap icmp6-rfc8335-v.out -v # ICMPv6 icmpv6 icmpv6.pcap icmpv6.out -vv diff --git a/tests/icmp6-rfc8335-v.out b/tests/icmp6-rfc8335-v.out new file mode 100644 index 00000000..dcaf3ecf --- /dev/null +++ b/tests/icmp6-rfc8335-v.out @@ -0,0 +1,18 @@ + 1 2024-02-05 05:10:17.314281 IP6 (flowlabel 0xf260b, hlim 255, next-header ICMPv6 (58) payload length: 28) fdfd:5c41:712d:d05a:d0dd:22ff:feac:5c6b > fdfd:5c41:712d:d0aa:225:90ff:fea8:8686: [icmp6 sum ok] ICMP6, extended echo request, id 64353, seq 0 + Local Interface, checksum 0xdcf4 (correct), length 12 + Interface Identification Object (3), Class-Type: 2, length 8 + Interface Index: 1 + 2 2024-02-05 05:10:17.314546 IP6 (flowlabel 0x618d4, hlim 59, next-header ICMPv6 (58) payload length: 28) fdfd:5c41:712d:d0aa:225:90ff:fea8:8686 > fdfd:5c41:712d:d05a:d0dd:22ff:feac:5c6b: [icmp6 sum ok] ICMP6, extended echo reply, id 64353, seq 0 + Code 0 (No error), State 0 (Reserved), active 1 ipv4 1 ipv6 1 + 3 2024-02-05 05:10:46.267725 IP6 (flowlabel 0xf260b, hlim 255, next-header ICMPv6 (58) payload length: 32) fdfd:5c41:712d:d05a:d0dd:22ff:feac:5c6b > fdfd:5c41:712d:d0aa:225:90ff:fea8:8686: [icmp6 sum ok] ICMP6, extended echo request, id 64356, seq 0 + Local Interface, checksum 0x2df1 (correct), length 16 + Interface Identification Object (3), Class-Type: 1, length 12 + Interface Name, length 8: enp2s0f0 + 4 2024-02-05 05:10:46.267887 IP6 (flowlabel 0x618d4, hlim 59, next-header ICMPv6 (58) payload length: 32) fdfd:5c41:712d:d0aa:225:90ff:fea8:8686 > fdfd:5c41:712d:d05a:d0dd:22ff:feac:5c6b: [icmp6 sum ok] ICMP6, extended echo reply, id 64356, seq 0 + Code 0 (No error), State 0 (Reserved), active 1 ipv4 0 ipv6 0 + 5 2024-02-05 05:11:07.324173 IP6 (flowlabel 0xf260b, hlim 255, next-header ICMPv6 (58) payload length: 32) fdfd:5c41:712d:d05a:d0dd:22ff:feac:5c6b > fdfd:5c41:712d:d0aa:225:90ff:fea8:8686: [icmp6 sum ok] ICMP6, extended echo request, id 64359, seq 0 + Local Interface, checksum 0x9eb5 (correct), length 16 + Interface Identification Object (3), Class-Type: 1, length 12 + Interface Name, length 8: george + 6 2024-02-05 05:11:07.324377 IP6 (flowlabel 0x618d4, hlim 59, next-header ICMPv6 (58) payload length: 32) fdfd:5c41:712d:d0aa:225:90ff:fea8:8686 > fdfd:5c41:712d:d05a:d0dd:22ff:feac:5c6b: [icmp6 sum ok] ICMP6, extended echo reply, id 64359, seq 0 + Code 2 (No Such Interface), State 0 (Reserved), active 0 ipv4 0 ipv6 0 diff --git a/tests/icmp6-rfc8335.out b/tests/icmp6-rfc8335.out new file mode 100644 index 00000000..f5e7b7f7 --- /dev/null +++ b/tests/icmp6-rfc8335.out @@ -0,0 +1,6 @@ + 1 2024-02-05 05:10:17.314281 IP6 fdfd:5c41:712d:d05a:d0dd:22ff:feac:5c6b > fdfd:5c41:712d:d0aa:225:90ff:fea8:8686: ICMP6, extended echo request, id 64353, seq 0, length 28 + 2 2024-02-05 05:10:17.314546 IP6 fdfd:5c41:712d:d0aa:225:90ff:fea8:8686 > fdfd:5c41:712d:d05a:d0dd:22ff:feac:5c6b: ICMP6, extended echo reply, id 64353, seq 0, length 28 + 3 2024-02-05 05:10:46.267725 IP6 fdfd:5c41:712d:d05a:d0dd:22ff:feac:5c6b > fdfd:5c41:712d:d0aa:225:90ff:fea8:8686: ICMP6, extended echo request, id 64356, seq 0, length 32 + 4 2024-02-05 05:10:46.267887 IP6 fdfd:5c41:712d:d0aa:225:90ff:fea8:8686 > fdfd:5c41:712d:d05a:d0dd:22ff:feac:5c6b: ICMP6, extended echo reply, id 64356, seq 0, length 32 + 5 2024-02-05 05:11:07.324173 IP6 fdfd:5c41:712d:d05a:d0dd:22ff:feac:5c6b > fdfd:5c41:712d:d0aa:225:90ff:fea8:8686: ICMP6, extended echo request, id 64359, seq 0, length 32 + 6 2024-02-05 05:11:07.324377 IP6 fdfd:5c41:712d:d0aa:225:90ff:fea8:8686 > fdfd:5c41:712d:d05a:d0dd:22ff:feac:5c6b: ICMP6, extended echo reply, id 64359, seq 0, length 32 diff --git a/tests/icmp6-rfc8335.pcap b/tests/icmp6-rfc8335.pcap new file mode 100644 index 00000000..30ba2b43 Binary files /dev/null and b/tests/icmp6-rfc8335.pcap differ