golang.org/x/net@v0.25.1-0.20240516223405-c87a5b62e243/ipv4/multicastsockopt_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 "net" 9 "runtime" 10 "testing" 11 12 "golang.org/x/net/ipv4" 13 "golang.org/x/net/nettest" 14 ) 15 16 var packetConnMulticastSocketOptionTests = []struct { 17 net, proto, addr string 18 grp, src net.Addr 19 }{ 20 {"udp4", "", "224.0.0.0:0", &net.UDPAddr{IP: net.IPv4(224, 0, 0, 249)}, nil}, // see RFC 4727 21 {"ip4", ":icmp", "0.0.0.0", &net.IPAddr{IP: net.IPv4(224, 0, 0, 250)}, nil}, // see RFC 4727 22 23 {"udp4", "", "232.0.0.0:0", &net.UDPAddr{IP: net.IPv4(232, 0, 1, 249)}, &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1)}}, // see RFC 5771 24 {"ip4", ":icmp", "0.0.0.0", &net.IPAddr{IP: net.IPv4(232, 0, 1, 250)}, &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1)}}, // see RFC 5771 25 } 26 27 func TestPacketConnMulticastSocketOptions(t *testing.T) { 28 switch runtime.GOOS { 29 case "fuchsia", "hurd", "js", "nacl", "plan9", "wasip1", "zos": 30 t.Skipf("not supported on %s", runtime.GOOS) 31 } 32 ifi, err := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagMulticast|net.FlagLoopback) 33 if err != nil { 34 t.Skipf("not available on %s", runtime.GOOS) 35 } 36 37 ok := nettest.SupportsRawSocket() 38 for _, tt := range packetConnMulticastSocketOptionTests { 39 if tt.net == "ip4" && !ok { 40 t.Logf("not supported on %s/%s", runtime.GOOS, runtime.GOARCH) 41 continue 42 } 43 c, err := net.ListenPacket(tt.net+tt.proto, tt.addr) 44 if err != nil { 45 t.Fatal(err) 46 } 47 defer c.Close() 48 p := ipv4.NewPacketConn(c) 49 defer p.Close() 50 51 if tt.src == nil { 52 testMulticastSocketOptions(t, p, ifi, tt.grp) 53 } else { 54 testSourceSpecificMulticastSocketOptions(t, p, ifi, tt.grp, tt.src) 55 } 56 } 57 } 58 59 var rawConnMulticastSocketOptionTests = []struct { 60 grp, src net.Addr 61 }{ 62 {&net.IPAddr{IP: net.IPv4(224, 0, 0, 250)}, nil}, // see RFC 4727 63 64 {&net.IPAddr{IP: net.IPv4(232, 0, 1, 250)}, &net.IPAddr{IP: net.IPv4(127, 0, 0, 1)}}, // see RFC 5771 65 } 66 67 func TestRawConnMulticastSocketOptions(t *testing.T) { 68 if !nettest.SupportsRawSocket() { 69 t.Skipf("not supported on %s/%s", runtime.GOOS, runtime.GOARCH) 70 } 71 ifi, err := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagMulticast|net.FlagLoopback) 72 if err != nil { 73 t.Skipf("not available on %s", runtime.GOOS) 74 } 75 76 for _, tt := range rawConnMulticastSocketOptionTests { 77 c, err := net.ListenPacket("ip4:icmp", "0.0.0.0") 78 if err != nil { 79 t.Fatal(err) 80 } 81 defer c.Close() 82 r, err := ipv4.NewRawConn(c) 83 if err != nil { 84 t.Fatal(err) 85 } 86 defer r.Close() 87 88 if tt.src == nil { 89 testMulticastSocketOptions(t, r, ifi, tt.grp) 90 } else { 91 testSourceSpecificMulticastSocketOptions(t, r, ifi, tt.grp, tt.src) 92 } 93 } 94 } 95 96 type testIPv4MulticastConn interface { 97 MulticastTTL() (int, error) 98 SetMulticastTTL(ttl int) error 99 MulticastLoopback() (bool, error) 100 SetMulticastLoopback(bool) error 101 JoinGroup(*net.Interface, net.Addr) error 102 LeaveGroup(*net.Interface, net.Addr) error 103 JoinSourceSpecificGroup(*net.Interface, net.Addr, net.Addr) error 104 LeaveSourceSpecificGroup(*net.Interface, net.Addr, net.Addr) error 105 ExcludeSourceSpecificGroup(*net.Interface, net.Addr, net.Addr) error 106 IncludeSourceSpecificGroup(*net.Interface, net.Addr, net.Addr) error 107 } 108 109 func testMulticastSocketOptions(t *testing.T, c testIPv4MulticastConn, ifi *net.Interface, grp net.Addr) { 110 t.Helper() 111 112 const ttl = 255 113 if err := c.SetMulticastTTL(ttl); err != nil { 114 t.Error(err) 115 return 116 } 117 if v, err := c.MulticastTTL(); err != nil { 118 t.Error(err) 119 return 120 } else if v != ttl { 121 t.Errorf("got %v; want %v", v, ttl) 122 return 123 } 124 125 for _, toggle := range []bool{true, false} { 126 if err := c.SetMulticastLoopback(toggle); err != nil { 127 t.Error(err) 128 return 129 } 130 if v, err := c.MulticastLoopback(); err != nil { 131 t.Error(err) 132 return 133 } else if v != toggle { 134 t.Errorf("got %v; want %v", v, toggle) 135 return 136 } 137 } 138 139 if err := c.JoinGroup(ifi, grp); err != nil { 140 t.Error(err) 141 return 142 } 143 if err := c.LeaveGroup(ifi, grp); err != nil { 144 t.Error(err) 145 return 146 } 147 } 148 149 func testSourceSpecificMulticastSocketOptions(t *testing.T, c testIPv4MulticastConn, ifi *net.Interface, grp, src net.Addr) { 150 t.Helper() 151 152 // MCAST_JOIN_GROUP -> MCAST_BLOCK_SOURCE -> MCAST_UNBLOCK_SOURCE -> MCAST_LEAVE_GROUP 153 if err := c.JoinGroup(ifi, grp); err != nil { 154 t.Error(err) 155 return 156 } 157 if err := c.ExcludeSourceSpecificGroup(ifi, grp, src); err != nil { 158 switch runtime.GOOS { 159 case "freebsd", "linux": 160 default: // platforms that don't support IGMPv2/3 fail here 161 t.Logf("not supported on %s", runtime.GOOS) 162 return 163 } 164 t.Error(err) 165 return 166 } 167 if err := c.IncludeSourceSpecificGroup(ifi, grp, src); err != nil { 168 t.Error(err) 169 return 170 } 171 if err := c.LeaveGroup(ifi, grp); err != nil { 172 t.Error(err) 173 return 174 } 175 176 // MCAST_JOIN_SOURCE_GROUP -> MCAST_LEAVE_SOURCE_GROUP 177 if err := c.JoinSourceSpecificGroup(ifi, grp, src); err != nil { 178 t.Error(err) 179 return 180 } 181 if err := c.LeaveSourceSpecificGroup(ifi, grp, src); err != nil { 182 t.Error(err) 183 return 184 } 185 186 // MCAST_JOIN_SOURCE_GROUP -> MCAST_LEAVE_GROUP 187 if err := c.JoinSourceSpecificGroup(ifi, grp, src); err != nil { 188 t.Error(err) 189 return 190 } 191 if err := c.LeaveGroup(ifi, grp); err != nil { 192 t.Error(err) 193 return 194 } 195 }