multicast_test.go 9.0 KB

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