summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHauke Mehrtens2026-05-23 12:21:10 +0000
committerHauke Mehrtens2026-06-18 00:35:05 +0000
commit9c785500a99004b3500a244c2cc00b09909b6213 (patch)
tree823bdedf4b188391647e5c1ed2d7f5455989c0b3
parent35536135685620cf51191e21ae3458ca1741d094 (diff)
downloadodhcpd-9c785500a99004b3500a244c2cc00b09909b6213.tar.gz
ndp: enforce RFC4861 §7.1.1 hop-limit and ICMP-code checks on NS
handle_solicit() previously trusted whatever the AF_PACKET socket delivered, so a Neighbor Solicitation with Hop Limit < 255 or a non-zero ICMP Code was forwarded to peer interfaces (triggering proxy NDP lookups and an NA on the requesting interface). RFC4861 §7.1.1 requires NS messages with those properties to be silently discarded — the hop-limit rule in particular is what prevents off-link attackers from forging NS / DAD packets onto our link. The router.c equivalent (router_icmpv6_valid + the IPV6_RECVHOPLIMIT cmsg check in odhcpd_receive_packets) already does this for RA/RS; the NDP path needs to enforce it itself because AF_PACKET sees raw frames with no kernel-side L3 validation. Assisted-by: Claude:claude-opus-4-7 Link: https://github.com/openwrt/odhcpd/pull/401 Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de> (cherry picked from commit 0eade3d4b7a37106f6498f4ce952ecd6ec1b932d)
-rw-r--r--src/ndp.c9
1 files changed, 9 insertions, 0 deletions
diff --git a/src/ndp.c b/src/ndp.c
index 9257869..d97b4da 100644
--- a/src/ndp.c
+++ b/src/ndp.c
@@ -382,6 +382,15 @@ static void handle_solicit(void *addr, void *data, size_t len,
if (len < sizeof(*ip6) + sizeof(*req))
return; // Invalid total length
+ /* RFC4861 §7.1.1: a Neighbor Solicitation MUST be silently discarded
+ * if the IP Hop Limit field is not 255 or the ICMP Code is non-zero.
+ * The hop-limit check is what protects against off-link attackers
+ * forging NS / DAD messages, so it must not be skipped. Because the
+ * NDP socket is AF_PACKET (not a kernel-managed ICMPv6 socket), we
+ * have to enforce it ourselves. */
+ if (ip6->ip6_hlim != 255 || req->nd_ns_hdr.icmp6_code != 0)
+ return;
+
if (IN6_IS_ADDR_LINKLOCAL(&req->nd_ns_target) ||
IN6_IS_ADDR_LOOPBACK(&req->nd_ns_target) ||
IN6_IS_ADDR_MULTICAST(&req->nd_ns_target))