wire: fix IPv4-mapped IPv6 addresses using wrong networkID in addrv2
What changed, and why it matters
This commit fixes a bug where IPv4 addresses were accidentally advertised as IPv6 addresses on the Bitcoin peer-to-peer network. Because of how Go stores IP addresses internally, a 16-byte IPv4-mapped IPv6 representation was being tagged with the IPv6 network type. Bitcoin Core silently ignores such mixed messages, so affected btcd nodes could have had their address announcements ignored by peers, potentially hurting connectivity and peer discovery. There is no direct evidence this was exploited as an attack.
Apply the patch. Monitor for any peer connectivity or address relay anomalies on nodes running the unfixed code. Consider adding tests for IPv4-mapped IPv6 handling in addrv2 serialization/deserialization.
Security signals we found
Protocol-layer address misclassification
Peer-to-peer network address propagation issue
Interoperability failure with Bitcoin Core
Potential peer connectivity / eclipse-related side effects
No input validation bypass or memory corruption evident
Evidence from the diff
In wire/netaddressv2.go, NetAddressV2FromBytes dispatches the networkID based on the byte length of the address. Go’s net.ParseIP stores IPv4 addresses as 16-byte IPv4-mapped IPv6 addresses (::ffff:x.x.x.x), so they were being serialized with networkID 0x02 (IPv6) instead of 0x01 (IPv4). The patch detects the ::ffff:0:0/96 prefix via isIPv4Mapped and extracts the trailing 4 bytes as a proper IPv4 addrv2 entry. The commit message notes Bitcoin Core drops these malformed addrv2 entries silently.
Changed components
wire/netaddressv2.goNetAddressV2FromBytes functionBitcoin P2P addrv2 message handlingInspect captured patch +13 / −0
diff --git a/wire/netaddressv2.go b/wire/netaddressv2.go
index 767ef3c..f514832 100644
--- a/wire/netaddressv2.go
+++ b/wire/netaddressv2.go
@@ -181,6 +181,19 @@ func NetAddressV2FromBytes(timestamp time.Time, services ServiceFlag,
break
}
+ // IPv4-mapped IPv6 addresses (::ffff:0:0/96) should use the
+ // IPv4 networkID. Bitcoin Core silently drops IPv6 addrv2
+ // entries with this prefix. Go's net.IP commonly stores
+ // IPv4 addresses in this 16-byte form, so extract the
+ // 4-byte IPv4 address.
+ if isIPv4Mapped(addrBytes) {
+ addr := &ipv4Addr{}
+ addr.netID = ipv4
+ copy(addr.addr[:], addrBytes[12:])
+ netAddr = addr
+ break
+ }
+
addr := &ipv6Addr{}
addr.netID = ipv6
copy(addr.addr[:], addrBytes)
Why this scored 51/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.