]> The Tcpdump Group git mirrors - tcpdump/commitdiff
ICMPv6: Recognise ND option 14 (Nonce)
authorArseny Maslennikov <[email protected]>
Mon, 4 Dec 2023 11:44:55 +0000 (14:44 +0300)
committerfxlb <[email protected]>
Tue, 11 Mar 2025 20:30:51 +0000 (20:30 +0000)
This option has been observed to be included in neighbour solicitations
sent by Linux kernel when `conf/*/enhanced_dad` is enabled on the
relevant network interface. It looks like it appeared in the linked
kernel commit.

In accordance with RFC 7527, a nonce can help distinguish valid DAD NS
messages in the presence of Ethernet loopbacks: after a DAD probe is
sent on the network, if an NS is received with the same nonce it is
considered looped back and ignored.

We implement the printer for this option and add a simple test with 3
different verbosity levels.

Also, introduce a helper function to util-print.c which prints
arbitrary data from the dissected packet as space-separated hexadecimal
octets, e. g. "77 c1 ad e9 17 70". Use it in the new printer.

Link: https://github.com/torvalds/linux/commit/adc176c5472214971d77c1a61c83db9b01e9cdc7
Link: https://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xhtml#icmpv6-parameters-5
netdissect.h
print-icmp6.c
tests/TESTLIST
tests/icmpv6-ns-nonce-v0.out [new file with mode: 0644]
tests/icmpv6-ns-nonce-v1.out [new file with mode: 0644]
tests/icmpv6-ns-nonce-v2.out [new file with mode: 0644]
tests/icmpv6-ns-nonce.pcap [new file with mode: 0644]
util-print.c

index ede1185d8795a82c4ea0dd1431b5aaf5e641d48a..ca2b566537d38b4bcf4fcabf03f5a12bf6e8d873 100644 (file)
@@ -465,6 +465,7 @@ extern u_int nd_printztn(netdissect_options *, const u_char *, u_int, const u_ch
 extern int nd_printn(netdissect_options *, const u_char *, u_int, const u_char *);
 extern void nd_printjn(netdissect_options *, const u_char *, u_int);
 extern void nd_printjnp(netdissect_options *, const u_char *, u_int);
+extern void nd_print_bytes_hex(netdissect_options *, const u_char *, u_int);
 
 /*
  * Flags for txtproto_print().
index 0f1b4297ec0bfbdb86a5460e440f6349c8d32fc4..880f3b45ba2cbe2cc4ad77bffd7c584df50f20ad 100644 (file)
@@ -279,6 +279,7 @@ struct nd_opt_hdr {         /* Neighbor discovery option header */
 #define ND_OPT_MTU                     5
 #define ND_OPT_ADVINTERVAL             7
 #define ND_OPT_HOMEAGENT_INFO          8
+#define ND_OPT_NONCE                   14
 #define ND_OPT_ROUTE_INFO              24      /* RFC4191 */
 #define ND_OPT_RDNSS                   25
 #define ND_OPT_DNSSL                   31
@@ -731,6 +732,7 @@ static const struct tok icmp6_opt_values[] = {
    { ND_OPT_DNSSL, "dnssl"},
    { ND_OPT_ADVINTERVAL, "advertisement interval"},
    { ND_OPT_HOMEAGENT_INFO, "homeagent information"},
+   { ND_OPT_NONCE, "nonce"},
    { ND_OPT_ROUTE_INFO, "route info"},
    { 0,        NULL }
 };
@@ -1504,6 +1506,10 @@ icmp6_opt_print(netdissect_options *ndo, const u_char *bp, int resid)
                                   GET_BE_U_2(oph->nd_opt_hai_preference),
                                   GET_BE_U_2(oph->nd_opt_hai_lifetime));
                        break;
+               case ND_OPT_NONCE:
+                       l = (opt_len << 3) - 2;
+                       nd_print_bytes_hex(ndo, cp + 2, l);
+                       break;
                case ND_OPT_ROUTE_INFO:
                        opri = (const struct nd_opt_route_info *)op;
                        ND_TCHECK_4(opri->nd_opt_rti_lifetime);
