1
2
3
4
5 package ipv4_test
6
7 import (
8 "bytes"
9 "fmt"
10 "net"
11 "os"
12 "runtime"
13 "testing"
14
15 "golang.org/x/net/icmp"
16 "golang.org/x/net/internal/iana"
17 "golang.org/x/net/ipv4"
18 "golang.org/x/net/nettest"
19 )
20
21 var packetConnReadWriteMulticastUDPTests = []struct {
22 addr string
23 grp, src *net.IPAddr
24 }{
25 {"224.0.0.0:0", &net.IPAddr{IP: net.IPv4(224, 0, 0, 254)}, nil},
26
27 {"232.0.1.0:0", &net.IPAddr{IP: net.IPv4(232, 0, 1, 254)}, &net.IPAddr{IP: net.IPv4(127, 0, 0, 1)}},
28 }
29
30 func TestPacketConnReadWriteMulticastUDP(t *testing.T) {
31 switch runtime.GOOS {
32 case "fuchsia", "hurd", "illumos", "js", "nacl", "plan9", "solaris", "wasip1", "windows", "zos":
33 t.Skipf("not supported on %s", runtime.GOOS)
34 }
35 ifi, err := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagMulticast|net.FlagLoopback)
36 if err != nil {
37 t.Skip(err)
38 }
39
40 for _, tt := range packetConnReadWriteMulticastUDPTests {
41 t.Run(fmt.Sprintf("addr=%s/grp=%s/src=%s", tt.addr, tt.grp, tt.src), func(t *testing.T) {
42 c, err := net.ListenPacket("udp4", tt.addr)
43 if err != nil {
44 t.Fatal(err)
45 }
46 p := ipv4.NewPacketConn(c)
47 defer func() {
48 if err := p.Close(); err != nil {
49 t.Error(err)
50 }
51 }()
52
53 grp := *p.LocalAddr().(*net.UDPAddr)
54 grp.IP = tt.grp.IP
55 if tt.src == nil {
56 if err := p.JoinGroup(ifi, &grp); err != nil {
57 t.Fatal(err)
58 }
59 defer func() {
60 if err := p.LeaveGroup(ifi, &grp); err != nil {
61 t.Error(err)
62 }
63 }()
64 } else {
65 if err := p.JoinSourceSpecificGroup(ifi, &grp, tt.src); err != nil {
66 switch runtime.GOOS {
67 case "freebsd", "linux":
68 default:
69 t.Skipf("not supported on %s", runtime.GOOS)
70 }
71 t.Fatal(err)
72 }
73 defer func() {
74 if err := p.LeaveSourceSpecificGroup(ifi, &grp, tt.src); err != nil {
75 t.Error(err)
76 }
77 }()
78 }
79 if err := p.SetMulticastInterface(ifi); err != nil {
80 t.Fatal(err)
81 }
82 if _, err := p.MulticastInterface(); err != nil {
83 t.Fatal(err)
84 }
85 if err := p.SetMulticastLoopback(true); err != nil {
86 t.Fatal(err)
87 }
88 if _, err := p.MulticastLoopback(); err != nil {
89 t.Fatal(err)
90 }
91 cf := ipv4.FlagTTL | ipv4.FlagDst | ipv4.FlagInterface
92 wb := []byte("HELLO-R-U-THERE")
93
94 for i, toggle := range []bool{true, false, true} {
95 if err := p.SetControlMessage(cf, toggle); err != nil {
96 if protocolNotSupported(err) {
97 t.Logf("not supported on %s", runtime.GOOS)
98 continue
99 }
100 t.Fatal(err)
101 }
102 if err := p.SetMulticastTTL(i + 1); err != nil {
103 t.Fatal(err)
104 }
105 }
106 if n, err := p.WriteTo(wb, nil, &grp); err != nil {
107 t.Fatal(err)
108 } else if n != len(wb) {
109 t.Fatalf("got %v; want %v", n, len(wb))
110 }
111 rb := make([]byte, 128)
112 if n, _, _, err := p.ReadFrom(rb); err != nil {
113 t.Fatal(err)
114 } else if !bytes.Equal(rb[:n], wb) {
115 t.Fatalf("got %v; want %v", rb[:n], wb)
116 }
117 })
118 }
119 }
120
121 var packetConnReadWriteMulticastICMPTests = []struct {
122 grp, src *net.IPAddr
123 }{
124 {&net.IPAddr{IP: net.IPv4(224, 0, 0, 254)}, nil},
125
126 {&net.IPAddr{IP: net.IPv4(232, 0, 1, 254)}, &net.IPAddr{IP: net.IPv4(127, 0, 0, 1)}},
127 }
128
129 func TestPacketConnReadWriteMulticastICMP(t *testing.T) {
130 if !nettest.SupportsRawSocket() {
131 t.Skipf("not supported on %s/%s", runtime.GOOS, runtime.GOARCH)
132 }
133 ifi, err := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagMulticast|net.FlagLoopback)
134
135
136 if runtime.GOOS == "zos" {
137 ifi, err = nettest.RoutedInterface("ip4", net.FlagUp|net.FlagMulticast)
138 }
139 if err != nil {
140 t.Skip(err)
141 }
142
143 for _, tt := range packetConnReadWriteMulticastICMPTests {
144 t.Run(fmt.Sprintf("grp=%s/src=%s", tt.grp, tt.src), func(t *testing.T) {
145 c, err := net.ListenPacket("ip4:icmp", "0.0.0.0")
146 if err != nil {
147 t.Fatal(err)
148 }
149 p := ipv4.NewPacketConn(c)
150 defer func() {
151 if err := p.Close(); err != nil {
152 t.Error(err)
153 }
154 }()
155
156 if tt.src == nil {
157 if err := p.JoinGroup(ifi, tt.grp); err != nil {
158 t.Fatal(err)
159 }
160 defer func() {
161 if err := p.LeaveGroup(ifi, tt.grp); err != nil {
162 t.Error(err)
163 }
164 }()
165 } else {
166 if err := p.JoinSourceSpecificGroup(ifi, tt.grp, tt.src); err != nil {
167 switch runtime.GOOS {
168 case "freebsd", "linux":
169 default:
170 t.Skipf("not supported on %s", runtime.GOOS)
171 }
172 t.Fatal(err)
173 }
174 defer func() {
175 if err := p.LeaveSourceSpecificGroup(ifi, tt.grp, tt.src); err != nil {
176 t.Error(err)
177 }
178 }()
179 }
180 if err := p.SetMulticastInterface(ifi); err != nil {
181 t.Fatal(err)
182 }
183 if _, err := p.MulticastInterface(); err != nil {
184 t.Fatal(err)
185 }
186 if err := p.SetMulticastLoopback(true); err != nil {
187 t.Fatal(err)
188 }
189 if _, err := p.MulticastLoopback(); err != nil {
190 t.Fatal(err)
191 }
192 cf := ipv4.FlagDst | ipv4.FlagInterface
193 if runtime.GOOS != "illumos" && runtime.GOOS != "solaris" {
194
195 cf |= ipv4.FlagTTL
196 }
197
198 for i, toggle := range []bool{true, false, true} {
199 wb, err := (&icmp.Message{
200 Type: ipv4.ICMPTypeEcho, Code: 0,
201 Body: &icmp.Echo{
202 ID: os.Getpid() & 0xffff, Seq: i + 1,
203 Data: []byte("HELLO-R-U-THERE"),
204 },
205 }).Marshal(nil)
206 if err != nil {
207 t.Fatal(err)
208 }
209 if err := p.SetControlMessage(cf, toggle); err != nil {
210 if protocolNotSupported(err) {
211 t.Logf("not supported on %s", runtime.GOOS)
212 continue
213 }
214 t.Fatal(err)
215 }
216 if err := p.SetMulticastTTL(i + 1); err != nil {
217 t.Fatal(err)
218 }
219 if n, err := p.WriteTo(wb, nil, tt.grp); err != nil {
220 t.Fatal(err)
221 } else if n != len(wb) {
222 t.Fatalf("got %v; want %v", n, len(wb))
223 }
224 rb := make([]byte, 128)
225 if n, _, _, err := p.ReadFrom(rb); err != nil {
226 t.Fatal(err)
227 } else {
228 m, err := icmp.ParseMessage(iana.ProtocolICMP, rb[:n])
229 if err != nil {
230 t.Fatal(err)
231 }
232 switch {
233 case m.Type == ipv4.ICMPTypeEchoReply && m.Code == 0:
234 case m.Type == ipv4.ICMPTypeEcho && m.Code == 0:
235 default:
236 t.Fatalf("got type=%v, code=%v; want type=%v, code=%v", m.Type, m.Code, ipv4.ICMPTypeEchoReply, 0)
237 }
238 }
239 }
240 })
241 }
242 }
243
244 var rawConnReadWriteMulticastICMPTests = []struct {
245 grp, src *net.IPAddr
246 }{
247 {&net.IPAddr{IP: net.IPv4(224, 0, 0, 254)}, nil},
248
249 {&net.IPAddr{IP: net.IPv4(232, 0, 1, 254)}, &net.IPAddr{IP: net.IPv4(127, 0, 0, 1)}},
250 }
251
252 func TestRawConnReadWriteMulticastICMP(t *testing.T) {
253 if testing.Short() {
254 t.Skip("to avoid external network")
255 }
256 if !nettest.SupportsRawSocket() {
257 t.Skipf("not supported on %s/%s", runtime.GOOS, runtime.GOARCH)
258 }
259 ifi, err := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagMulticast|net.FlagLoopback)
260 if err != nil {
261 t.Skipf("not available on %s", runtime.GOOS)
262 }
263
264 for _, tt := range rawConnReadWriteMulticastICMPTests {
265 c, err := net.ListenPacket("ip4:icmp", "0.0.0.0")
266 if err != nil {
267 t.Fatal(err)
268 }
269 defer c.Close()
270
271 r, err := ipv4.NewRawConn(c)
272 if err != nil {
273 t.Fatal(err)
274 }
275 defer r.Close()
276 if tt.src == nil {
277 if err := r.JoinGroup(ifi, tt.grp); err != nil {
278 t.Fatal(err)
279 }
280 defer r.LeaveGroup(ifi, tt.grp)
281 } else {
282 if err := r.JoinSourceSpecificGroup(ifi, tt.grp, tt.src); err != nil {
283 switch runtime.GOOS {
284 case "freebsd", "linux":
285 default:
286 t.Logf("not supported on %s", runtime.GOOS)
287 continue
288 }
289 t.Fatal(err)
290 }
291 defer r.LeaveSourceSpecificGroup(ifi, tt.grp, tt.src)
292 }
293 if err := r.SetMulticastInterface(ifi); err != nil {
294 t.Fatal(err)
295 }
296 if _, err := r.MulticastInterface(); err != nil {
297 t.Fatal(err)
298 }
299 if err := r.SetMulticastLoopback(true); err != nil {
300 t.Fatal(err)
301 }
302 if _, err := r.MulticastLoopback(); err != nil {
303 t.Fatal(err)
304 }
305 cf := ipv4.FlagTTL | ipv4.FlagDst | ipv4.FlagInterface
306
307 for i, toggle := range []bool{true, false, true} {
308 wb, err := (&icmp.Message{
309 Type: ipv4.ICMPTypeEcho, Code: 0,
310 Body: &icmp.Echo{
311 ID: os.Getpid() & 0xffff, Seq: i + 1,
312 Data: []byte("HELLO-R-U-THERE"),
313 },
314 }).Marshal(nil)
315 if err != nil {
316 t.Fatal(err)
317 }
318 wh := &ipv4.Header{
319 Version: ipv4.Version,
320 Len: ipv4.HeaderLen,
321 TOS: i + 1,
322 TotalLen: ipv4.HeaderLen + len(wb),
323 Protocol: 1,
324 Dst: tt.grp.IP,
325 }
326 if err := r.SetControlMessage(cf, toggle); err != nil {
327 if protocolNotSupported(err) {
328 t.Logf("not supported on %s", runtime.GOOS)
329 continue
330 }
331 t.Fatal(err)
332 }
333 r.SetMulticastTTL(i + 1)
334 if err := r.WriteTo(wh, wb, nil); err != nil {
335 t.Fatal(err)
336 }
337 rb := make([]byte, ipv4.HeaderLen+128)
338 if rh, b, _, err := r.ReadFrom(rb); err != nil {
339 t.Fatal(err)
340 } else {
341 m, err := icmp.ParseMessage(iana.ProtocolICMP, b)
342 if err != nil {
343 t.Fatal(err)
344 }
345 switch {
346 case (rh.Dst.IsLoopback() || rh.Dst.IsLinkLocalUnicast() || rh.Dst.IsGlobalUnicast()) && m.Type == ipv4.ICMPTypeEchoReply && m.Code == 0:
347 case rh.Dst.IsMulticast() && m.Type == ipv4.ICMPTypeEcho && m.Code == 0:
348 default:
349 t.Fatalf("got type=%v, code=%v; want type=%v, code=%v", m.Type, m.Code, ipv4.ICMPTypeEchoReply, 0)
350 }
351 }
352 }
353 }
354 }
355
View as plain text