golang.org/x/net@v0.25.1-0.20240516223405-c87a5b62e243/ipv6/multicastsockopt_test.go (about)

     1  // Copyright 2013 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 ipv6_test
     6  
     7  import (
     8  	"net"
     9  	"runtime"
    10  	"testing"
    11  
    12  	"golang.org/x/net/ipv6"
    13  	"golang.org/x/net/nettest"
    14  )
    15  
    16  var packetConnMulticastSocketOptionTests = []struct {
    17  	net, proto, addr string
    18  	grp, src         net.Addr
    19  }{
    20  	{"udp6", "", "[ff02::]:0", &net.UDPAddr{IP: net.ParseIP("ff02::114")}, nil}, // see RFC 4727
    21  	{"ip6", ":ipv6-icmp", "::", &net.IPAddr{IP: net.ParseIP("ff02::115")}, nil}, // see RFC 4727
    22  
    23  	{"udp6", "", "[ff30::8000:0]:0", &net.UDPAddr{IP: net.ParseIP("ff30::8000:1")}, &net.UDPAddr{IP: net.IPv6loopback}}, // see RFC 5771
    24  	{"ip6", ":ipv6-icmp", "::", &net.IPAddr{IP: net.ParseIP("ff30::8000:2")}, &net.IPAddr{IP: net.IPv6loopback}},        // see RFC 5771
    25  }
    26  
    27  func TestPacketConnMulticastSocketOptions(t *testing.T) {
    28  	switch runtime.GOOS {
    29  	case "fuchsia", "hurd", "js", "nacl", "plan9", "wasip1", "windows":
    30  		t.Skipf("not supported on %s", runtime.GOOS)
    31  	}
    32  	if !nettest.SupportsIPv6() {
    33  		t.Skip("ipv6 is not supported")
    34  	}
    35  	ifi, err := nettest.RoutedInterface("ip6", net.FlagUp|net.FlagMulticast|net.FlagLoopback)
    36  	if err != nil {
    37  		t.Skipf("not available on %s", runtime.GOOS)
    38  	}
    39  
    40  	ok := nettest.SupportsRawSocket()
    41  	for _, tt := range packetConnMulticastSocketOptionTests {
    42  		if tt.net == "ip6" && !ok {
    43  			t.Logf("not supported on %s/%s", runtime.GOOS, runtime.GOARCH)
    44  			continue
    45  		}
    46  		c, err := net.ListenPacket(tt.net+tt.proto, tt.addr)
    47  		if err != nil {
    48  			t.Fatal(err)
    49  		}
    50  		defer c.Close()
    51  		p := ipv6.NewPacketConn(c)
    52  		defer p.Close()
    53  
    54  		if tt.src == nil {
    55  			testMulticastSocketOptions(t, p, ifi, tt.grp)
    56  		} else {
    57  			testSourceSpecificMulticastSocketOptions(t, p, ifi, tt.grp, tt.src)
    58  		}
    59  	}
    60  }
    61  
    62  type testIPv6MulticastConn interface {
    63  	MulticastHopLimit() (int, error)
    64  	SetMulticastHopLimit(ttl int) error
    65  	MulticastLoopback() (bool, error)
    66  	SetMulticastLoopback(bool) error
    67  	JoinGroup(*net.Interface, net.Addr) error
    68  	LeaveGroup(*net.Interface, net.Addr) error
    69  	JoinSourceSpecificGroup(*net.Interface, net.Addr, net.Addr) error
    70  	LeaveSourceSpecificGroup(*net.Interface, net.Addr, net.Addr) error
    71  	ExcludeSourceSpecificGroup(*net.Interface, net.Addr, net.Addr) error
    72  	IncludeSourceSpecificGroup(*net.Interface, net.Addr, net.Addr) error
    73  }
    74  
    75  func testMulticastSocketOptions(t *testing.T, c testIPv6MulticastConn, ifi *net.Interface, grp net.Addr) {
    76  	t.Helper()
    77  
    78  	const hoplim = 255
    79  	if err := c.SetMulticastHopLimit(hoplim); err != nil {
    80  		t.Error(err)
    81  		return
    82  	}
    83  	if v, err := c.MulticastHopLimit(); err != nil {
    84  		t.Error(err)
    85  		return
    86  	} else if v != hoplim {
    87  		t.Errorf("got %v; want %v", v, hoplim)
    88  		return
    89  	}
    90  
    91  	for _, toggle := range []bool{true, false} {
    92  		if err := c.SetMulticastLoopback(toggle); err != nil {
    93  			t.Error(err)
    94  			return
    95  		}
    96  		if v, err := c.MulticastLoopback(); err != nil {
    97  			t.Error(err)
    98  			return
    99  		} else if v != toggle {
   100  			t.Errorf("got %v; want %v", v, toggle)
   101  			return
   102  		}
   103  	}
   104  
   105  	if err := c.JoinGroup(ifi, grp); err != nil {
   106  		t.Error(err)
   107  		return
   108  	}
   109  	if err := c.LeaveGroup(ifi, grp); err != nil {
   110  		t.Error(err)
   111  		return
   112  	}
   113  }
   114  
   115  func testSourceSpecificMulticastSocketOptions(t *testing.T, c testIPv6MulticastConn, ifi *net.Interface, grp, src net.Addr) {
   116  	t.Helper()
   117  
   118  	// MCAST_JOIN_GROUP -> MCAST_BLOCK_SOURCE -> MCAST_UNBLOCK_SOURCE -> MCAST_LEAVE_GROUP
   119  	if err := c.JoinGroup(ifi, grp); err != nil {
   120  		t.Error(err)
   121  		return
   122  	}
   123  	if err := c.ExcludeSourceSpecificGroup(ifi, grp, src); err != nil {
   124  		switch runtime.GOOS {
   125  		case "freebsd", "linux":
   126  		default: // platforms that don't support MLDv2 fail here
   127  			t.Logf("not supported on %s", runtime.GOOS)
   128  			return
   129  		}
   130  		t.Error(err)
   131  		return
   132  	}
   133  	if err := c.IncludeSourceSpecificGroup(ifi, grp, src); err != nil {
   134  		t.Error(err)
   135  		return
   136  	}
   137  	if err := c.LeaveGroup(ifi, grp); err != nil {
   138  		t.Error(err)
   139  		return
   140  	}
   141  
   142  	// MCAST_JOIN_SOURCE_GROUP -> MCAST_LEAVE_SOURCE_GROUP
   143  	if err := c.JoinSourceSpecificGroup(ifi, grp, src); err != nil {
   144  		t.Error(err)
   145  		return
   146  	}
   147  	if err := c.LeaveSourceSpecificGroup(ifi, grp, src); err != nil {
   148  		t.Error(err)
   149  		return
   150  	}
   151  
   152  	// MCAST_JOIN_SOURCE_GROUP -> MCAST_LEAVE_GROUP
   153  	if err := c.JoinSourceSpecificGroup(ifi, grp, src); err != nil {
   154  		t.Error(err)
   155  		return
   156  	}
   157  	if err := c.LeaveGroup(ifi, grp); err != nil {
   158  		t.Error(err)
   159  		return
   160  	}
   161  }