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