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