Source file
src/net/netip/fuzz_test.go
1
2
3
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
20 "0.0.0.0",
21
22 "192.168.140.255",
23
24 "010.000.015.001",
25
26 "000001.00000002.00000003.000000004",
27
28 "::ffff:1.2.03.4",
29
30 "::",
31
32 "::1",
33
34 "fd7a:115c:a1e0:ab12:4843:cd96:626b:430b",
35
36 "fd7a:115c::626b:430b",
37
38 "fd7a:115c:a1e0:ab12:4843:cd96::",
39
40 "fd7a:115c:a1e0:ab12:4843:cd96:626b::",
41 "fd7a:115c:a1e0:ab12:4843:cd96:626b:0",
42
43 "fd7a:115c:a1e0::4843:cd96:626b:430b",
44 "fd7a:115c:a1e0:0:4843:cd96:626b:430b",
45
46 "::ffff:192.168.140.255",
47 "::ffff:192.168.140.255",
48
49 "fd7a:115c:a1e0:ab12:4843:cd96:626b:430b%eth0",
50
51 "1:2::ffff:192.168.140.255%eth1",
52 "1:2::ffff:c0a8:8cff%eth1",
53
54 "FD9E:1A04:F01D::1",
55 "fd9e:1a04:f01d::1",
56
57 "",
58
59 "bad",
60
61
62 "1234",
63
64 "1.2.3.4%eth0",
65
66 ".1.2.3",
67 "1.2.3.",
68 "1..2.3",
69
70 "1.2.3.4.5",
71
72 "0300.0250.0214.0377",
73
74 "0xc0.0xa8.0x8c.0xff",
75
76 "192.168.12345",
77
78
79 "127.0.1",
80
81 "192.1234567",
82
83
84 "127.1",
85
86 "192.168.300.1",
87
88 "192.168.0.1.5.6",
89
90 "1:2:3:4:5:6:7",
91
92 "1:2:3:4:5:6:7:8:9",
93
94 "1:2:3:4::5:6:7:8",
95
96 "fe801::1",
97
98 "fe80:tail:scal:e::",
99
100 "fe80::1%",
101
102 "::ffff:0:0%0",
103
104 "ffff:ffff:ffff:ffff:ffff:ffff:ffff:192.168.140.255",
105
106 "ffff::ffff:ffff:ffff:ffff:ffff:ffff:192.168.140.255",
107
108 "::ffff:192.168.140.bad",
109
110 "fe80::1::1",
111
112 "fe80:1?:1",
113
114 "fe80:",
115
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
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
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
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
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
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
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
321 func checkStringParseRoundTrip[P netipTypeCmp](t *testing.T, x P, parse func(string) (P, error)) {
322 if !x.IsValid() {
323
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 }
352
View as plain text