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