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  }