1
2
3
4
5 package ipv6_test
6
7 import (
8 "bytes"
9 "net"
10 "os"
11 "runtime"
12 "testing"
13 "time"
14
15 "golang.org/x/net/icmp"
16 "golang.org/x/net/internal/iana"
17 "golang.org/x/net/ipv6"
18 "golang.org/x/net/nettest"
19 )
20
21 var packetConnReadWriteMulticastUDPTests = []struct {
22 addr string
23 grp, src *net.UDPAddr
24 }{
25 {"[ff02::]:0", &net.UDPAddr{IP: net.ParseIP("ff02::114")}, nil},
26
27 {"[ff30::8000:0]:0", &net.UDPAddr{IP: net.ParseIP("ff30::8000:1")}, &net.UDPAddr{IP: net.IPv6loopback}},
28 }
29
30 func TestPacketConnReadWriteMulticastUDP(t *testing.T) {
31 switch runtime.GOOS {
32 case "fuchsia", "hurd", "js", "nacl", "plan9", "wasip1", "windows":
33 t.Skipf("not supported on %s", runtime.GOOS)
34 }
35 if !nettest.SupportsIPv6() {
36 t.Skip("ipv6 is not supported")
37 }
38 if m, ok := supportsIPv6MulticastDeliveryOnLoopback(); !ok {
39 t.Skip(m)
40 }
41 ifi, err := nettest.RoutedInterface("ip6", net.FlagUp|net.FlagMulticast|net.FlagLoopback)
42 if err != nil {
43 t.Skipf("not available on %s", runtime.GOOS)
44 }
45
46 for _, tt := range packetConnReadWriteMulticastUDPTests {
47 c, err := net.ListenPacket("udp6", tt.addr)
48 if err != nil {
49 t.Fatal(err)
50 }
51 defer c.Close()
52
53 grp := *tt.grp
54 grp.Port = c.LocalAddr().(*net.UDPAddr).Port
55 p := ipv6.NewPacketConn(c)
56 defer p.Close()
57 if tt.src == nil {
58 if err := p.JoinGroup(ifi, &grp); err != nil {
59 t.Fatal(err)
60 }
61 defer p.LeaveGroup(ifi, &grp)
62 } else {
63 if err := p.JoinSourceSpecificGroup(ifi, &grp, tt.src); err != nil {
64 switch runtime.GOOS {
65 case "freebsd", "linux":
66 default:
67 t.Logf("not supported on %s", runtime.GOOS)
68 continue
69 }
70 t.Fatal(err)
71 }
72 defer p.LeaveSourceSpecificGroup(ifi, &grp, tt.src)
73 }
74 if err := p.SetMulticastInterface(ifi); err != nil {
75 t.Fatal(err)
76 }
77 if _, err := p.MulticastInterface(); err != nil {
78 t.Fatal(err)
79 }
80 if err := p.SetMulticastLoopback(true); err != nil {
81 t.Fatal(err)
82 }
83 if _, err := p.MulticastLoopback(); err != nil {
84 t.Fatal(err)
85 }
86
87 cm := ipv6.ControlMessage{
88 TrafficClass: iana.DiffServAF11 | iana.CongestionExperienced,
89 Src: net.IPv6loopback,
90 IfIndex: ifi.Index,
91 }
92 cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagSrc | ipv6.FlagDst | ipv6.FlagInterface | ipv6.FlagPathMTU
93 wb := []byte("HELLO-R-U-THERE")
94
95 for i, toggle := range []bool{true, false, true} {
96 if err := p.SetControlMessage(cf, toggle); err != nil {
97 if protocolNotSupported(err) {
98 t.Logf("not supported on %s", runtime.GOOS)
99 continue
100 }
101 t.Fatal(err)
102 }
103 cm.HopLimit = i + 1
104
105 backoff := time.Millisecond
106 for {
107 n, err := p.WriteTo(wb, &cm, &grp)
108 if err != nil {
109 if n == 0 && isENOBUFS(err) {
110 time.Sleep(backoff)
111 backoff *= 2
112 continue
113 }
114 t.Fatal(err)
115 }
116 if n != len(wb) {
117 t.Fatalf("wrote %v bytes; want %v", n, len(wb))
118 }
119 break
120 }
121
122 rb := make([]byte, 128)
123 if n, _, _, err := p.ReadFrom(rb); err != nil {
124 t.Fatal(err)
125 } else if !bytes.Equal(rb[:n], wb) {
126 t.Fatalf("got %v; want %v", rb[:n], wb)
127 }
128 }
129 }
130 }
131
132 var packetConnReadWriteMulticastICMPTests = []struct {
133 grp, src *net.IPAddr
134 }{
135 {&net.IPAddr{IP: net.ParseIP("ff02::114")}, nil},
136
137 {&net.IPAddr{IP: net.ParseIP("ff30::8000:1")}, &net.IPAddr{IP: net.IPv6loopback}},
138 }
139
140 func TestPacketConnReadWriteMulticastICMP(t *testing.T) {
141 if os.Getenv("GO_BUILDER_NAME") == "openbsd-amd64-68" ||
142 os.Getenv("GO_BUILDER_NAME") == "openbsd-386-68" {
143 t.Skip(`this test is currently failing on OpenBSD 6.8 builders with "raw-read ip6: i/o timeout" ` +
144 `and needs investigation, see golang.org/issue/42064`)
145 }
146 switch runtime.GOOS {
147 case "fuchsia", "hurd", "js", "nacl", "plan9", "wasip1", "windows":
148 t.Skipf("not supported on %s", runtime.GOOS)
149 }
150 if !nettest.SupportsIPv6() {
151 t.Skip("ipv6 is not supported")
152 }
153 if m, ok := supportsIPv6MulticastDeliveryOnLoopback(); !ok {
154 t.Skip(m)
155 }
156 if !nettest.SupportsRawSocket() {
157 t.Skipf("not supported on %s/%s", runtime.GOOS, runtime.GOARCH)
158 }
159 ifi, err := nettest.RoutedInterface("ip6", net.FlagUp|net.FlagMulticast|net.FlagLoopback)
160 if err != nil {
161 t.Skipf("not available on %s", runtime.GOOS)
162 }
163
164 for _, tt := range packetConnReadWriteMulticastICMPTests {
165 c, err := net.ListenPacket("ip6:ipv6-icmp", "::")
166 if err != nil {
167 t.Fatal(err)
168 }
169 defer c.Close()
170
171 pshicmp := icmp.IPv6PseudoHeader(c.LocalAddr().(*net.IPAddr).IP, tt.grp.IP)
172 p := ipv6.NewPacketConn(c)
173 defer p.Close()
174 if tt.src == nil {
175 if err := p.JoinGroup(ifi, tt.grp); err != nil {
176 t.Fatal(err)
177 }
178 defer p.LeaveGroup(ifi, tt.grp)
179 } else {
180 if err := p.JoinSourceSpecificGroup(ifi, tt.grp, tt.src); err != nil {
181 switch runtime.GOOS {
182 case "freebsd", "linux":
183 default:
184 t.Logf("not supported on %s", runtime.GOOS)
185 continue
186 }
187 t.Fatal(err)
188 }
189 defer p.LeaveSourceSpecificGroup(ifi, tt.grp, tt.src)
190 }
191 if err := p.SetMulticastInterface(ifi); err != nil {
192 t.Fatal(err)
193 }
194 if _, err := p.MulticastInterface(); err != nil {
195 t.Fatal(err)
196 }
197 if err := p.SetMulticastLoopback(true); err != nil {
198 t.Fatal(err)
199 }
200 if _, err := p.MulticastLoopback(); err != nil {
201 t.Fatal(err)
202 }
203
204 cm := ipv6.ControlMessage{
205 TrafficClass: iana.DiffServAF11 | iana.CongestionExperienced,
206 Src: net.IPv6loopback,
207 IfIndex: ifi.Index,
208 }
209 cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagSrc | ipv6.FlagDst | ipv6.FlagInterface | ipv6.FlagPathMTU
210
211 var f ipv6.ICMPFilter
212 f.SetAll(true)
213 f.Accept(ipv6.ICMPTypeEchoReply)
214 if err := p.SetICMPFilter(&f); err != nil {
215 t.Fatal(err)
216 }
217
218 var psh []byte
219 for i, toggle := range []bool{true, false, true} {
220 if toggle {
221 psh = nil
222 if err := p.SetChecksum(true, 2); err != nil {
223
224
225 if runtime.GOOS != "illumos" && runtime.GOOS != "solaris" {
226 t.Fatal(err)
227 }
228 }
229 } else {
230 psh = pshicmp
231
232
233
234 p.SetChecksum(false, -1)
235 }
236 wb, err := (&icmp.Message{
237 Type: ipv6.ICMPTypeEchoRequest, Code: 0,
238 Body: &icmp.Echo{
239 ID: os.Getpid() & 0xffff, Seq: i + 1,
240 Data: []byte("HELLO-R-U-THERE"),
241 },
242 }).Marshal(psh)
243 if err != nil {
244 t.Fatal(err)
245 }
246 if err := p.SetControlMessage(cf, toggle); err != nil {
247 if protocolNotSupported(err) {
248 t.Logf("not supported on %s", runtime.GOOS)
249 continue
250 }
251 t.Fatal(err)
252 }
253 cm.HopLimit = i + 1
254 if n, err := p.WriteTo(wb, &cm, tt.grp); err != nil {
255 t.Fatal(err)
256 } else if n != len(wb) {
257 t.Fatalf("got %v; want %v", n, len(wb))
258 }
259 rb := make([]byte, 128)
260 if n, _, _, err := p.ReadFrom(rb); err != nil {
261 switch runtime.GOOS {
262 case "darwin", "ios":
263 t.Logf("not supported on %s", runtime.GOOS)
264 continue
265 }
266 t.Fatal(err)
267 } else {
268 if m, err := icmp.ParseMessage(iana.ProtocolIPv6ICMP, rb[:n]); err != nil {
269 t.Fatal(err)
270 } else if m.Type != ipv6.ICMPTypeEchoReply || m.Code != 0 {
271 t.Fatalf("got type=%v, code=%v; want type=%v, code=%v", m.Type, m.Code, ipv6.ICMPTypeEchoReply, 0)
272 }
273 }
274 }
275 }
276 }
277
View as plain text