1// Copyright 2013 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 ipv6_test
6
7import (
8	"net"
9	"runtime"
10	"testing"
11
12	"golang.org/x/net/ipv6"
13	"golang.org/x/net/nettest"
14)
15
16var udpMultipleGroupListenerTests = []net.Addr{
17	&net.UDPAddr{IP: net.ParseIP("ff02::114")}, // see RFC 4727
18	&net.UDPAddr{IP: net.ParseIP("ff02::1:114")},
19	&net.UDPAddr{IP: net.ParseIP("ff02::2:114")},
20}
21
22func TestUDPSinglePacketConnWithMultipleGroupListeners(t *testing.T) {
23	switch runtime.GOOS {
24	case "fuchsia", "hurd", "js", "nacl", "plan9", "windows":
25		t.Skipf("not supported on %s", runtime.GOOS)
26	}
27	if !nettest.SupportsIPv6() {
28		t.Skip("ipv6 is not supported")
29	}
30
31	for _, gaddr := range udpMultipleGroupListenerTests {
32		c, err := net.ListenPacket("udp6", "[::]:0") // wildcard address with non-reusable port
33		if err != nil {
34			t.Fatal(err)
35		}
36		defer c.Close()
37
38		p := ipv6.NewPacketConn(c)
39		var mift []*net.Interface
40
41		ift, err := net.Interfaces()
42		if err != nil {
43			t.Fatal(err)
44		}
45		for i, ifi := range ift {
46			if _, err := nettest.MulticastSource("ip6", &ifi); err != nil {
47				continue
48			}
49			if err := p.JoinGroup(&ifi, gaddr); err != nil {
50				t.Fatal(err)
51			}
52			mift = append(mift, &ift[i])
53		}
54		for _, ifi := range mift {
55			if err := p.LeaveGroup(ifi, gaddr); err != nil {
56				t.Fatal(err)
57			}
58		}
59	}
60}
61
62func TestUDPMultiplePacketConnWithMultipleGroupListeners(t *testing.T) {
63	switch runtime.GOOS {
64	case "fuchsia", "hurd", "js", "nacl", "plan9", "windows", "zos":
65		t.Skipf("not supported on %s", runtime.GOOS)
66	}
67	if !nettest.SupportsIPv6() {
68		t.Skip("ipv6 is not supported")
69	}
70
71	for _, gaddr := range udpMultipleGroupListenerTests {
72		c1, err := net.ListenPacket("udp6", "[ff02::]:0") // wildcard address with reusable port
73		if err != nil {
74			t.Fatal(err)
75		}
76		defer c1.Close()
77		_, port, err := net.SplitHostPort(c1.LocalAddr().String())
78		if err != nil {
79			t.Fatal(err)
80		}
81		c2, err := net.ListenPacket("udp6", net.JoinHostPort("ff02::", port)) // wildcard address with reusable port
82		if err != nil {
83			t.Fatal(err)
84		}
85		defer c2.Close()
86
87		var ps [2]*ipv6.PacketConn
88		ps[0] = ipv6.NewPacketConn(c1)
89		ps[1] = ipv6.NewPacketConn(c2)
90		var mift []*net.Interface
91
92		ift, err := net.Interfaces()
93		if err != nil {
94			t.Fatal(err)
95		}
96		for i, ifi := range ift {
97			if _, err := nettest.MulticastSource("ip6", &ifi); err != nil {
98				continue
99			}
100			for _, p := range ps {
101				if err := p.JoinGroup(&ifi, gaddr); err != nil {
102					t.Fatal(err)
103				}
104			}
105			mift = append(mift, &ift[i])
106		}
107		for _, ifi := range mift {
108			for _, p := range ps {
109				if err := p.LeaveGroup(ifi, gaddr); err != nil {
110					t.Fatal(err)
111				}
112			}
113		}
114	}
115}
116
117func TestUDPPerInterfaceSinglePacketConnWithSingleGroupListener(t *testing.T) {
118	switch runtime.GOOS {
119	case "fuchsia", "hurd", "js", "nacl", "plan9", "windows":
120		t.Skipf("not supported on %s", runtime.GOOS)
121	}
122	if !nettest.SupportsIPv6() {
123		t.Skip("ipv6 is not supported")
124	}
125
126	gaddr := net.IPAddr{IP: net.ParseIP("ff02::114")} // see RFC 4727
127	type ml struct {
128		c   *ipv6.PacketConn
129		ifi *net.Interface
130	}
131	var mlt []*ml
132
133	ift, err := net.Interfaces()
134	if err != nil {
135		t.Fatal(err)
136	}
137	port := "0"
138	for i, ifi := range ift {
139		ip, err := nettest.MulticastSource("ip6", &ifi)
140		if err != nil {
141			continue
142		}
143		c, err := net.ListenPacket("udp6", net.JoinHostPort(ip.String()+"%"+ifi.Name, port)) // unicast address with non-reusable port
144		if err != nil {
145			// The listen may fail when the serivce is
146			// already in use, but it's fine because the
147			// purpose of this is not to test the
148			// bookkeeping of IP control block inside the
149			// kernel.
150			t.Log(err)
151			continue
152		}
153		defer c.Close()
154		if port == "0" {
155			_, port, err = net.SplitHostPort(c.LocalAddr().String())
156			if err != nil {
157				t.Fatal(err)
158			}
159		}
160		p := ipv6.NewPacketConn(c)
161		if err := p.JoinGroup(&ifi, &gaddr); err != nil {
162			t.Fatal(err)
163		}
164		mlt = append(mlt, &ml{p, &ift[i]})
165	}
166	for _, m := range mlt {
167		if err := m.c.LeaveGroup(m.ifi, &gaddr); err != nil {
168			t.Fatal(err)
169		}
170	}
171}
172
173func TestIPSinglePacketConnWithSingleGroupListener(t *testing.T) {
174	switch runtime.GOOS {
175	case "fuchsia", "hurd", "js", "nacl", "plan9", "windows":
176		t.Skipf("not supported on %s", runtime.GOOS)
177	}
178	if !nettest.SupportsIPv6() {
179		t.Skip("ipv6 is not supported")
180	}
181	if !nettest.SupportsRawSocket() {
182		t.Skipf("not supported on %s/%s", runtime.GOOS, runtime.GOARCH)
183	}
184
185	c, err := net.ListenPacket("ip6:ipv6-icmp", "::") // wildcard address
186	if err != nil {
187		t.Fatal(err)
188	}
189	defer c.Close()
190
191	p := ipv6.NewPacketConn(c)
192	gaddr := net.IPAddr{IP: net.ParseIP("ff02::114")} // see RFC 4727
193	var mift []*net.Interface
194
195	ift, err := net.Interfaces()
196	if err != nil {
197		t.Fatal(err)
198	}
199	for i, ifi := range ift {
200		if _, err := nettest.MulticastSource("ip6", &ifi); err != nil {
201			continue
202		}
203		if err := p.JoinGroup(&ifi, &gaddr); err != nil {
204			t.Fatal(err)
205		}
206		mift = append(mift, &ift[i])
207	}
208	for _, ifi := range mift {
209		if err := p.LeaveGroup(ifi, &gaddr); err != nil {
210			t.Fatal(err)
211		}
212	}
213}
214
215func TestIPPerInterfaceSinglePacketConnWithSingleGroupListener(t *testing.T) {
216	switch runtime.GOOS {
217	case "darwin", "ios", "dragonfly", "openbsd": // platforms that return fe80::1%lo0: bind: can't assign requested address
218		t.Skipf("not supported on %s", runtime.GOOS)
219	case "fuchsia", "hurd", "js", "nacl", "plan9", "windows":
220		t.Skipf("not supported on %s", runtime.GOOS)
221	}
222	if !nettest.SupportsIPv6() {
223		t.Skip("ipv6 is not supported")
224	}
225	if !nettest.SupportsRawSocket() {
226		t.Skipf("not supported on %s/%s", runtime.GOOS, runtime.GOARCH)
227	}
228
229	gaddr := net.IPAddr{IP: net.ParseIP("ff02::114")} // see RFC 4727
230	type ml struct {
231		c   *ipv6.PacketConn
232		ifi *net.Interface
233	}
234	var mlt []*ml
235
236	ift, err := net.Interfaces()
237	if err != nil {
238		t.Fatal(err)
239	}
240	for i, ifi := range ift {
241		ip, err := nettest.MulticastSource("ip6", &ifi)
242		if err != nil {
243			continue
244		}
245		c, err := net.ListenPacket("ip6:ipv6-icmp", ip.String()+"%"+ifi.Name) // unicast address
246		if err != nil {
247			t.Fatal(err)
248		}
249		defer c.Close()
250		p := ipv6.NewPacketConn(c)
251		if err := p.JoinGroup(&ifi, &gaddr); err != nil {
252			t.Fatal(err)
253		}
254		mlt = append(mlt, &ml{p, &ift[i]})
255	}
256	for _, m := range mlt {
257		if err := m.c.LeaveGroup(m.ifi, &gaddr); err != nil {
258			t.Fatal(err)
259		}
260	}
261}
262