randomized clat dad nonce, send only one copy
this is to fully match observed behaviour of the Linux Kernel's DAD,
and to make the resulting packets indistinguishable
Bug: 238387793
Test: TreeHugger, manually on bramble with ipv6-only wifi network
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Change-Id: I2f041c066bb85dd083fb2d6e137b0a1fed41af54
diff --git a/clatd.c b/clatd.c
index 4ce94f7..9c3424e 100644
--- a/clatd.c
+++ b/clatd.c
@@ -138,7 +138,7 @@
// u128 tgt_ip6
// ICMPv6 ND options:
// u8 opt nr '14'; u8 length '1'; u8[6] nonce '6 random bytes'
-void send_dad(int fd, const struct in6_addr* tgt, int count) {
+void send_dad(int fd, const struct in6_addr* tgt) {
struct {
struct ip6_hdr ip6h;
struct nd_neighbor_solicit ns;
@@ -168,11 +168,9 @@
},
.ns_opt_nr = 14, // icmp6 option 'nonce' from RFC3971
.ns_opt_len = 1, // in units of 8 bytes, including option nr and len
- .ns_opt_nonce = { // 'opt_len' * 8 - [size of u8: opt nr] - [size of u8: opt len] = 6 bytes
- 0, 0, 'C', 'L', 'A', 'T',
- }, // first 2 bytes filled in below with random bytes, CLAT left to ease id in tcpdump
+ .ns_opt_nonce = {}, // opt_len *8 - sizeof u8(opt_nr) - sizeof u8(opt_len) = 6 ranodmized bytes
};
- arc4random_buf(&dad_pkt.ns_opt_nonce, 2);
+ arc4random_buf(&dad_pkt.ns_opt_nonce, sizeof(dad_pkt.ns_opt_nonce));
// 40 byte IPv6 header + 8 byte ICMPv6 header + 16 byte ipv6 target address + 8 byte nonce option
_Static_assert(sizeof(dad_pkt) == 40 + 8 + 16 + 8, "sizeof dad packet != 72");
@@ -198,9 +196,7 @@
.sin6_scope_id = if_nametoindex(Global_Clatd_Config.native_ipv6_interface),
};
- while (count--) {
- sendto(fd, &dad_pkt, sizeof(dad_pkt), 0 /*flags*/, (const struct sockaddr *)&dst, sizeof(dst));
- }
+ sendto(fd, &dad_pkt, sizeof(dad_pkt), 0 /*flags*/, (const struct sockaddr *)&dst, sizeof(dst));
}
/* function: event_loop
@@ -217,7 +213,7 @@
// (with the other 16 chosen to guarantee checksum neutrality) this seems like a remote
// concern...
// TODO: actually perform true DAD
- send_dad(tunnel->write_fd6, &Global_Clatd_Config.ipv6_local_subnet, 2);
+ send_dad(tunnel->write_fd6, &Global_Clatd_Config.ipv6_local_subnet);
time_t last_interface_poll;
struct pollfd wait_fd[] = {