# DF-2609 — ICMPv6 Node Information responder default-enabled disclosure

## What this proves

DragonFly ships `icmp6_nodeinfo = 3` (`sys/netinet6/in6_proto.c:398`). With
that default, the KAME node-information responder in `icmp6.c` answers
**unauthenticated** ICMPv6 NI queries (RFC 4620) addressed to **any unicast
address of the host**:

- **QTYPE FQDN, no subject** (code 0, subjlen 0 — the oldfqdn compat path,
  `icmp6.c:1182-1186`) returns the system hostname.
- **QTYPE NODEADDR** with scope flags (`icmp6.c:1278-1281` bit 1, gated only
  by the same sysctl) returns the host's complete IPv6 address inventory
  across all interfaces, including link-local scopes (`ni6_store_addrs`,
  `icmp6.c:1660-1806`).

Verified live on the audit guest: `sysctl net.inet6.icmp6.nodeinfo` = 3,
a single NI query to `::1` (and to a global unicast alias) returned
`hostname` = "dfbsd" and all 4 configured IPv6 addresses. A query to an
address that is not the host's own got **no reply** (negative control).
Setting the sysctl to 0 silences the responder completely (live fix check);
1 answers FQDN only; 2 would answer NODEADDR only.

No authentication, capability, or scope check is involved — any peer that
can route an IPv6 packet to the host gets this information. FreeBSD's
default for the same sysctl is 0.

## Files

- `niq.c`         NI query sender/receiver + reply parser (raw ICMPv6 socket)
- `build.sh`      build command
- `run.sh`        canonical run (queries, negative control, sysctl matrix)
- `run.log`       FULL untrimmed output of the canonical run
- `env.txt`       guest environment (uname, sysctls, interfaces)
- `fix.diff`      default flip 3 -> 0 (in6_proto.c)

## Reproduce

```
scp niq.c root@guest:/root/poc/
guest# cc -O2 -Wall -o niq niq.c && ./niq ::1 fqdn && ./niq ::1 nodeaddr 002e
```

Expected: `FQDN ttl=... name=<hostname>` and `NODEADDR[n] ...` lines listing
every IPv6 address of the host. `./niq <foreign-addr> fqdn` -> `NO REPLY`.

## Notes

- The query needs a raw ICMPv6 socket (root) only as an *injection
  convenience*; the responder itself answers any remotely-routed packet —
  the threat is the remote unauthenticated peer, not the local user.
- The NI reply itself carries no uninitialized/padding bytes: reply lengths
  are exact (`run.log` hexdumps; FQDN = 16B nodeinfo + 4B TTL + name,
  NODEADDR = 16B + 20B/addr). The disclosure is the *content* (hostname and
  address inventory), not memory.
