golang.org/x/net@v0.25.1-0.20240516223405-c87a5b62e243/ipv6/unicast_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  	"bytes"
     9  	"errors"
    10  	"net"
    11  	"os"
    12  	"runtime"
    13  	"testing"
    14  	"time"
    15  
    16  	"golang.org/x/net/icmp"
    17  	"golang.org/x/net/internal/iana"
    18  	"golang.org/x/net/ipv6"
    19  	"golang.org/x/net/nettest"
    20  )
    21  
    22  func TestPacketConnReadWriteUnicastUDP(t *testing.T) {
    23  	switch runtime.GOOS {
    24  	case "fuchsia", "hurd", "js", "nacl", "plan9", "wasip1", "windows":
    25  		t.Skipf("not supported on %s", runtime.GOOS)
    26  	}
    27  	if _, err := nettest.RoutedInterface("ip6", net.FlagUp|net.FlagLoopback); err != nil {
    28  		t.Skip("ipv6 is not enabled for loopback interface")
    29  	}
    30  
    31  	c, err := nettest.NewLocalPacketListener("udp6")
    32  	if err != nil {
    33  		t.Fatal(err)
    34  	}
    35  	defer c.Close()
    36  	p := ipv6.NewPacketConn(c)
    37  	defer p.Close()
    38  
    39  	dst := c.LocalAddr()
    40  	cm := ipv6.ControlMessage{
    41  		TrafficClass: iana.DiffServAF11 | iana.CongestionExperienced,
    42  		Src:          net.IPv6loopback,
    43  	}
    44  	cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagSrc | ipv6.FlagDst | ipv6.FlagInterface | ipv6.FlagPathMTU
    45  	ifi, _ := nettest.RoutedInterface("ip6", net.FlagUp|net.FlagLoopback)
    46  	if ifi != nil {
    47  		cm.IfIndex = ifi.Index
    48  	}
    49  	wb := []byte("HELLO-R-U-THERE")
    50  
    51  	for i, toggle := range []bool{true, false, true} {
    52  		if err := p.SetControlMessage(cf, toggle); err != nil {
    53  			if protocolNotSupported(err) {
    54  				t.Logf("not supported on %s", runtime.GOOS)
    55  				continue
    56  			}
    57  			t.Fatal(err)
    58  		}
    59  		cm.HopLimit = i + 1
    60  
    61  		backoff := time.Millisecond
    62  		for {
    63  			n, err := p.WriteTo(wb, &cm, dst)
    64  			if err != nil {
    65  				if n == 0 && isENOBUFS(err) {
    66  					time.Sleep(backoff)
    67  					backoff *= 2
    68  					continue
    69  				}
    70  				t.Fatal(err)
    71  			}
    72  			if n != len(wb) {
    73  				t.Fatalf("got %d; want %d", n, len(wb))
    74  			}
    75  			break
    76  		}
    77  
    78  		rb := make([]byte, 128)
    79  		if n, _, _, err := p.ReadFrom(rb); err != nil {
    80  			t.Fatal(err)
    81  		} else if !bytes.Equal(rb[:n], wb) {
    82  			t.Fatalf("got %v; want %v", rb[:n], wb)
    83  		}
    84  	}
    85  }
    86  
    87  func TestPacketConnReadWriteUnicastICMP(t *testing.T) {
    88  	if !nettest.SupportsIPv6() {
    89  		t.Skip("ipv6 is not supported")
    90  	}
    91  	if !nettest.SupportsRawSocket() {
    92  		t.Skipf("not supported on %s/%s", runtime.GOOS, runtime.GOARCH)
    93  	}
    94  
    95  	c, err := net.ListenPacket("ip6:ipv6-icmp", "::1")
    96  	if err != nil {
    97  		t.Fatal(err)
    98  	}
    99  	defer c.Close()
   100  	p := ipv6.NewPacketConn(c)
   101  	defer p.Close()
   102  
   103  	dst, err := net.ResolveIPAddr("ip6", "::1")
   104  	if err != nil {
   105  		t.Fatal(err)
   106  	}
   107  
   108  	pshicmp := icmp.IPv6PseudoHeader(c.LocalAddr().(*net.IPAddr).IP, dst.IP)
   109  	cm := ipv6.ControlMessage{
   110  		TrafficClass: iana.DiffServAF11 | iana.CongestionExperienced,
   111  		Src:          net.IPv6loopback,
   112  	}
   113  	cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagSrc | ipv6.FlagDst | ipv6.FlagInterface | ipv6.FlagPathMTU
   114  	ifi, _ := nettest.RoutedInterface("ip6", net.FlagUp|net.FlagLoopback)
   115  	if ifi != nil {
   116  		cm.IfIndex = ifi.Index
   117  	}
   118  
   119  	var f ipv6.ICMPFilter
   120  	f.SetAll(true)
   121  	f.Accept(ipv6.ICMPTypeEchoReply)
   122  	if err := p.SetICMPFilter(&f); errors.Is(err, ipv6.ErrNotImplemented) {
   123  		t.Skipf("setting ICMP filter not supported: %v", err)
   124  	} else if err != nil {
   125  		t.Fatal(err)
   126  	}
   127  
   128  	var psh []byte
   129  	for i, toggle := range []bool{true, false, true} {
   130  		if toggle {
   131  			psh = nil
   132  			if err := p.SetChecksum(true, 2); err != nil {
   133  				// AIX, Illumos and Solaris never allow
   134  				// modification of ICMP properties.
   135  				switch runtime.GOOS {
   136  				case "aix", "illumos", "solaris":
   137  				default:
   138  					t.Fatal(err)
   139  				}
   140  			}
   141  		} else {
   142  			psh = pshicmp
   143  			// Some platforms never allow to disable the
   144  			// kernel checksum processing.
   145  			p.SetChecksum(false, -1)
   146  		}
   147  		wb, err := (&icmp.Message{
   148  			Type: ipv6.ICMPTypeEchoRequest, Code: 0,
   149  			Body: &icmp.Echo{
   150  				ID: os.Getpid() & 0xffff, Seq: i + 1,
   151  				Data: []byte("HELLO-R-U-THERE"),
   152  			},
   153  		}).Marshal(psh)
   154  		if err != nil {
   155  			t.Fatal(err)
   156  		}
   157  		if err := p.SetControlMessage(cf, toggle); err != nil {
   158  			if protocolNotSupported(err) {
   159  				t.Logf("not supported on %s", runtime.GOOS)
   160  				continue
   161  			}
   162  			t.Fatal(err)
   163  		}
   164  		cm.HopLimit = i + 1
   165  
   166  		backoff := time.Millisecond
   167  		for {
   168  			n, err := p.WriteTo(wb, &cm, dst)
   169  			if err != nil {
   170  				if n == 0 && isENOBUFS(err) {
   171  					time.Sleep(backoff)
   172  					backoff *= 2
   173  					continue
   174  				}
   175  				t.Fatal(err)
   176  			}
   177  			if n != len(wb) {
   178  				t.Fatalf("got %d; want %d", n, len(wb))
   179  			}
   180  			break
   181  		}
   182  
   183  		rb := make([]byte, 128)
   184  		if n, _, _, err := p.ReadFrom(rb); err != nil {
   185  			t.Fatal(err)
   186  		} else {
   187  			if m, err := icmp.ParseMessage(iana.ProtocolIPv6ICMP, rb[:n]); err != nil {
   188  				t.Fatal(err)
   189  			} else if m.Type != ipv6.ICMPTypeEchoReply || m.Code != 0 {
   190  				t.Fatalf("got type=%v, code=%v; want type=%v, code=%v", m.Type, m.Code, ipv6.ICMPTypeEchoReply, 0)
   191  			}
   192  		}
   193  	}
   194  }