]> The Tcpdump Group git mirrors - tcpdump/commitdiff
ICMPv6: Recognise ND option 38 (PREF64)
authorArseny Maslennikov <[email protected]>
Fri, 8 Dec 2023 11:44:55 +0000 (14:44 +0300)
committerfxlb <[email protected]>
Wed, 19 Mar 2025 10:10:55 +0000 (10:10 +0000)
This option, defined in RFC 8781, allows a router administrator to pass
NAT64 prefix information for the network to end hosts together with
other routing and prefix information in the RA message, getting rid
of the need for DNS64 service in the network.

As of today the option is widely supported by software routers,
including radvd, BIRD and systemd-networkd.

We implement the printer and test some valid and broken option contents.

print-icmp6.c
tests/TESTLIST
tests/icmpv6-ra-pref64-v1.out [new file with mode: 0644]
tests/icmpv6-ra-pref64-v2.out [new file with mode: 0644]
tests/icmpv6-ra-pref64.pcap [new file with mode: 0644]

index 880f3b45ba2cbe2cc4ad77bffd7c584df50f20ad..66cfcb633ee031a57c405c3e4a883db51298972a 100644 (file)
@@ -283,6 +283,7 @@ struct nd_opt_hdr {         /* Neighbor discovery option header */
 #define ND_OPT_ROUTE_INFO              24      /* RFC4191 */
 #define ND_OPT_RDNSS                   25
 #define ND_OPT_DNSSL                   31
+#define ND_OPT_PREF64_INFORMATION      38      /* RFC8781 */
 
 struct nd_opt_prefix_info {    /* prefix information */
        nd_uint8_t      nd_opt_pi_type;
@@ -354,6 +355,13 @@ struct nd_opt_route_info { /* route info */
        /* prefix follows */
 };
 
+struct nd_opt_pref64 {         /* PREF64 option */
+       nd_uint8_t      nd_opt_pref64_type;
+       nd_uint8_t      nd_opt_pref64_len;
+       nd_uint16_t     nd_opt_pref64_slplc; /* 13bit lft + 3bit PLC */
+       nd_uint32_t     nd_opt_pref64_words[3]; /* highest 96 bits of prefix */
+};
+
 /*
  * icmp6 namelookup
  */
@@ -495,6 +503,7 @@ struct rr_result {          /* router renumbering result message */
 
 static const char *get_rtpref(u_int);
 static const char *get_lifetime(uint32_t);
+static const char *get_pref64_len_repr(uint16_t);
 static void print_lladdr(netdissect_options *ndo, const u_char *, size_t);
 static int icmp6_opt_print(netdissect_options *ndo, const u_char *, int);
 static void mld6_print(netdissect_options *ndo, const u_char *);
@@ -734,6 +743,7 @@ static const struct tok icmp6_opt_values[] = {
    { ND_OPT_HOMEAGENT_INFO, "homeagent information"},
    { ND_OPT_NONCE, "nonce"},
    { ND_OPT_ROUTE_INFO, "route info"},
+   { ND_OPT_PREF64_INFORMATION, "pref64"},
    { 0,        NULL }
 };
 
@@ -774,6 +784,20 @@ get_lifetime(uint32_t v)
        }
 }
 
+static const char *
+get_pref64_len_repr(uint16_t v)
+{
+       static const char *prefixlen_str[] = {
+               "96", "64", "56", "48", "40", "32"
+       };
+
+       v = v & 0x0007;
+       if (v < 6)
+               return prefixlen_str[v];
+       else
+               return "??";
+}
+
 static void
 print_lladdr(netdissect_options *ndo, const uint8_t *p, size_t l)
 {
@@ -1416,10 +1440,12 @@ icmp6_opt_print(netdissect_options *ndo, const u_char *bp, int resid)
        const struct nd_opt_advinterval *opa;
        const struct nd_opt_homeagent_info *oph;
        const struct nd_opt_route_info *opri;
+       const struct nd_opt_pref64 *op64;
        const u_char *cp, *ep, *domp;
        nd_ipv6 in6;
        size_t l;
        u_int i;
+       uint16_t w;
 
        cp = bp;
        /* 'ep' points to the end of available data. */
@@ -1533,6 +1559,20 @@ icmp6_opt_print(netdissect_options *ndo, const u_char *bp, int resid)
                        ND_PRINT(", lifetime=%s",
                                   get_lifetime(GET_BE_U_4(opri->nd_opt_rti_lifetime)));
                        break;
+               case ND_OPT_PREF64_INFORMATION:
+                       op64 = (const struct nd_opt_pref64 *)op;
+                       if (opt_len != 2)
+                               ND_PRINT("%s", "bad option length! ");
+                       w = GET_BE_U_2(op64->nd_opt_pref64_slplc);
+                       memset(&in6, 0, sizeof(in6));
+                       GET_CPY_BYTES(&in6, op64->nd_opt_pref64_words,
+                                      sizeof(op64->nd_opt_pref64_words));
+                       ND_PRINT("%s/%s (plc %u), lifetime %us",
+                                 ip6addr_string(ndo, (const u_char *)&in6),
+                                 get_pref64_len_repr(w),
+                                 w & 0x0007,
+                                 w & 0xfff8);
+                       break;
                default:
                         if (ndo->ndo_vflag <= 1) {
                                 print_unknown_data(ndo,cp+2,"\n\t  ", (opt_len << 3) - 2); /* skip option header */
index 0789905b7009d72ada4cb25b398a3ba80da12882..86ffa66ec8e9803ad152a8b34d16de033cac9de5 100644 (file)
@@ -249,6 +249,8 @@ icmpv6_nodeinfo_replyipv6 icmpv6_nodeinfo_replyipv6.pcap icmpv6_nodeinfo_replyip
 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
+icmpv6-ra-pref64-v1    icmpv6-ra-pref64.pcap   icmpv6-ra-pref64-v1.out -v
+icmpv6-ra-pref64-v2    icmpv6-ra-pref64.pcap   icmpv6-ra-pref64-v2.out -vv
 
 # SPB tests
 spb                spb.pcap                spb.out
diff --git a/tests/icmpv6-ra-pref64-v1.out b/tests/icmpv6-ra-pref64-v1.out
new file mode 100644 (file)
index 0000000..ded5edc
--- /dev/null
@@ -0,0 +1,20 @@
+    1  2023-12-04 20:18:21.401201 IP6 (flowlabel 0x9fc72, hlim 255, next-header ICMPv6 (58), payload length 72) fe80::e015:81ff:feb4:b945 > ff02::1: [icmp6 sum ok] ICMP6, router advertisement, length 72
+       hop limit 80, Flags [other stateful], pref medium, router lifetime 500s, reachable time 0ms, retrans timer 0ms
+         source link-address option (1), length 8 (1): e2:15:81:b4:b9:45
+         prefix info option (3), length 32 (4): 2001:db8:cc:dd::/64, Flags [onlink], valid time 3600s, pref. time 1800s
+         pref64 option (38), length 16 (2): 2001:db8:1:64:ff9b::/96 (plc 0), lifetime 0s
+    2  2023-12-04 20:18:24.401773 IP6 (flowlabel 0x9fc72, hlim 255, next-header ICMPv6 (58), payload length 72) fe80::e015:81ff:feb4:b945 > ff02::1: [icmp6 sum ok] ICMP6, router advertisement, length 72
+       hop limit 80, Flags [other stateful], pref medium, router lifetime 500s, reachable time 0ms, retrans timer 0ms
+         source link-address option (1), length 8 (1): e2:15:81:b4:b9:45
+         prefix info option (3), length 32 (4): 2001:db8:cc:dd::/64, Flags [onlink], valid time 3600s, pref. time 1800s
+         pref64 option (38), length 16 (2): 2001:db8:0:64:ff9b::/?? (plc 6), lifetime 1800s
+    3  2023-12-04 20:18:27.402345 IP6 (flowlabel 0x9fc72, hlim 255, next-header ICMPv6 (58), payload length 72) fe80::e015:81ff:feb4:b945 > ff02::1: [icmp6 sum ok] ICMP6, router advertisement, length 72
+       hop limit 80, Flags [other stateful], pref medium, router lifetime 500s, reachable time 0ms, retrans timer 0ms
+         source link-address option (1), length 8 (1): e2:15:81:b4:b9:45
+         prefix info option (3), length 32 (4): 2a00:f480:cc:dd::/64, Flags [onlink], valid time 3600s, pref. time 1800s
+         pref64 option (38), length 16 (2): 2001:db8:0:64:ff9b::/96 (plc 0), lifetime 1800s
+    4  2023-12-04 20:18:30.402917 IP6 (flowlabel 0x9fc72, hlim 255, next-header ICMPv6 (58), payload length 72) fe80::e015:81ff:feb4:b945 > ff02::1: [icmp6 sum ok] ICMP6, router advertisement, length 72
+       hop limit 80, Flags [other stateful], pref medium, router lifetime 500s, reachable time 0ms, retrans timer 0ms
+         source link-address option (1), length 8 (1): e2:15:81:b4:b9:45
+         prefix info option (3), length 32 (4): 2001:db8:cc:dd::/64, Flags [onlink], valid time 3600s, pref. time 1800s
+         pref64 option (38), length 16 (2): 2001:db8:0:64:ff9b::/96 (plc 0), lifetime 65528s
diff --git a/tests/icmpv6-ra-pref64-v2.out b/tests/icmpv6-ra-pref64-v2.out
new file mode 100644 (file)
index 0000000..51f9104
--- /dev/null
@@ -0,0 +1,36 @@
+    1  2023-12-04 20:18:21.401201 IP6 (flowlabel 0x9fc72, hlim 255, next-header ICMPv6 (58), payload length 72) fe80::e015:81ff:feb4:b945 > ff02::1: [icmp6 sum ok] ICMP6, router advertisement, length 72
+       hop limit 80, Flags [other stateful], pref medium, router lifetime 500s, reachable time 0ms, retrans timer 0ms
+         source link-address option (1), length 8 (1): e2:15:81:b4:b9:45
+           0x0000:  e215 81b4 b945
+         prefix info option (3), length 32 (4): 2001:db8:cc:dd::/64, Flags [onlink], valid time 3600s, pref. time 1800s
+           0x0000:  4080 0000 0e10 0000 0708 0000 0000 2001
+           0x0010:  0db8 00cc 00dd 0000 0000 0000 0000
+         pref64 option (38), length 16 (2): 2001:db8:1:64:ff9b::/96 (plc 0), lifetime 0s
+           0x0000:  0000 2001 0db8 0001 0064 ff9b 0000
+    2  2023-12-04 20:18:24.401773 IP6 (flowlabel 0x9fc72, hlim 255, next-header ICMPv6 (58), payload length 72) fe80::e015:81ff:feb4:b945 > ff02::1: [icmp6 sum ok] ICMP6, router advertisement, length 72
+       hop limit 80, Flags [other stateful], pref medium, router lifetime 500s, reachable time 0ms, retrans timer 0ms
+         source link-address option (1), length 8 (1): e2:15:81:b4:b9:45
+           0x0000:  e215 81b4 b945
+         prefix info option (3), length 32 (4): 2001:db8:cc:dd::/64, Flags [onlink], valid time 3600s, pref. time 1800s
+           0x0000:  4080 0000 0e10 0000 0708 0000 0000 2001
+           0x0010:  0db8 00cc 00dd 0000 0000 0000 0000
+         pref64 option (38), length 16 (2): 2001:db8:0:64:ff9b::/?? (plc 6), lifetime 1800s
+           0x0000:  070e 2001 0db8 0000 0064 ff9b 0000
+    3  2023-12-04 20:18:27.402345 IP6 (flowlabel 0x9fc72, hlim 255, next-header ICMPv6 (58), payload length 72) fe80::e015:81ff:feb4:b945 > ff02::1: [icmp6 sum ok] ICMP6, router advertisement, length 72
+       hop limit 80, Flags [other stateful], pref medium, router lifetime 500s, reachable time 0ms, retrans timer 0ms
+         source link-address option (1), length 8 (1): e2:15:81:b4:b9:45
+           0x0000:  e215 81b4 b945
+         prefix info option (3), length 32 (4): 2a00:f480:cc:dd::/64, Flags [onlink], valid time 3600s, pref. time 1800s
+           0x0000:  4080 0000 0e10 0000 0708 0000 0000 2a00
+           0x0010:  f480 00cc 00dd 0000 0000 0000 0000
+         pref64 option (38), length 16 (2): 2001:db8:0:64:ff9b::/96 (plc 0), lifetime 1800s
+           0x0000:  0708 2001 0db8 0000 0064 ff9b 0000
+    4  2023-12-04 20:18:30.402917 IP6 (flowlabel 0x9fc72, hlim 255, next-header ICMPv6 (58), payload length 72) fe80::e015:81ff:feb4:b945 > ff02::1: [icmp6 sum ok] ICMP6, router advertisement, length 72
+       hop limit 80, Flags [other stateful], pref medium, router lifetime 500s, reachable time 0ms, retrans timer 0ms
+         source link-address option (1), length 8 (1): e2:15:81:b4:b9:45
+           0x0000:  e215 81b4 b945
+         prefix info option (3), length 32 (4): 2001:db8:cc:dd::/64, Flags [onlink], valid time 3600s, pref. time 1800s
+           0x0000:  4080 0000 0e10 0000 0708 0000 0000 2001
+           0x0010:  0db8 00cc 00dd 0000 0000 0000 0000
+         pref64 option (38), length 16 (2): 2001:db8:0:64:ff9b::/96 (plc 0), lifetime 65528s
+           0x0000:  fff8 2001 0db8 0000 0064 ff9b 0000
diff --git a/tests/icmpv6-ra-pref64.pcap b/tests/icmpv6-ra-pref64.pcap
new file mode 100644 (file)
index 0000000..4a40597
Binary files /dev/null and b/tests/icmpv6-ra-pref64.pcap differ