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  }