]> The Tcpdump Group git mirrors - tcpdump/commitdiff
ICMP: print RFC8335 PROBE extended echo/reply messages
authorBill Fenner <[email protected]>
Fri, 29 Dec 2023 20:11:03 +0000 (12:11 -0800)
committerfxlb <[email protected]>
Thu, 11 Jul 2024 15:14:47 +0000 (15:14 +0000)
Add interface name, ifindex and IP address printing for Interface
Information Object, and use the newly-refactored object printing
to print the single object included in an RFC8335 PROBE message.

Include a test with several well-formed packets, and one test
with a truncated packet (truncated packet supplied by fuzzer).

print-icmp.c
tests/TESTLIST
tests/icmp-rfc8335-missing-bytes.out [new file with mode: 0644]
tests/icmp-rfc8335-v.out [new file with mode: 0644]
tests/icmp-rfc8335.out [new file with mode: 0644]
tests/rfc8335-missing-bytes.pcap [new file with mode: 0644]
tests/rfc8335.pcap [new file with mode: 0644]

index 05dc0555bee146b8c8aa90854ccd0938a66157f0..daea617f640df0e23a6248bb78fa7fbb40757aa6 100644 (file)
@@ -57,12 +57,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 {
@@ -140,7 +147,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 || \
@@ -150,6 +162,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 */
@@ -195,6 +210,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 }
 };
 
@@ -278,12 +315,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;
@@ -292,8 +333,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}
 };
 
@@ -332,6 +374,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);
 
@@ -480,6 +538,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;
@@ -818,6 +915,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;
@@ -927,4 +1034,47 @@ 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)) {
+           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;
+           }
+       }
+
+       return;
 }
index fcb725c985c9dcc35ca2aaa77ba901f925df3200..24103c7469cd4a0bb29b2b398e935894699fdedd 100644 (file)
@@ -221,6 +221,9 @@ dvmrp               mrinfo_query.pcap       dvmrp.out
 # ICMPv4 -- pcap from https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=6632
 rfc5837    icmp-rfc5837.pcap icmp-rfc5837.out -v
 icmp_inft_name_length_zero icmp_inft_name_length_zero.pcap icmp_inft_name_length_zero.out -v
+rfc8335                rfc8335.pcap    icmp-rfc8335.out
+rfc8335-v      rfc8335.pcap    icmp-rfc8335-v.out      -v
+rfc8335-missing-bytes  rfc8335-missing-bytes.pcap      icmp-rfc8335-missing-bytes.out  -v
 
 # ICMPv6
 icmpv6          icmpv6.pcap             icmpv6.out      -vv
