github.com/ice-blockchain/go/src@v0.0.0-20240403114104-1564d284e521/net/netip/fuzz_test.go (about) 1 // Copyright 2021 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package netip_test 6 7 import ( 8 "bytes" 9 "encoding" 10 "fmt" 11 "net" 12 . "net/netip" 13 "reflect" 14 "strings" 15 "testing" 16 ) 17 18 var corpus = []string{ 19 // Basic zero IPv4 address. 20 "0.0.0.0", 21 // Basic non-zero IPv4 address. 22 "192.168.140.255", 23 // IPv4 address in windows-style "print all the digits" form. 24 "010.000.015.001", 25 // IPv4 address with a silly amount of leading zeros. 26 "000001.00000002.00000003.000000004", 27 // 4-in-6 with octet with leading zero 28 "::ffff:1.2.03.4", 29 // Basic zero IPv6 address. 30 "::", 31 // Localhost IPv6. 32 "::1", 33 // Fully expanded IPv6 address. 34 "fd7a:115c:a1e0:ab12:4843:cd96:626b:430b", 35 // IPv6 with elided fields in the middle. 36 "fd7a:115c::626b:430b", 37 // IPv6 with elided fields at the end. 38 "fd7a:115c:a1e0:ab12:4843:cd96::", 39 // IPv6 with single elided field at the end. 40 "fd7a:115c:a1e0:ab12:4843:cd96:626b::", 41 "fd7a:115c:a1e0:ab12:4843:cd96:626b:0", 42 // IPv6 with single elided field in the middle. 43 "fd7a:115c:a1e0::4843:cd96:626b:430b", 44 "fd7a:115c:a1e0:0:4843:cd96:626b:430b", 45 // IPv6 with the trailing 32 bits written as IPv4 dotted decimal. (4in6) 46 "::ffff:192.168.140.255", 47 "::ffff:192.168.140.255", 48 // IPv6 with a zone specifier. 49 "fd7a:115c:a1e0:ab12:4843:cd96:626b:430b%eth0", 50 // IPv6 with dotted decimal and zone specifier. 51 "1:2::ffff:192.168.140.255%eth1", 52 "1:2::ffff:c0a8:8cff%eth1", 53 // IPv6 with capital letters. 54 "FD9E:1A04:F01D::1", 55 "fd9e:1a04:f01d::1", 56 // Empty string. 57 "", 58 // Garbage non-IP. 59 "bad", 60 // Single number. Some parsers accept this as an IPv4 address in 61 // big-endian uint32 form, but we don't. 62 "1234", 63 // IPv4 with a zone specifier. 64 "1.2.3.4%eth0", 65 // IPv4 field must have at least one digit. 66 ".1.2.3", 67 "1.2.3.", 68 "1..2.3", 69 // IPv4 address too long. 70 "1.2.3.4.5", 71 // IPv4 in dotted octal form. 72 "0300.0250.0214.0377", 73 // IPv4 in dotted hex form. 74 "0xc0.0xa8.0x8c.0xff", 75 // IPv4 in class B form. 76 "192.168.12345", 77 // IPv4 in class B form, with a small enough number to be 78 // parseable as a regular dotted decimal field. 79 "127.0.1", 80 // IPv4 in class A form. 81 "192.1234567", 82 // IPv4 in class A form, with a small enough number to be 83 // parseable as a regular dotted decimal field. 84 "127.1", 85 // IPv4 field has value >255. 86 "192.168.300.1", 87 // IPv4 with too many fields. 88 "192.168.0.1.5.6", 89 // IPv6 with not enough fields. 90 "1:2:3:4:5:6:7", 91 // IPv6 with too many fields. 92 "1:2:3:4:5:6:7:8:9", 93 // IPv6 with 8 fields and a :: expander. 94 "1:2:3:4::5:6:7:8", 95 // IPv6 with a field bigger than 2b. 96 "fe801::1", 97 // IPv6 with non-hex values in field. 98 "fe80:tail:scal:e::", 99 // IPv6 with a zone delimiter but no zone. 100 "fe80::1%", 101 // IPv6 with a zone specifier of zero. 102 "::ffff:0:0%0", 103 // IPv6 (without ellipsis) with too many fields for trailing embedded IPv4. 104 "ffff:ffff:ffff:ffff:ffff:ffff:ffff:192.168.140.255", 105 // IPv6 (with ellipsis) with too many fields for trailing embedded IPv4. 106 "ffff::ffff:ffff:ffff:ffff:ffff:ffff:192.168.140.255", 107 // IPv6 with invalid embedded IPv4. 108 "::ffff:192.168.140.bad", 109 // IPv6 with multiple ellipsis ::. 110 "fe80::1::1", 111 // IPv6 with invalid non hex/colon character. 112 "fe80:1?:1", 113 // IPv6 with truncated bytes after single colon. 114 "fe80:", 115 // AddrPort strings. 116 "1.2.3.4:51820", 117 "[fd7a:115c:a1e0:ab12:4843:cd96:626b:430b]:80", 118 "[::ffff:c000:0280]:65535", 119 "[::ffff:c000:0280%eth0]:1", 120 // Prefix strings. 121 "1.2.3.4/24", 122 "fd7a:115c:a1e0:ab12:4843:cd96:626b:430b/118", 123 "::ffff:c000:0280/96", 124 "::ffff:c000:0280%eth0/37", 125 } 126 127 func FuzzParse(f *testing.F) { 128 for _, seed := range corpus { 129 f.Add(seed) 130 } 131 132 f.Fuzz(func(t *testing.T, s string) { 133 ip, _ := ParseAddr(s) 134 checkStringParseRoundTrip(t, ip, ParseAddr) 135 checkEncoding(t, ip) 136 137 // Check that we match the net's IP parser, modulo zones. 138 if !strings.Contains(s, "%") { 139 stdip := net.ParseIP(s) 140 if !ip.IsValid() != (stdip == nil) { 141 t.Errorf("ParseAddr zero != net.ParseIP nil: ip=%q stdip=%q", ip, stdip) 142 } 143 144 if ip.IsValid() && !ip.Is4In6() { 145 buf, err := ip.MarshalText() 146 if err != nil { 147 t.Fatal(err) 148 } 149 buf2, err := stdip.MarshalText() 150 if err != nil { 151 t.Fatal(err) 152 } 153 if !bytes.Equal(buf, buf2) { 154 t.Errorf("Addr.MarshalText() != net.IP.MarshalText(): ip=%q stdip=%q", ip, stdip) 155 } 156 if ip.String() != stdip.String() { 157 t.Errorf("Addr.String() != net.IP.String(): ip=%q stdip=%q", ip, stdip) 158 } 159 if ip.IsGlobalUnicast() != stdip.IsGlobalUnicast() { 160 t.Errorf("Addr.IsGlobalUnicast() != net.IP.IsGlobalUnicast(): ip=%q stdip=%q", ip, stdip) 161 } 162 if ip.IsInterfaceLocalMulticast() != stdip.IsInterfaceLocalMulticast() { 163 t.Errorf("Addr.IsInterfaceLocalMulticast() != net.IP.IsInterfaceLocalMulticast(): ip=%q stdip=%q", ip, stdip) 164 } 165 if ip.IsLinkLocalMulticast() != stdip.IsLinkLocalMulticast() { 166 t.Errorf("Addr.IsLinkLocalMulticast() != net.IP.IsLinkLocalMulticast(): ip=%q stdip=%q", ip, stdip) 167 } 168 if ip.IsLinkLocalUnicast() != stdip.IsLinkLocalUnicast() { 169 t.Errorf("Addr.IsLinkLocalUnicast() != net.IP.IsLinkLocalUnicast(): ip=%q stdip=%q", ip, stdip) 170 } 171 if ip.IsLoopback() != stdip.IsLoopback() { 172 t.Errorf("Addr.IsLoopback() != net.IP.IsLoopback(): ip=%q stdip=%q", ip, stdip) 173 } 174 if ip.IsMulticast() != stdip.IsMulticast() { 175 t.Errorf("Addr.IsMulticast() != net.IP.IsMulticast(): ip=%q stdip=%q", ip, stdip) 176 } 177 if ip.IsPrivate() != stdip.IsPrivate() { 178 t.Errorf("Addr.IsPrivate() != net.IP.IsPrivate(): ip=%q stdip=%q", ip, stdip) 179 } 180 if ip.IsUnspecified() != stdip.IsUnspecified() { 181 t.Errorf("Addr.IsUnspecified() != net.IP.IsUnspecified(): ip=%q stdip=%q", ip, stdip) 182 } 183 } 184 } 185 186 // Check that .Next().Prev() and .Prev().Next() preserve the IP. 187 if ip.IsValid() && ip.Next().IsValid() && ip.Next().Prev() != ip { 188 t.Errorf(".Next.Prev did not round trip: ip=%q .next=%q .next.prev=%q", ip, ip.Next(), ip.Next().Prev()) 189 } 190 if ip.IsValid() && ip.Prev().IsValid() && ip.Prev().Next() != ip { 191 t.Errorf(".Prev.Next did not round trip: ip=%q .prev=%q .prev.next=%q", ip, ip.Prev(), ip.Prev().Next()) 192 } 193 194 port, err := ParseAddrPort(s) 195 if err == nil { 196 checkStringParseRoundTrip(t, port, ParseAddrPort) 197 checkEncoding(t, port) 198 } 199 port = AddrPortFrom(ip, 80) 200 checkStringParseRoundTrip(t, port, ParseAddrPort) 201 checkEncoding(t, port) 202 203 ipp, err := ParsePrefix(s) 204 if err == nil { 205 checkStringParseRoundTrip(t, ipp, ParsePrefix) 206 checkEncoding(t, ipp) 207 } 208 ipp = PrefixFrom(ip, 8) 209 checkStringParseRoundTrip(t, ipp, ParsePrefix) 210 checkEncoding(t, ipp) 211 }) 212 } 213 214 // checkTextMarshaler checks that x's MarshalText and UnmarshalText functions round trip correctly. 215 func checkTextMarshaler(t *testing.T, x encoding.TextMarshaler) { 216 buf, err := x.MarshalText() 217 if err != nil { 218 t.Fatal(err) 219 } 220 y := reflect.New(reflect.TypeOf(x)).Interface().(encoding.TextUnmarshaler) 221 err = y.UnmarshalText(buf) 222 if err != nil { 223 t.Logf("(%v).MarshalText() = %q", x, buf) 224 t.Fatalf("(%T).UnmarshalText(%q) = %v", y, buf, err) 225 } 226 e := reflect.ValueOf(y).Elem().Interface() 227 if !reflect.DeepEqual(x, e) { 228 t.Logf("(%v).MarshalText() = %q", x, buf) 229 t.Logf("(%T).UnmarshalText(%q) = %v", y, buf, y) 230 t.Fatalf("MarshalText/UnmarshalText failed to round trip: %#v != %#v", x, e) 231 } 232 buf2, err := y.(encoding.TextMarshaler).MarshalText() 233 if err != nil { 234 t.Logf("(%v).MarshalText() = %q", x, buf) 235 t.Logf("(%T).UnmarshalText(%q) = %v", y, buf, y) 236 t.Fatalf("failed to MarshalText a second time: %v", err) 237 } 238 if !bytes.Equal(buf, buf2) { 239 t.Logf("(%v).MarshalText() = %q", x, buf) 240 t.Logf("(%T).UnmarshalText(%q) = %v", y, buf, y) 241 t.Logf("(%v).MarshalText() = %q", y, buf2) 242 t.Fatalf("second MarshalText differs from first: %q != %q", buf, buf2) 243 } 244 } 245 246 // checkBinaryMarshaler checks that x's MarshalText and UnmarshalText functions round trip correctly. 247 func checkBinaryMarshaler(t *testing.T, x encoding.BinaryMarshaler) { 248 buf, err := x.MarshalBinary() 249 if err != nil { 250 t.Fatal(err) 251 } 252 y := reflect.New(reflect.TypeOf(x)).Interface().(encoding.BinaryUnmarshaler) 253 err = y.UnmarshalBinary(buf) 254 if err != nil { 255 t.Logf("(%v).MarshalBinary() = %q", x, buf) 256 t.Fatalf("(%T).UnmarshalBinary(%q) = %v", y, buf, err) 257 } 258 e := reflect.ValueOf(y).Elem().Interface() 259 if !reflect.DeepEqual(x, e) { 260 t.Logf("(%v).MarshalBinary() = %q", x, buf) 261 t.Logf("(%T).UnmarshalBinary(%q) = %v", y, buf, y) 262 t.Fatalf("MarshalBinary/UnmarshalBinary failed to round trip: %#v != %#v", x, e) 263 } 264 buf2, err := y.(encoding.BinaryMarshaler).MarshalBinary() 265 if err != nil { 266 t.Logf("(%v).MarshalBinary() = %q", x, buf) 267 t.Logf("(%T).UnmarshalBinary(%q) = %v", y, buf, y) 268 t.Fatalf("failed to MarshalBinary a second time: %v", err) 269 } 270 if !bytes.Equal(buf, buf2) { 271 t.Logf("(%v).MarshalBinary() = %q", x, buf) 272 t.Logf("(%T).UnmarshalBinary(%q) = %v", y, buf, y) 273 t.Logf("(%v).MarshalBinary() = %q", y, buf2) 274 t.Fatalf("second MarshalBinary differs from first: %q != %q", buf, buf2) 275 } 276 } 277 278 func checkTextMarshalMatchesString(t *testing.T, x netipType) { 279 buf, err := x.MarshalText() 280 if err != nil { 281 t.Fatal(err) 282 } 283 str := x.String() 284 if string(buf) != str { 285 t.Fatalf("%v: MarshalText = %q, String = %q", x, buf, str) 286 } 287 } 288 289 type appendMarshaler interface { 290 encoding.TextMarshaler 291 AppendTo([]byte) []byte 292 } 293 294 // checkTextMarshalMatchesAppendTo checks that x's MarshalText matches x's AppendTo. 295 func checkTextMarshalMatchesAppendTo(t *testing.T, x appendMarshaler) { 296 buf, err := x.MarshalText() 297 if err != nil { 298 t.Fatal(err) 299 } 300 301 buf2 := make([]byte, 0, len(buf)) 302 buf2 = x.AppendTo(buf2) 303 if !bytes.Equal(buf, buf2) { 304 t.Fatalf("%v: MarshalText = %q, AppendTo = %q", x, buf, buf2) 305 } 306 } 307 308 type netipType interface { 309 encoding.BinaryMarshaler 310 encoding.TextMarshaler 311 fmt.Stringer 312 IsValid() bool 313 } 314 315 type netipTypeCmp interface { 316 comparable 317 netipType 318 } 319 320 // checkStringParseRoundTrip checks that x's String method and the provided parse function can round trip correctly. 321 func checkStringParseRoundTrip[P netipTypeCmp](t *testing.T, x P, parse func(string) (P, error)) { 322 if !x.IsValid() { 323 // Ignore invalid values. 324 return 325 } 326 327 s := x.String() 328 y, err := parse(s) 329 if err != nil { 330 t.Fatalf("s=%q err=%v", s, err) 331 } 332 if x != y { 333 t.Fatalf("%T round trip identity failure: s=%q x=%#v y=%#v", x, s, x, y) 334 } 335 s2 := y.String() 336 if s != s2 { 337 t.Fatalf("%T String round trip identity failure: s=%#v s2=%#v", x, s, s2) 338 } 339 } 340 341 func checkEncoding(t *testing.T, x netipType) { 342 if x.IsValid() { 343 checkTextMarshaler(t, x) 344 checkBinaryMarshaler(t, x) 345 checkTextMarshalMatchesString(t, x) 346 } 347 348 if am, ok := x.(appendMarshaler); ok { 349 checkTextMarshalMatchesAppendTo(t, am) 350 } 351 }