1
2
3
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
27
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
85
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
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
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
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 }
239
View as plain text