github.com/Andyfoo/golang/x/net@v0.0.0-20190901054642-57c1bf301704/ipv4/unicast_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  func TestPacketConnReadWriteUnicastUDP(t *testing.T) {
    22  	switch runtime.GOOS {
    23  	case "fuchsia", "hurd", "js", "nacl", "plan9", "windows":
    24  		t.Skipf("not supported on %s", runtime.GOOS)
    25  	}
    26  	if _, err := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagLoopback); err != nil {
    27  		t.Skipf("not available on %s", runtime.GOOS)
    28  	}
    29  
    30  	c, err := nettest.NewLocalPacketListener("udp4")
    31  	if err != nil {
    32  		t.Fatal(err)
    33  	}
    34  	defer c.Close()
    35  	p := ipv4.NewPacketConn(c)
    36  	defer p.Close()
    37  
    38  	dst := c.LocalAddr()
    39  	cf := ipv4.FlagTTL | ipv4.FlagDst | ipv4.FlagInterface
    40  	wb := []byte("HELLO-R-U-THERE")
    41  
    42  	for i, toggle := range []bool{true, false, true} {
    43  		if err := p.SetControlMessage(cf, toggle); err != nil {
    44  			if protocolNotSupported(err) {
    45  				t.Logf("not supported on %s", runtime.GOOS)
    46  				continue
    47  			}
    48  			t.Fatal(err)
    49  		}
    50  		p.SetTTL(i + 1)
    51  		if err := p.SetWriteDeadline(time.Now().Add(100 * time.Millisecond)); err != nil {
    52  			t.Fatal(err)
    53  		}
    54  		if n, err := p.WriteTo(wb, nil, dst); err != nil {
    55  			t.Fatal(err)
    56  		} else if n != len(wb) {
    57  			t.Fatalf("got %v; want %v", n, len(wb))
    58  		}
    59  		rb := make([]byte, 128)
    60  		if err := p.SetReadDeadline(time.Now().Add(100 * time.Millisecond)); err != nil {
    61  			t.Fatal(err)
    62  		}
    63  		if n, _, _, err := p.ReadFrom(rb); err != nil {
    64  			t.Fatal(err)
    65  		} else if !bytes.Equal(rb[:n], wb) {
    66  			t.Fatalf("got %v; want %v", rb[:n], wb)
    67  		}
    68  	}
    69  }
    70  
    71  func TestPacketConnReadWriteUnicastICMP(t *testing.T) {
    72  	switch runtime.GOOS {
    73  	case "fuchsia", "hurd", "js", "nacl", "plan9", "windows":
    74  		t.Skipf("not supported on %s", runtime.GOOS)
    75  	}
    76  	if !nettest.SupportsRawSocket() {
    77  		t.Skipf("not supported on %s/%s", runtime.GOOS, runtime.GOARCH)
    78  	}
    79  	if _, err := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagLoopback); err != nil {
    80  		t.Skipf("not available on %s", runtime.GOOS)
    81  	}
    82  
    83  	c, err := net.ListenPacket("ip4:icmp", "0.0.0.0")
    84  	if err != nil {
    85  		t.Fatal(err)
    86  	}
    87  	defer c.Close()
    88  
    89  	dst, err := net.ResolveIPAddr("ip4", "127.0.0.1")
    90  	if err != nil {
    91  		t.Fatal(err)
    92  	}
    93  	p := ipv4.NewPacketConn(c)
    94  	defer p.Close()
    95  	cf := ipv4.FlagDst | ipv4.FlagInterface
    96  	if runtime.GOOS != "illumos" && runtime.GOOS != "solaris" {
    97  		// Illumos and Solaris never allow modification of ICMP properties.
    98  		cf |= ipv4.FlagTTL
    99  	}
   100  
   101  	for i, toggle := range []bool{true, false, true} {
   102  		wb, err := (&icmp.Message{
   103  			Type: ipv4.ICMPTypeEcho, Code: 0,
   104  			Body: &icmp.Echo{
   105  				ID: os.Getpid() & 0xffff, Seq: i + 1,
   106  				Data: []byte("HELLO-R-U-THERE"),
   107  			},
   108  		}).Marshal(nil)
   109  		if err != nil {
   110  			t.Fatal(err)
   111  		}
   112  		if err := p.SetControlMessage(cf, toggle); err != nil {
   113  			if protocolNotSupported(err) {
   114  				t.Logf("not supported on %s", runtime.GOOS)
   115  				continue
   116  			}
   117  			t.Fatal(err)
   118  		}
   119  		p.SetTTL(i + 1)
   120  		if err := p.SetWriteDeadline(time.Now().Add(100 * time.Millisecond)); err != nil {
   121  			t.Fatal(err)
   122  		}
   123  		if n, err := p.WriteTo(wb, nil, dst); err != nil {
   124  			t.Fatal(err)
   125  		} else if n != len(wb) {
   126  			t.Fatalf("got %v; want %v", n, len(wb))
   127  		}
   128  		rb := make([]byte, 128)
   129  	loop:
   130  		if err := p.SetReadDeadline(time.Now().Add(100 * time.Millisecond)); err != nil {
   131  			t.Fatal(err)
   132  		}
   133  		if n, _, _, err := p.ReadFrom(rb); err != nil {
   134  			switch runtime.GOOS {
   135  			case "darwin": // older darwin kernels have some limitation on receiving icmp packet through raw socket
   136  				t.Logf("not supported on %s", runtime.GOOS)
   137  				continue
   138  			}
   139  			t.Fatal(err)
   140  		} else {
   141  			m, err := icmp.ParseMessage(iana.ProtocolICMP, rb[:n])
   142  			if err != nil {
   143  				t.Fatal(err)
   144  			}
   145  			if runtime.GOOS == "linux" && m.Type == ipv4.ICMPTypeEcho {
   146  				// On Linux we must handle own sent packets.
   147  				goto loop
   148  			}
   149  			if m.Type != ipv4.ICMPTypeEchoReply || m.Code != 0 {
   150  				t.Fatalf("got type=%v, code=%v; want type=%v, code=%v", m.Type, m.Code, ipv4.ICMPTypeEchoReply, 0)
   151  			}
   152  		}
   153  	}
   154  }
   155  
   156  func TestRawConnReadWriteUnicastICMP(t *testing.T) {
   157  	switch runtime.GOOS {
   158  	case "fuchsia", "hurd", "js", "nacl", "plan9", "windows":
   159  		t.Skipf("not supported on %s", runtime.GOOS)
   160  	}
   161  	if !nettest.SupportsRawSocket() {
   162  		t.Skipf("not supported on %s/%s", runtime.GOOS, runtime.GOARCH)
   163  	}
   164  	if _, err := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagLoopback); err != nil {
   165  		t.Skipf("not available on %s", runtime.GOOS)
   166  	}
   167  
   168  	c, err := net.ListenPacket("ip4:icmp", "0.0.0.0")
   169  	if err != nil {
   170  		t.Fatal(err)
   171  	}
   172  	defer c.Close()
   173  
   174  	dst, err := net.ResolveIPAddr("ip4", "127.0.0.1")
   175  	if err != nil {
   176  		t.Fatal(err)
   177  	}
   178  	r, err := ipv4.NewRawConn(c)
   179  	if err != nil {
   180  		t.Fatal(err)
   181  	}
   182  	defer r.Close()
   183  	cf := ipv4.FlagTTL | ipv4.FlagDst | ipv4.FlagInterface
   184  
   185  	for i, toggle := range []bool{true, false, true} {
   186  		wb, err := (&icmp.Message{
   187  			Type: ipv4.ICMPTypeEcho, Code: 0,
   188  			Body: &icmp.Echo{
   189  				ID: os.Getpid() & 0xffff, Seq: i + 1,
   190  				Data: []byte("HELLO-R-U-THERE"),
   191  			},
   192  		}).Marshal(nil)
   193  		if err != nil {
   194  			t.Fatal(err)
   195  		}
   196  		wh := &ipv4.Header{
   197  			Version:  ipv4.Version,
   198  			Len:      ipv4.HeaderLen,
   199  			TOS:      i + 1,
   200  			TotalLen: ipv4.HeaderLen + len(wb),
   201  			TTL:      i + 1,
   202  			Protocol: 1,
   203  			Dst:      dst.IP,
   204  		}
   205  		if err := r.SetControlMessage(cf, toggle); err != nil {
   206  			if protocolNotSupported(err) {
   207  				t.Logf("not supported on %s", runtime.GOOS)
   208  				continue
   209  			}
   210  			t.Fatal(err)
   211  		}
   212  		if err := r.SetWriteDeadline(time.Now().Add(100 * time.Millisecond)); err != nil {
   213  			t.Fatal(err)
   214  		}
   215  		if err := r.WriteTo(wh, wb, nil); err != nil {
   216  			t.Fatal(err)
   217  		}
   218  		rb := make([]byte, ipv4.HeaderLen+128)
   219  	loop:
   220  		if err := r.SetReadDeadline(time.Now().Add(100 * time.Millisecond)); err != nil {
   221  			t.Fatal(err)
   222  		}
   223  		if _, b, _, err := r.ReadFrom(rb); err != nil {
   224  			switch runtime.GOOS {
   225  			case "darwin": // older darwin kernels have some limitation on receiving icmp packet through raw socket
   226  				t.Logf("not supported on %s", runtime.GOOS)
   227  				continue
   228  			}
   229  			t.Fatal(err)
   230  		} else {
   231  			m, err := icmp.ParseMessage(iana.ProtocolICMP, b)
   232  			if err != nil {
   233  				t.Fatal(err)
   234  			}
   235  			if runtime.GOOS == "linux" && m.Type == ipv4.ICMPTypeEcho {
   236  				// On Linux we must handle own sent packets.
   237  				goto loop
   238  			}
   239  			if m.Type != ipv4.ICMPTypeEchoReply || m.Code != 0 {
   240  				t.Fatalf("got type=%v, code=%v; want type=%v, code=%v", m.Type, m.Code, ipv4.ICMPTypeEchoReply, 0)
   241  			}
   242  		}
   243  	}
   244  }