1// Copyright 2012 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
5package net
6
7import (
8	"errors"
9	"fmt"
10	"internal/testenv"
11	"net/netip"
12	"os"
13	"reflect"
14	"runtime"
15	"testing"
16	"time"
17)
18
19func BenchmarkUDP6LinkLocalUnicast(b *testing.B) {
20	testHookUninstaller.Do(uninstallTestHooks)
21
22	if !supportsIPv6() {
23		b.Skip("IPv6 is not supported")
24	}
25	ifi := loopbackInterface()
26	if ifi == nil {
27		b.Skip("loopback interface not found")
28	}
29	lla := ipv6LinkLocalUnicastAddr(ifi)
30	if lla == "" {
31		b.Skip("IPv6 link-local unicast address not found")
32	}
33
34	c1, err := ListenPacket("udp6", JoinHostPort(lla+"%"+ifi.Name, "0"))
35	if err != nil {
36		b.Fatal(err)
37	}
38	defer c1.Close()
39	c2, err := ListenPacket("udp6", JoinHostPort(lla+"%"+ifi.Name, "0"))
40	if err != nil {
41		b.Fatal(err)
42	}
43	defer c2.Close()
44
45	var buf [1]byte
46	for i := 0; i < b.N; i++ {
47		if _, err := c1.WriteTo(buf[:], c2.LocalAddr()); err != nil {
48			b.Fatal(err)
49		}
50		if _, _, err := c2.ReadFrom(buf[:]); err != nil {
51			b.Fatal(err)
52		}
53	}
54}
55
56type resolveUDPAddrTest struct {
57	network       string
58	litAddrOrName string
59	addr          *UDPAddr
60	err           error
61}
62
63var resolveUDPAddrTests = []resolveUDPAddrTest{
64	{"udp", "127.0.0.1:0", &UDPAddr{IP: IPv4(127, 0, 0, 1), Port: 0}, nil},
65	{"udp4", "127.0.0.1:65535", &UDPAddr{IP: IPv4(127, 0, 0, 1), Port: 65535}, nil},
66
67	{"udp", "[::1]:0", &UDPAddr{IP: ParseIP("::1"), Port: 0}, nil},
68	{"udp6", "[::1]:65535", &UDPAddr{IP: ParseIP("::1"), Port: 65535}, nil},
69
70	{"udp", "[::1%en0]:1", &UDPAddr{IP: ParseIP("::1"), Port: 1, Zone: "en0"}, nil},
71	{"udp6", "[::1%911]:2", &UDPAddr{IP: ParseIP("::1"), Port: 2, Zone: "911"}, nil},
72
73	{"", "127.0.0.1:0", &UDPAddr{IP: IPv4(127, 0, 0, 1), Port: 0}, nil}, // Go 1.0 behavior
74	{"", "[::1]:0", &UDPAddr{IP: ParseIP("::1"), Port: 0}, nil},         // Go 1.0 behavior
75
76	{"udp", ":12345", &UDPAddr{Port: 12345}, nil},
77
78	{"http", "127.0.0.1:0", nil, UnknownNetworkError("http")},
79
80	{"udp", "127.0.0.1:domain", &UDPAddr{IP: ParseIP("127.0.0.1"), Port: 53}, nil},
81	{"udp", "[::ffff:127.0.0.1]:domain", &UDPAddr{IP: ParseIP("::ffff:127.0.0.1"), Port: 53}, nil},
82	{"udp", "[2001:db8::1]:domain", &UDPAddr{IP: ParseIP("2001:db8::1"), Port: 53}, nil},
83	{"udp4", "127.0.0.1:domain", &UDPAddr{IP: ParseIP("127.0.0.1"), Port: 53}, nil},
84	{"udp4", "[::ffff:127.0.0.1]:domain", &UDPAddr{IP: ParseIP("127.0.0.1"), Port: 53}, nil},
85	{"udp6", "[2001:db8::1]:domain", &UDPAddr{IP: ParseIP("2001:db8::1"), Port: 53}, nil},
86
87	{"udp4", "[2001:db8::1]:domain", nil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: "2001:db8::1"}},
88	{"udp6", "127.0.0.1:domain", nil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: "127.0.0.1"}},
89	{"udp6", "[::ffff:127.0.0.1]:domain", nil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: "::ffff:127.0.0.1"}},
90}
91
92func TestResolveUDPAddr(t *testing.T) {
93	origTestHookLookupIP := testHookLookupIP
94	defer func() { testHookLookupIP = origTestHookLookupIP }()
95	testHookLookupIP = lookupLocalhost
96
97	for _, tt := range resolveUDPAddrTests {
98		addr, err := ResolveUDPAddr(tt.network, tt.litAddrOrName)
99		if !reflect.DeepEqual(addr, tt.addr) || !reflect.DeepEqual(err, tt.err) {
100			t.Errorf("ResolveUDPAddr(%q, %q) = %#v, %v, want %#v, %v", tt.network, tt.litAddrOrName, addr, err, tt.addr, tt.err)
101			continue
102		}
103		if err == nil {
104			addr2, err := ResolveUDPAddr(addr.Network(), addr.String())
105			if !reflect.DeepEqual(addr2, tt.addr) || err != tt.err {
106				t.Errorf("(%q, %q): ResolveUDPAddr(%q, %q) = %#v, %v, want %#v, %v", tt.network, tt.litAddrOrName, addr.Network(), addr.String(), addr2, err, tt.addr, tt.err)
107			}
108		}
109	}
110}
111
112func TestWriteToUDP(t *testing.T) {
113	switch runtime.GOOS {
114	case "plan9":
115		t.Skipf("not supported on %s", runtime.GOOS)
116	}
117
118	if !testableNetwork("udp") {
119		t.Skipf("skipping: udp not supported")
120	}
121
122	c, err := ListenPacket("udp", "127.0.0.1:0")
123	if err != nil {
124		t.Fatal(err)
125	}
126	defer c.Close()
127
128	testWriteToConn(t, c.LocalAddr().String())
129	testWriteToPacketConn(t, c.LocalAddr().String())
130}
131
132func testWriteToConn(t *testing.T, raddr string) {
133	c, err := Dial("udp", raddr)
134	if err != nil {
135		t.Fatal(err)
136	}
137	defer c.Close()
138
139	ra, err := ResolveUDPAddr("udp", raddr)
140	if err != nil {
141		t.Fatal(err)
142	}
143
144	b := []byte("CONNECTED-MODE SOCKET")
145	_, err = c.(*UDPConn).WriteToUDP(b, ra)
146	if err == nil {
147		t.Fatal("should fail")
148	}
149	if err != nil && err.(*OpError).Err != ErrWriteToConnected {
150		t.Fatalf("should fail as ErrWriteToConnected: %v", err)
151	}
152	_, err = c.(*UDPConn).WriteTo(b, ra)
153	if err == nil {
154		t.Fatal("should fail")
155	}
156	if err != nil && err.(*OpError).Err != ErrWriteToConnected {
157		t.Fatalf("should fail as ErrWriteToConnected: %v", err)
158	}
159	_, err = c.Write(b)
160	if err != nil {
161		t.Fatal(err)
162	}
163	_, _, err = c.(*UDPConn).WriteMsgUDP(b, nil, ra)
164	if err == nil {
165		t.Fatal("should fail")
166	}
167	if err != nil && err.(*OpError).Err != ErrWriteToConnected {
168		t.Fatalf("should fail as ErrWriteToConnected: %v", err)
169	}
170	_, _, err = c.(*UDPConn).WriteMsgUDP(b, nil, nil)
171	if err != nil {
172		t.Fatal(err)
173	}
174}
175
176func testWriteToPacketConn(t *testing.T, raddr string) {
177	c, err := ListenPacket("udp", "127.0.0.1:0")
178	if err != nil {
179		t.Fatal(err)
180	}
181	defer c.Close()
182
183	ra, err := ResolveUDPAddr("udp", raddr)
184	if err != nil {
185		t.Fatal(err)
186	}
187
188	b := []byte("UNCONNECTED-MODE SOCKET")
189	_, err = c.(*UDPConn).WriteToUDP(b, ra)
190	if err != nil {
191		t.Fatal(err)
192	}
193	_, err = c.WriteTo(b, ra)
194	if err != nil {
195		t.Fatal(err)
196	}
197	_, err = c.(*UDPConn).Write(b)
198	if err == nil {
199		t.Fatal("should fail")
200	}
201	_, _, err = c.(*UDPConn).WriteMsgUDP(b, nil, nil)
202	if err == nil {
203		t.Fatal("should fail")
204	}
205	if err != nil && err.(*OpError).Err != errMissingAddress {
206		t.Fatalf("should fail as errMissingAddress: %v", err)
207	}
208	_, _, err = c.(*UDPConn).WriteMsgUDP(b, nil, ra)
209	if err != nil {
210		t.Fatal(err)
211	}
212}
213
214var udpConnLocalNameTests = []struct {
215	net   string
216	laddr *UDPAddr
217}{
218	{"udp4", &UDPAddr{IP: IPv4(127, 0, 0, 1)}},
219	{"udp4", &UDPAddr{}},
220	{"udp4", nil},
221}
222
223func TestUDPConnLocalName(t *testing.T) {
224	testenv.MustHaveExternalNetwork(t)
225
226	for _, tt := range udpConnLocalNameTests {
227		t.Run(fmt.Sprint(tt.laddr), func(t *testing.T) {
228			if !testableNetwork(tt.net) {
229				t.Skipf("skipping: %s not available", tt.net)
230			}
231
232			c, err := ListenUDP(tt.net, tt.laddr)
233			if err != nil {
234				t.Fatal(err)
235			}
236			defer c.Close()
237			la := c.LocalAddr()
238			if a, ok := la.(*UDPAddr); !ok || a.Port == 0 {
239				t.Fatalf("got %v; expected a proper address with non-zero port number", la)
240			}
241		})
242	}
243}
244
245func TestUDPConnLocalAndRemoteNames(t *testing.T) {
246	if !testableNetwork("udp") {
247		t.Skipf("skipping: udp not available")
248	}
249
250	for _, laddr := range []string{"", "127.0.0.1:0"} {
251		c1, err := ListenPacket("udp", "127.0.0.1:0")
252		if err != nil {
253			t.Fatal(err)
254		}
255		defer c1.Close()
256
257		var la *UDPAddr
258		if laddr != "" {
259			var err error
260			if la, err = ResolveUDPAddr("udp", laddr); err != nil {
261				t.Fatal(err)
262			}
263		}
264		c2, err := DialUDP("udp", la, c1.LocalAddr().(*UDPAddr))
265		if err != nil {
266			t.Fatal(err)
267		}
268		defer c2.Close()
269
270		var connAddrs = [4]struct {
271			got Addr
272			ok  bool
273		}{
274			{c1.LocalAddr(), true},
275			{c1.(*UDPConn).RemoteAddr(), false},
276			{c2.LocalAddr(), true},
277			{c2.RemoteAddr(), true},
278		}
279		for _, ca := range connAddrs {
280			if a, ok := ca.got.(*UDPAddr); ok != ca.ok || ok && a.Port == 0 {
281				t.Fatalf("got %v; expected a proper address with non-zero port number", ca.got)
282			}
283		}
284	}
285}
286
287func TestIPv6LinkLocalUnicastUDP(t *testing.T) {
288	testenv.MustHaveExternalNetwork(t)
289
290	if !supportsIPv6() {
291		t.Skip("IPv6 is not supported")
292	}
293
294	for i, tt := range ipv6LinkLocalUnicastUDPTests {
295		c1, err := ListenPacket(tt.network, tt.address)
296		if err != nil {
297			// It might return "LookupHost returned no
298			// suitable address" error on some platforms.
299			t.Log(err)
300			continue
301		}
302		ls := (&packetListener{PacketConn: c1}).newLocalServer()
303		defer ls.teardown()
304		ch := make(chan error, 1)
305		handler := func(ls *localPacketServer, c PacketConn) { packetTransponder(c, ch) }
306		if err := ls.buildup(handler); err != nil {
307			t.Fatal(err)
308		}
309		if la, ok := c1.LocalAddr().(*UDPAddr); !ok || !tt.nameLookup && la.Zone == "" {
310			t.Fatalf("got %v; expected a proper address with zone identifier", la)
311		}
312
313		c2, err := Dial(tt.network, ls.PacketConn.LocalAddr().String())
314		if err != nil {
315			t.Fatal(err)
316		}
317		defer c2.Close()
318		if la, ok := c2.LocalAddr().(*UDPAddr); !ok || !tt.nameLookup && la.Zone == "" {
319			t.Fatalf("got %v; expected a proper address with zone identifier", la)
320		}
321		if ra, ok := c2.RemoteAddr().(*UDPAddr); !ok || !tt.nameLookup && ra.Zone == "" {
322			t.Fatalf("got %v; expected a proper address with zone identifier", ra)
323		}
324
325		if _, err := c2.Write([]byte("UDP OVER IPV6 LINKLOCAL TEST")); err != nil {
326			t.Fatal(err)
327		}
328		b := make([]byte, 32)
329		if _, err := c2.Read(b); err != nil {
330			t.Fatal(err)
331		}
332
333		for err := range ch {
334			t.Errorf("#%d: %v", i, err)
335		}
336	}
337}
338
339func TestUDPZeroBytePayload(t *testing.T) {
340	switch runtime.GOOS {
341	case "plan9":
342		t.Skipf("not supported on %s", runtime.GOOS)
343	case "darwin", "ios":
344		testenv.SkipFlaky(t, 29225)
345	}
346	if !testableNetwork("udp") {
347		t.Skipf("skipping: udp not available")
348	}
349
350	c := newLocalPacketListener(t, "udp")
351	defer c.Close()
352
353	for _, genericRead := range []bool{false, true} {
354		n, err := c.WriteTo(nil, c.LocalAddr())
355		if err != nil {
356			t.Fatal(err)
357		}
358		if n != 0 {
359			t.Errorf("got %d; want 0", n)
360		}
361		c.SetReadDeadline(time.Now().Add(30 * time.Second))
362		var b [1]byte
363		var name string
364		if genericRead {
365			_, err = c.(Conn).Read(b[:])
366			name = "Read"
367		} else {
368			_, _, err = c.ReadFrom(b[:])
369			name = "ReadFrom"
370		}
371		if err != nil {
372			t.Errorf("%s of zero byte packet failed: %v", name, err)
373		}
374	}
375}
376
377func TestUDPZeroByteBuffer(t *testing.T) {
378	switch runtime.GOOS {
379	case "plan9":
380		t.Skipf("not supported on %s", runtime.GOOS)
381	}
382	if !testableNetwork("udp") {
383		t.Skipf("skipping: udp not available")
384	}
385
386	c := newLocalPacketListener(t, "udp")
387	defer c.Close()
388
389	b := []byte("UDP ZERO BYTE BUFFER TEST")
390	for _, genericRead := range []bool{false, true} {
391		n, err := c.WriteTo(b, c.LocalAddr())
392		if err != nil {
393			t.Fatal(err)
394		}
395		if n != len(b) {
396			t.Errorf("got %d; want %d", n, len(b))
397		}
398		c.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
399		if genericRead {
400			_, err = c.(Conn).Read(nil)
401		} else {
402			_, _, err = c.ReadFrom(nil)
403		}
404		switch err {
405		case nil: // ReadFrom succeeds
406		default: // Read may timeout, it depends on the platform
407			if nerr, ok := err.(Error); (!ok || !nerr.Timeout()) && runtime.GOOS != "windows" { // Windows returns WSAEMSGSIZE
408				t.Fatal(err)
409			}
410		}
411	}
412}
413
414func TestUDPReadSizeError(t *testing.T) {
415	switch runtime.GOOS {
416	case "plan9":
417		t.Skipf("not supported on %s", runtime.GOOS)
418	}
419	if !testableNetwork("udp") {
420		t.Skipf("skipping: udp not available")
421	}
422
423	c1 := newLocalPacketListener(t, "udp")
424	defer c1.Close()
425
426	c2, err := Dial("udp", c1.LocalAddr().String())
427	if err != nil {
428		t.Fatal(err)
429	}
430	defer c2.Close()
431
432	b1 := []byte("READ SIZE ERROR TEST")
433	for _, genericRead := range []bool{false, true} {
434		n, err := c2.Write(b1)
435		if err != nil {
436			t.Fatal(err)
437		}
438		if n != len(b1) {
439			t.Errorf("got %d; want %d", n, len(b1))
440		}
441		b2 := make([]byte, len(b1)-1)
442		if genericRead {
443			n, err = c1.(Conn).Read(b2)
444		} else {
445			n, _, err = c1.ReadFrom(b2)
446		}
447		if err != nil && runtime.GOOS != "windows" { // Windows returns WSAEMSGSIZE
448			t.Fatal(err)
449		}
450		if n != len(b1)-1 {
451			t.Fatalf("got %d; want %d", n, len(b1)-1)
452		}
453	}
454}
455
456// TestUDPReadTimeout verifies that ReadFromUDP with timeout returns an error
457// without data or an address.
458func TestUDPReadTimeout(t *testing.T) {
459	if !testableNetwork("udp4") {
460		t.Skipf("skipping: udp4 not available")
461	}
462
463	la, err := ResolveUDPAddr("udp4", "127.0.0.1:0")
464	if err != nil {
465		t.Fatal(err)
466	}
467	c, err := ListenUDP("udp4", la)
468	if err != nil {
469		t.Fatal(err)
470	}
471	defer c.Close()
472
473	c.SetDeadline(time.Now())
474	b := make([]byte, 1)
475	n, addr, err := c.ReadFromUDP(b)
476	if !errors.Is(err, os.ErrDeadlineExceeded) {
477		t.Errorf("ReadFromUDP got err %v want os.ErrDeadlineExceeded", err)
478	}
479	if n != 0 {
480		t.Errorf("ReadFromUDP got n %d want 0", n)
481	}
482	if addr != nil {
483		t.Errorf("ReadFromUDP got addr %+#v want nil", addr)
484	}
485}
486
487func TestAllocs(t *testing.T) {
488	switch runtime.GOOS {
489	case "plan9", "js", "wasip1":
490		// These implementations have not been optimized.
491		t.Skipf("skipping on %v", runtime.GOOS)
492	}
493	if !testableNetwork("udp4") {
494		t.Skipf("skipping: udp4 not available")
495	}
496
497	// Optimizations are required to remove the allocs.
498	testenv.SkipIfOptimizationOff(t)
499
500	conn, err := ListenUDP("udp4", &UDPAddr{IP: IPv4(127, 0, 0, 1)})
501	if err != nil {
502		t.Fatal(err)
503	}
504	defer conn.Close()
505	addr := conn.LocalAddr()
506	addrPort := addr.(*UDPAddr).AddrPort()
507	buf := make([]byte, 8)
508
509	allocs := testing.AllocsPerRun(1000, func() {
510		_, _, err := conn.WriteMsgUDPAddrPort(buf, nil, addrPort)
511		if err != nil {
512			t.Fatal(err)
513		}
514		_, _, _, _, err = conn.ReadMsgUDPAddrPort(buf, nil)
515		if err != nil {
516			t.Fatal(err)
517		}
518	})
519	if got := int(allocs); got != 0 {
520		t.Errorf("WriteMsgUDPAddrPort/ReadMsgUDPAddrPort allocated %d objects", got)
521	}
522
523	allocs = testing.AllocsPerRun(1000, func() {
524		_, err := conn.WriteToUDPAddrPort(buf, addrPort)
525		if err != nil {
526			t.Fatal(err)
527		}
528		_, _, err = conn.ReadFromUDPAddrPort(buf)
529		if err != nil {
530			t.Fatal(err)
531		}
532	})
533	if got := int(allocs); got != 0 {
534		t.Errorf("WriteToUDPAddrPort/ReadFromUDPAddrPort allocated %d objects", got)
535	}
536
537	allocs = testing.AllocsPerRun(1000, func() {
538		_, err := conn.WriteTo(buf, addr)
539		if err != nil {
540			t.Fatal(err)
541		}
542		_, _, err = conn.ReadFromUDP(buf)
543		if err != nil {
544			t.Fatal(err)
545		}
546	})
547	if got := int(allocs); got != 1 {
548		t.Errorf("WriteTo/ReadFromUDP allocated %d objects", got)
549	}
550}
551
552func BenchmarkReadWriteMsgUDPAddrPort(b *testing.B) {
553	conn, err := ListenUDP("udp4", &UDPAddr{IP: IPv4(127, 0, 0, 1)})
554	if err != nil {
555		b.Fatal(err)
556	}
557	defer conn.Close()
558	addr := conn.LocalAddr().(*UDPAddr).AddrPort()
559	buf := make([]byte, 8)
560	b.ResetTimer()
561	b.ReportAllocs()
562	for i := 0; i < b.N; i++ {
563		_, _, err := conn.WriteMsgUDPAddrPort(buf, nil, addr)
564		if err != nil {
565			b.Fatal(err)
566		}
567		_, _, _, _, err = conn.ReadMsgUDPAddrPort(buf, nil)
568		if err != nil {
569			b.Fatal(err)
570		}
571	}
572}
573
574func BenchmarkWriteToReadFromUDP(b *testing.B) {
575	conn, err := ListenUDP("udp4", &UDPAddr{IP: IPv4(127, 0, 0, 1)})
576	if err != nil {
577		b.Fatal(err)
578	}
579	defer conn.Close()
580	addr := conn.LocalAddr()
581	buf := make([]byte, 8)
582	b.ResetTimer()
583	b.ReportAllocs()
584	for i := 0; i < b.N; i++ {
585		_, err := conn.WriteTo(buf, addr)
586		if err != nil {
587			b.Fatal(err)
588		}
589		_, _, err = conn.ReadFromUDP(buf)
590		if err != nil {
591			b.Fatal(err)
592		}
593	}
594}
595
596func BenchmarkWriteToReadFromUDPAddrPort(b *testing.B) {
597	conn, err := ListenUDP("udp4", &UDPAddr{IP: IPv4(127, 0, 0, 1)})
598	if err != nil {
599		b.Fatal(err)
600	}
601	defer conn.Close()
602	addr := conn.LocalAddr().(*UDPAddr).AddrPort()
603	buf := make([]byte, 8)
604	b.ResetTimer()
605	b.ReportAllocs()
606	for i := 0; i < b.N; i++ {
607		_, err := conn.WriteToUDPAddrPort(buf, addr)
608		if err != nil {
609			b.Fatal(err)
610		}
611		_, _, err = conn.ReadFromUDPAddrPort(buf)
612		if err != nil {
613			b.Fatal(err)
614		}
615	}
616}
617
618func TestUDPIPVersionReadMsg(t *testing.T) {
619	switch runtime.GOOS {
620	case "plan9":
621		t.Skipf("skipping on %v", runtime.GOOS)
622	}
623	if !testableNetwork("udp4") {
624		t.Skipf("skipping: udp4 not available")
625	}
626
627	conn, err := ListenUDP("udp4", &UDPAddr{IP: IPv4(127, 0, 0, 1)})
628	if err != nil {
629		t.Fatal(err)
630	}
631	defer conn.Close()
632	daddr := conn.LocalAddr().(*UDPAddr).AddrPort()
633	buf := make([]byte, 8)
634	_, err = conn.WriteToUDPAddrPort(buf, daddr)
635	if err != nil {
636		t.Fatal(err)
637	}
638	_, _, _, saddr, err := conn.ReadMsgUDPAddrPort(buf, nil)
639	if err != nil {
640		t.Fatal(err)
641	}
642	if !saddr.Addr().Is4() {
643		t.Error("returned AddrPort is not IPv4")
644	}
645	_, err = conn.WriteToUDPAddrPort(buf, daddr)
646	if err != nil {
647		t.Fatal(err)
648	}
649	_, _, _, soldaddr, err := conn.ReadMsgUDP(buf, nil)
650	if err != nil {
651		t.Fatal(err)
652	}
653	if len(soldaddr.IP) != 4 {
654		t.Error("returned UDPAddr is not IPv4")
655	}
656}
657
658// TestIPv6WriteMsgUDPAddrPortTargetAddrIPVersion verifies that
659// WriteMsgUDPAddrPort accepts IPv4, IPv4-mapped IPv6, and IPv6 target addresses
660// on a UDPConn listening on "::".
661func TestIPv6WriteMsgUDPAddrPortTargetAddrIPVersion(t *testing.T) {
662	if !testableNetwork("udp4") {
663		t.Skipf("skipping: udp4 not available")
664	}
665	if !testableNetwork("udp6") {
666		t.Skipf("skipping: udp6 not available")
667	}
668
669	switch runtime.GOOS {
670	case "dragonfly", "openbsd":
671		// DragonflyBSD's IPv6 sockets are always IPv6-only, according to the man page:
672		// https://www.dragonflybsd.org/cgi/web-man?command=ip6 (search for IPV6_V6ONLY).
673		// OpenBSD's IPv6 sockets are always IPv6-only, according to the man page:
674		// https://man.openbsd.org/ip6#IPV6_V6ONLY
675		t.Skipf("skipping on %v", runtime.GOOS)
676	}
677
678	conn, err := ListenUDP("udp", nil)
679	if err != nil {
680		t.Fatal(err)
681	}
682	defer conn.Close()
683
684	daddr4 := netip.AddrPortFrom(netip.MustParseAddr("127.0.0.1"), 12345)
685	daddr4in6 := netip.AddrPortFrom(netip.MustParseAddr("::ffff:127.0.0.1"), 12345)
686	daddr6 := netip.AddrPortFrom(netip.MustParseAddr("::1"), 12345)
687	buf := make([]byte, 8)
688
689	_, _, err = conn.WriteMsgUDPAddrPort(buf, nil, daddr4)
690	if err != nil {
691		t.Fatal(err)
692	}
693
694	_, _, err = conn.WriteMsgUDPAddrPort(buf, nil, daddr4in6)
695	if err != nil {
696		t.Fatal(err)
697	}
698
699	_, _, err = conn.WriteMsgUDPAddrPort(buf, nil, daddr6)
700	if err != nil {
701		t.Fatal(err)
702	}
703}
704