index 5ed6522deeb0b24edb18f1f088a9c615ce9a6d92..0789905b7009d72ada4cb25b398a3ba80da12882 100644 (file)
@@ -246,6 +246,9 @@ icmpv6_nodeinfo_queryipv4 icmpv6_nodeinfo_queryipv4.pcap icmpv6_nodeinfo_queryip
 icmpv6_nodeinfo_replyipv4 icmpv6_nodeinfo_replyipv4.pcap icmpv6_nodeinfo_replyipv4.out -v
 icmpv6_nodeinfo_queryipv6 icmpv6_nodeinfo_queryipv6.pcap icmpv6_nodeinfo_queryipv6.out -v
 icmpv6_nodeinfo_replyipv6 icmpv6_nodeinfo_replyipv6.pcap icmpv6_nodeinfo_replyipv6.out -v
+icmpv6-ns-nonce-v0     icmpv6-ns-nonce.pcap    icmpv6-ns-nonce-v0.out
+icmpv6-ns-nonce-v1     icmpv6-ns-nonce.pcap    icmpv6-ns-nonce-v1.out  -v
+icmpv6-ns-nonce-v2     icmpv6-ns-nonce.pcap    icmpv6-ns-nonce-v2.out  -vv
 
 # SPB tests
 spb                spb.pcap                spb.out
diff --git a/tests/icmpv6-ns-nonce-v0.out b/tests/icmpv6-ns-nonce-v0.out
new file mode 100644 (file)
index 0000000..9179aa8
--- /dev/null
@@ -0,0 +1 @@
+    1  2023-12-04 11:07:31.663323 IP6 :: > ff02::1:ffe1:f: ICMP6, neighbor solicitation, who has fe80::546f:f7ff:fee1:f, length 32
diff --git a/tests/icmpv6-ns-nonce-v1.out b/tests/icmpv6-ns-nonce-v1.out
new file mode 100644 (file)
index 0000000..d00e516
--- /dev/null
@@ -0,0 +1,2 @@
+    1  2023-12-04 11:07:31.663323 IP6 (hlim 255, next-header ICMPv6 (58), payload length 32) :: > ff02::1:ffe1:f: [icmp6 sum ok] ICMP6, neighbor solicitation, length 32, who has fe80::546f:f7ff:fee1:f
+         nonce option (14), length 8 (1): 60 69 60 4c 0a aa
diff --git a/tests/icmpv6-ns-nonce-v2.out b/tests/icmpv6-ns-nonce-v2.out
new file mode 100644 (file)
index 0000000..ddd7dff
--- /dev/null
@@ -0,0 +1,3 @@
+    1  2023-12-04 11:07:31.663323 IP6 (hlim 255, next-header ICMPv6 (58), payload length 32) :: > ff02::1:ffe1:f: [icmp6 sum ok] ICMP6, neighbor solicitation, length 32, who has fe80::546f:f7ff:fee1:f
+         nonce option (14), length 8 (1): 60 69 60 4c 0a aa
+           0x0000:  6069 604c 0aaa
diff --git a/tests/icmpv6-ns-nonce.pcap b/tests/icmpv6-ns-nonce.pcap
new file mode 100644 (file)
index 0000000..107c0ae
Binary files /dev/null and b/tests/icmpv6-ns-nonce.pcap differ
index 4a064eb0b9be788b4fd5b5b11ed95a4199b07b0d..beeb4f4a8c7dedf89a63b37265daa67b37b790bd 100644 (file)
@@ -481,6 +481,23 @@ void nd_print_invalid(netdissect_options *ndo)
        ND_PRINT(" (invalid)");
 }
 
+/*
+ * Print a sequence of bytes, separated by a single space.
+ * Stop if truncated (via GET_U_1/longjmp) or after n bytes,
+ * whichever is first.
+ */
+void
+nd_print_bytes_hex(netdissect_options *ndo, const u_char *cp, u_int n)
+{
+       while (n > 0) {
+               ND_PRINT("%02x", GET_U_1(cp));
+               n--;
+               cp++;
+               if (n > 0)
+                       ND_PRINT(" ");
+       }
+}
+
 /*
  *  this is a generic routine for printing unknown data;
  *  we pass on the linefeed plus indentation string to