|
| 1 | +diff --git a/src/net/netip/inlining_test.go b/src/net/netip/inlining_test.go |
| 2 | +index 107fe1f083..1250c37725 100644 |
| 3 | +--- a/src/net/netip/inlining_test.go |
| 4 | ++++ b/src/net/netip/inlining_test.go |
| 5 | +@@ -41,8 +41,6 @@ func TestInlining(t *testing.T) { |
| 6 | + "Addr.Is4", |
| 7 | + "Addr.Is4In6", |
| 8 | + "Addr.Is6", |
| 9 | +- "Addr.IsLoopback", |
| 10 | +- "Addr.IsMulticast", |
| 11 | + "Addr.IsInterfaceLocalMulticast", |
| 12 | + "Addr.IsValid", |
| 13 | + "Addr.IsUnspecified", |
| 14 | +diff --git a/src/net/netip/netip.go b/src/net/netip/netip.go |
| 15 | +index f27984ab57..310e4e5bf4 100644 |
| 16 | +--- a/src/net/netip/netip.go |
| 17 | ++++ b/src/net/netip/netip.go |
| 18 | +@@ -75,6 +75,9 @@ var ( |
| 19 | + // address ff02::1. |
| 20 | + func IPv6LinkLocalAllNodes() Addr { return AddrFrom16([16]byte{0: 0xff, 1: 0x02, 15: 0x01}) } |
| 21 | + |
| 22 | ++// IPv6Loopback returns the IPv6 loopback address ::1. |
| 23 | ++func IPv6Loopback() Addr { return AddrFrom16([16]byte{15: 0x01}) } |
| 24 | ++ |
| 25 | + // IPv6Unspecified returns the IPv6 unspecified address "::". |
| 26 | + func IPv6Unspecified() Addr { return Addr{z: z6noz} } |
| 27 | + |
| 28 | +@@ -515,6 +518,9 @@ func (ip Addr) hasZone() bool { |
| 29 | + |
| 30 | + // IsLinkLocalUnicast reports whether ip is a link-local unicast address. |
| 31 | + func (ip Addr) IsLinkLocalUnicast() bool { |
| 32 | ++ if ip.Is4In6() { |
| 33 | ++ ip = ip.Unmap() |
| 34 | ++ } |
| 35 | + // Dynamic Configuration of IPv4 Link-Local Addresses |
| 36 | + // https://datatracker.ietf.org/doc/html/rfc3927#section-2.1 |
| 37 | + if ip.Is4() { |
| 38 | +@@ -530,6 +536,9 @@ func (ip Addr) IsLinkLocalUnicast() bool { |
| 39 | + |
| 40 | + // IsLoopback reports whether ip is a loopback address. |
| 41 | + func (ip Addr) IsLoopback() bool { |
| 42 | ++ if ip.Is4In6() { |
| 43 | ++ ip = ip.Unmap() |
| 44 | ++ } |
| 45 | + // Requirements for Internet Hosts -- Communication Layers (3.2.1.3 Addressing) |
| 46 | + // https://datatracker.ietf.org/doc/html/rfc1122#section-3.2.1.3 |
| 47 | + if ip.Is4() { |
| 48 | +@@ -545,6 +554,9 @@ func (ip Addr) IsLoopback() bool { |
| 49 | + |
| 50 | + // IsMulticast reports whether ip is a multicast address. |
| 51 | + func (ip Addr) IsMulticast() bool { |
| 52 | ++ if ip.Is4In6() { |
| 53 | ++ ip = ip.Unmap() |
| 54 | ++ } |
| 55 | + // Host Extensions for IP Multicasting (4. HOST GROUP ADDRESSES) |
| 56 | + // https://datatracker.ietf.org/doc/html/rfc1112#section-4 |
| 57 | + if ip.Is4() { |
| 58 | +@@ -563,7 +575,7 @@ func (ip Addr) IsMulticast() bool { |
| 59 | + func (ip Addr) IsInterfaceLocalMulticast() bool { |
| 60 | + // IPv6 Addressing Architecture (2.7.1. Pre-Defined Multicast Addresses) |
| 61 | + // https://datatracker.ietf.org/doc/html/rfc4291#section-2.7.1 |
| 62 | +- if ip.Is6() { |
| 63 | ++ if ip.Is6() && !ip.Is4In6() { |
| 64 | + return ip.v6u16(0)&0xff0f == 0xff01 |
| 65 | + } |
| 66 | + return false // zero value |
| 67 | +@@ -571,6 +583,9 @@ func (ip Addr) IsInterfaceLocalMulticast() bool { |
| 68 | + |
| 69 | + // IsLinkLocalMulticast reports whether ip is a link-local multicast address. |
| 70 | + func (ip Addr) IsLinkLocalMulticast() bool { |
| 71 | ++ if ip.Is4In6() { |
| 72 | ++ ip = ip.Unmap() |
| 73 | ++ } |
| 74 | + // IPv4 Multicast Guidelines (4. Local Network Control Block (224.0.0/24)) |
| 75 | + // https://datatracker.ietf.org/doc/html/rfc5771#section-4 |
| 76 | + if ip.Is4() { |
| 77 | +@@ -599,6 +614,9 @@ func (ip Addr) IsGlobalUnicast() bool { |
| 78 | + return false |
| 79 | + } |
| 80 | + |
| 81 | ++ if ip.Is4In6() { |
| 82 | ++ ip = ip.Unmap() |
| 83 | ++ } |
| 84 | + // Match package net's IsGlobalUnicast logic. Notably private IPv4 addresses |
| 85 | + // and ULA IPv6 addresses are still considered "global unicast". |
| 86 | + if ip.Is4() && (ip == IPv4Unspecified() || ip == AddrFrom4([4]byte{255, 255, 255, 255})) { |
| 87 | +@@ -616,6 +634,10 @@ func (ip Addr) IsGlobalUnicast() bool { |
| 88 | + // ip is in 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, or fc00::/7. This is the |
| 89 | + // same as net.IP.IsPrivate. |
| 90 | + func (ip Addr) IsPrivate() bool { |
| 91 | ++ if ip.Is4In6() { |
| 92 | ++ ip = ip.Unmap() |
| 93 | ++ } |
| 94 | ++ |
| 95 | + // Match the stdlib's IsPrivate logic. |
| 96 | + if ip.Is4() { |
| 97 | + // RFC 1918 allocates 10.0.0.0/8, 172.16.0.0/12, and 192.168.0.0/16 as |
| 98 | +diff --git a/src/net/netip/netip_test.go b/src/net/netip/netip_test.go |
| 99 | +index d988864827..c7e458af43 100644 |
| 100 | +--- a/src/net/netip/netip_test.go |
| 101 | ++++ b/src/net/netip/netip_test.go |
| 102 | +@@ -554,10 +554,13 @@ func TestIPProperties(t *testing.T) { |
| 103 | + ilm6 = mustIP("ff01::1") |
| 104 | + ilmZone6 = mustIP("ff01::1%eth0") |
| 105 | + |
| 106 | +- private4a = mustIP("10.0.0.1") |
| 107 | +- private4b = mustIP("172.16.0.1") |
| 108 | +- private4c = mustIP("192.168.1.1") |
| 109 | +- private6 = mustIP("fd00::1") |
| 110 | ++ private4a = mustIP("10.0.0.1") |
| 111 | ++ private4b = mustIP("172.16.0.1") |
| 112 | ++ private4c = mustIP("192.168.1.1") |
| 113 | ++ private6 = mustIP("fd00::1") |
| 114 | ++ private6mapped4a = mustIP("::ffff:10.0.0.1") |
| 115 | ++ private6mapped4b = mustIP("::ffff:172.16.0.1") |
| 116 | ++ private6mapped4c = mustIP("::ffff:192.168.1.1") |
| 117 | + |
| 118 | + unspecified4 = AddrFrom4([4]byte{}) |
| 119 | + unspecified6 = IPv6Unspecified() |
| 120 | +@@ -584,6 +587,11 @@ func TestIPProperties(t *testing.T) { |
| 121 | + ip: unicast4, |
| 122 | + globalUnicast: true, |
| 123 | + }, |
| 124 | ++ { |
| 125 | ++ name: "unicast v6 mapped v4Addr", |
| 126 | ++ ip: AddrFrom16(unicast4.As16()), |
| 127 | ++ globalUnicast: true, |
| 128 | ++ }, |
| 129 | + { |
| 130 | + name: "unicast v6Addr", |
| 131 | + ip: unicast6, |
| 132 | +@@ -605,6 +613,12 @@ func TestIPProperties(t *testing.T) { |
| 133 | + linkLocalMulticast: true, |
| 134 | + multicast: true, |
| 135 | + }, |
| 136 | ++ { |
| 137 | ++ name: "multicast v6 mapped v4Addr", |
| 138 | ++ ip: AddrFrom16(multicast4.As16()), |
| 139 | ++ linkLocalMulticast: true, |
| 140 | ++ multicast: true, |
| 141 | ++ }, |
| 142 | + { |
| 143 | + name: "multicast v6Addr", |
| 144 | + ip: multicast6, |
| 145 | +@@ -622,6 +636,11 @@ func TestIPProperties(t *testing.T) { |
| 146 | + ip: llu4, |
| 147 | + linkLocalUnicast: true, |
| 148 | + }, |
| 149 | ++ { |
| 150 | ++ name: "link-local unicast v6 mapped v4Addr", |
| 151 | ++ ip: AddrFrom16(llu4.As16()), |
| 152 | ++ linkLocalUnicast: true, |
| 153 | ++ }, |
| 154 | + { |
| 155 | + name: "link-local unicast v6Addr", |
| 156 | + ip: llu6, |
| 157 | +@@ -647,6 +666,11 @@ func TestIPProperties(t *testing.T) { |
| 158 | + ip: loopback6, |
| 159 | + loopback: true, |
| 160 | + }, |
| 161 | ++ { |
| 162 | ++ name: "loopback v6 mapped v4Addr", |
| 163 | ++ ip: AddrFrom16(IPv6Loopback().As16()), |
| 164 | ++ loopback: true, |
| 165 | ++ }, |
| 166 | + { |
| 167 | + name: "interface-local multicast v6Addr", |
| 168 | + ip: ilm6, |
| 169 | +@@ -683,6 +707,24 @@ func TestIPProperties(t *testing.T) { |
| 170 | + globalUnicast: true, |
| 171 | + private: true, |
| 172 | + }, |
| 173 | ++ { |
| 174 | ++ name: "private v6 mapped v4Addr 10/8", |
| 175 | ++ ip: private6mapped4a, |
| 176 | ++ globalUnicast: true, |
| 177 | ++ private: true, |
| 178 | ++ }, |
| 179 | ++ { |
| 180 | ++ name: "private v6 mapped v4Addr 172.16/12", |
| 181 | ++ ip: private6mapped4b, |
| 182 | ++ globalUnicast: true, |
| 183 | ++ private: true, |
| 184 | ++ }, |
| 185 | ++ { |
| 186 | ++ name: "private v6 mapped v4Addr 192.168/16", |
| 187 | ++ ip: private6mapped4c, |
| 188 | ++ globalUnicast: true, |
| 189 | ++ private: true, |
| 190 | ++ }, |
| 191 | + { |
| 192 | + name: "unspecified v4Addr", |
| 193 | + ip: unspecified4, |
0 commit comments