golang.org/x/net@v0.25.1-0.20240516223405-c87a5b62e243/quic/udp_test.go (about) 1 // Copyright 2023 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 //go:build go1.21 6 7 package quic 8 9 import ( 10 "bytes" 11 "fmt" 12 "net" 13 "net/netip" 14 "runtime" 15 "testing" 16 ) 17 18 func TestUDPSourceUnspecified(t *testing.T) { 19 // Send datagram with no source address set. 20 runUDPTest(t, func(t *testing.T, test udpTest) { 21 t.Logf("%v", test.dstAddr) 22 data := []byte("source unspecified") 23 if err := test.src.Write(datagram{ 24 b: data, 25 peerAddr: test.dstAddr, 26 }); err != nil { 27 t.Fatalf("Write: %v", err) 28 } 29 got := <-test.dgramc 30 if !bytes.Equal(got.b, data) { 31 t.Errorf("got datagram {%x}, want {%x}", got.b, data) 32 } 33 }) 34 } 35 36 func TestUDPSourceSpecified(t *testing.T) { 37 // Send datagram with source address set. 38 runUDPTest(t, func(t *testing.T, test udpTest) { 39 data := []byte("source specified") 40 if err := test.src.Write(datagram{ 41 b: data, 42 peerAddr: test.dstAddr, 43 localAddr: test.src.LocalAddr(), 44 }); err != nil { 45 t.Fatalf("Write: %v", err) 46 } 47 got := <-test.dgramc 48 if !bytes.Equal(got.b, data) { 49 t.Errorf("got datagram {%x}, want {%x}", got.b, data) 50 } 51 }) 52 } 53 54 func TestUDPSourceInvalid(t *testing.T) { 55 // Send datagram with source address set to an address not associated with the connection. 56 if !udpInvalidLocalAddrIsError { 57 t.Skipf("%v: sending from invalid source succeeds", runtime.GOOS) 58 } 59 runUDPTest(t, func(t *testing.T, test udpTest) { 60 var localAddr netip.AddrPort 61 if test.src.LocalAddr().Addr().Is4() { 62 localAddr = netip.MustParseAddrPort("127.0.0.2:1234") 63 } else { 64 localAddr = netip.MustParseAddrPort("[::2]:1234") 65 } 66 data := []byte("source invalid") 67 if err := test.src.Write(datagram{ 68 b: data, 69 peerAddr: test.dstAddr, 70 localAddr: localAddr, 71 }); err == nil { 72 t.Errorf("Write with invalid localAddr succeeded; want error") 73 } 74 }) 75 } 76 77 func TestUDPECN(t *testing.T) { 78 if !udpECNSupport { 79 t.Skipf("%v: no ECN support", runtime.GOOS) 80 } 81 // Send datagrams with ECN bits set, verify the ECN bits are received. 82 runUDPTest(t, func(t *testing.T, test udpTest) { 83 for _, ecn := range []ecnBits{ecnNotECT, ecnECT1, ecnECT0, ecnCE} { 84 if err := test.src.Write(datagram{ 85 b: []byte{1, 2, 3, 4}, 86 peerAddr: test.dstAddr, 87 ecn: ecn, 88 }); err != nil { 89 t.Fatalf("Write: %v", err) 90 } 91 got := <-test.dgramc 92 if got.ecn != ecn { 93 t.Errorf("sending ECN bits %x, got %x", ecn, got.ecn) 94 } 95 } 96 }) 97 } 98 99 type udpTest struct { 100 src *netUDPConn 101 dst *netUDPConn 102 dstAddr netip.AddrPort 103 dgramc chan *datagram 104 } 105 106 // runUDPTest calls f with a pair of UDPConns in a matrix of network variations: 107 // udp, udp4, and udp6, and variations on binding to an unspecified address (0.0.0.0) 108 // or a specified one. 109 func runUDPTest(t *testing.T, f func(t *testing.T, u udpTest)) { 110 for _, test := range []struct { 111 srcNet, srcAddr, dstNet, dstAddr string 112 }{ 113 {"udp4", "127.0.0.1", "udp", ""}, 114 {"udp4", "127.0.0.1", "udp4", ""}, 115 {"udp4", "127.0.0.1", "udp4", "127.0.0.1"}, 116 {"udp6", "::1", "udp", ""}, 117 {"udp6", "::1", "udp6", ""}, 118 {"udp6", "::1", "udp6", "::1"}, 119 } { 120 spec := "spec" 121 if test.dstAddr == "" { 122 spec = "unspec" 123 } 124 t.Run(fmt.Sprintf("%v/%v/%v", test.srcNet, test.dstNet, spec), func(t *testing.T) { 125 // See: https://go.googlesource.com/go/+/refs/tags/go1.22.0/src/net/ipsock.go#47 126 // On these platforms, conns with network="udp" cannot accept IPv6. 127 switch runtime.GOOS { 128 case "dragonfly", "openbsd": 129 if test.srcNet == "udp6" && test.dstNet == "udp" { 130 t.Skipf("%v: no support for mapping IPv4 address to IPv6", runtime.GOOS) 131 } 132 } 133 if runtime.GOARCH == "wasm" && test.srcNet == "udp6" { 134 t.Skipf("%v: IPv6 tests fail when using wasm fake net", runtime.GOARCH) 135 } 136 137 srcAddr := netip.AddrPortFrom(netip.MustParseAddr(test.srcAddr), 0) 138 srcConn, err := net.ListenUDP(test.srcNet, net.UDPAddrFromAddrPort(srcAddr)) 139 if err != nil { 140 // If ListenUDP fails here, we presumably don't have 141 // IPv4/IPv6 configured. 142 t.Skipf("ListenUDP(%q, %v) = %v", test.srcNet, srcAddr, err) 143 } 144 t.Cleanup(func() { srcConn.Close() }) 145 src, err := newNetUDPConn(srcConn) 146 if err != nil { 147 t.Fatalf("newNetUDPConn: %v", err) 148 } 149 150 var dstAddr netip.AddrPort 151 if test.dstAddr != "" { 152 dstAddr = netip.AddrPortFrom(netip.MustParseAddr(test.dstAddr), 0) 153 } 154 dstConn, err := net.ListenUDP(test.dstNet, net.UDPAddrFromAddrPort(dstAddr)) 155 if err != nil { 156 t.Skipf("ListenUDP(%q, nil) = %v", test.dstNet, err) 157 } 158 dst, err := newNetUDPConn(dstConn) 159 if err != nil { 160 dstConn.Close() 161 t.Fatalf("newNetUDPConn: %v", err) 162 } 163 164 dgramc := make(chan *datagram) 165 go func() { 166 defer close(dgramc) 167 dst.Read(func(dgram *datagram) { 168 dgramc <- dgram 169 }) 170 }() 171 t.Cleanup(func() { 172 dstConn.Close() 173 for range dgramc { 174 t.Errorf("test read unexpected datagram") 175 } 176 }) 177 178 f(t, udpTest{ 179 src: src, 180 dst: dst, 181 dstAddr: netip.AddrPortFrom( 182 srcAddr.Addr(), 183 dst.LocalAddr().Port(), 184 ), 185 dgramc: dgramc, 186 }) 187 }) 188 } 189 }