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