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