diff --git a/tests/icmp-rfc8335-missing-bytes.out b/tests/icmp-rfc8335-missing-bytes.out
new file mode 100644 (file)
index 0000000..563a9d9
--- /dev/null
@@ -0,0 +1,3 @@
+    1  2024-01-22 18:23:52.186004 IP [total length 84 > length 35] (invalid) (tos 0x0, ttl 64, id 53536, offset 0, flags [DF], proto ICMP (1), length 84, bad cksum 22 (->cdef)!)
+    35.36.42.37 > 38.39.40.41: ICMP extended echo request, id 11823, seq 48, length 64
+       Local Interface [|icmp]
diff --git a/tests/icmp-rfc8335-v.out b/tests/icmp-rfc8335-v.out
new file mode 100644 (file)
index 0000000..a7a87fd
--- /dev/null
@@ -0,0 +1,44 @@
+    1  2024-01-01 22:21:42.293205 IP (tos 0x0, ttl 54, id 10659, offset 0, flags [none], proto ICMP (1), length 48)
+    204.194.23.128 > 149.28.74.237: ICMP extended echo request, id 63210, seq 0, length 28
+       Local Interface, checksum 0xdcf4 (correct), length 12
+         Interface Identification Object (3), Class-Type: 2, length 8
+           Interface Index: 1
+    2  2024-01-01 22:22:02.791281 IP (tos 0x0, ttl 54, id 11917, offset 0, flags [none], proto ICMP (1), length 50)
+    204.194.23.128 > 149.28.74.237: ICMP extended echo request, id 63239, seq 0, length 30
+       Local Interface, checksum 0x9424 (correct), length 14
+         Interface Identification Object (3), Class-Type: 1, length 10
+           Interface Name, length 6: enp1s0
+    3  2024-01-01 22:22:49.391909 IP (tos 0x0, ttl 54, id 14708, offset 0, flags [none], proto ICMP (1), length 52)
+    204.194.23.128 > 149.28.74.237: ICMP extended echo request, id 63269, seq 0, length 32
+       Local Interface, checksum 0xf8e5 (correct), length 16
+         Interface Identification Object (3), Class-Type: 3, length 12
+           IP Address sub-object: 149.28.74.237
+    4  2024-01-01 22:23:14.907148 IP (tos 0x0, ttl 54, id 16258, offset 0, flags [none], proto ICMP (1), length 52)
+    204.194.23.128 > 149.28.74.237: ICMP extended echo request, id 63274, seq 0, length 32
+       Remote Interface, checksum 0xf9d1 (correct), length 16
+         Interface Identification Object (3), Class-Type: 3, length 12
+           IP Address sub-object: 149.28.74.1
+    5  2024-01-01 22:36:36.688455 IP (tos 0x0, ttl 64, id 1, offset 0, flags [none], proto ICMP (1), length 52)
+    149.28.74.237 > 204.194.23.128: ICMP extended echo request, id 42, seq 42, length 32
+       Local Interface, checksum 0xd819 (correct), length 16
+         Interface Identification Object (3), Class-Type: 1, length 12
+           Interface Name, length 8: fxp0.0
+    6  2024-01-01 22:36:36.750419 IP (tos 0x0, ttl 245, id 63324, offset 0, flags [DF], proto ICMP (1), length 52)
+    204.194.23.128 > 149.28.74.237: ICMP extended echo reply, id 42, seq 42, length 32
+       Code 0 (No error), State 0 (Reserved), active 1 ipv4 1 ipv6 1
+    7  2024-01-01 22:36:44.864530 IP (tos 0x0, ttl 64, id 1, offset 0, flags [none], proto ICMP (1), length 44)
+    149.28.74.237 > 204.194.23.128: ICMP extended echo request, id 42, seq 42, length 24
+       Local Interface, checksum 0xd819 (correct), length 16
+         Interface Identification Object (3), Class-Type: 1, length 12
+           Interface Name, length 8: fxp0.0
+    8  2024-01-01 22:36:44.926583 IP (tos 0x0, ttl 245, id 63780, offset 0, flags [DF], proto ICMP (1), length 44)
+    204.194.23.128 > 149.28.74.237: ICMP extended echo reply, id 42, seq 42, length 24
+       Code 1 (Malformed Query), State 0 (Reserved), active 0 ipv4 0 ipv6 0
+    9  2024-01-01 22:37:03.384499 IP (tos 0x0, ttl 64, id 1, offset 0, flags [none], proto ICMP (1), length 48)
+    149.28.74.237 > 204.194.23.128: ICMP extended echo request, id 42, seq 42, length 28
+       Local Interface, checksum 0xdccb (correct), length 12
+         Interface Identification Object (3), Class-Type: 2, length 8
+           Interface Index: 42
+   10  2024-01-01 22:37:03.446572 IP (tos 0x0, ttl 245, id 64921, offset 0, flags [DF], proto ICMP (1), length 48)
+    204.194.23.128 > 149.28.74.237: ICMP extended echo reply, id 42, seq 42, length 28
+       Code 2 (No Such Interface), State 0 (Reserved), active 0 ipv4 0 ipv6 0
diff --git a/tests/icmp-rfc8335.out b/tests/icmp-rfc8335.out
new file mode 100644 (file)
index 0000000..9712718
--- /dev/null
@@ -0,0 +1,10 @@
+    1  2024-01-01 22:21:42.293205 IP 204.194.23.128 > 149.28.74.237: ICMP extended echo request, id 63210, seq 0, length 28
+    2  2024-01-01 22:22:02.791281 IP 204.194.23.128 > 149.28.74.237: ICMP extended echo request, id 63239, seq 0, length 30
+    3  2024-01-01 22:22:49.391909 IP 204.194.23.128 > 149.28.74.237: ICMP extended echo request, id 63269, seq 0, length 32
+    4  2024-01-01 22:23:14.907148 IP 204.194.23.128 > 149.28.74.237: ICMP extended echo request, id 63274, seq 0, length 32
+    5  2024-01-01 22:36:36.688455 IP 149.28.74.237 > 204.194.23.128: ICMP extended echo request, id 42, seq 42, length 32
+    6  2024-01-01 22:36:36.750419 IP 204.194.23.128 > 149.28.74.237: ICMP extended echo reply, id 42, seq 42, length 32
+    7  2024-01-01 22:36:44.864530 IP 149.28.74.237 > 204.194.23.128: ICMP extended echo request, id 42, seq 42, length 24
+    8  2024-01-01 22:36:44.926583 IP 204.194.23.128 > 149.28.74.237: ICMP extended echo reply, id 42, seq 42, length 24
+    9  2024-01-01 22:37:03.384499 IP 149.28.74.237 > 204.194.23.128: ICMP extended echo request, id 42, seq 42, length 28
+   10  2024-01-01 22:37:03.446572 IP 204.194.23.128 > 149.28.74.237: ICMP extended echo reply, id 42, seq 42, length 28
diff --git a/tests/rfc8335-missing-bytes.pcap b/tests/rfc8335-missing-bytes.pcap
new file mode 100644 (file)
index 0000000..c253b8b
Binary files /dev/null and b/tests/rfc8335-missing-bytes.pcap differ
diff --git a/tests/rfc8335.pcap b/tests/rfc8335.pcap
new file mode 100644 (file)
index 0000000..78994b6
Binary files /dev/null and b/tests/rfc8335.pcap differ