1
2
3
4
5 package icmp_test
6
7 import (
8 "bytes"
9 "net"
10 "reflect"
11 "testing"
12
13 "golang.org/x/net/icmp"
14 "golang.org/x/net/internal/iana"
15 "golang.org/x/net/ipv4"
16 "golang.org/x/net/ipv6"
17 )
18
19 func TestMarshalAndParseMessage(t *testing.T) {
20 fn := func(t *testing.T, proto int, tms []icmp.Message) {
21 var pshs [][]byte
22 switch proto {
23 case iana.ProtocolICMP:
24 pshs = [][]byte{nil}
25 case iana.ProtocolIPv6ICMP:
26 pshs = [][]byte{
27 icmp.IPv6PseudoHeader(net.ParseIP("fe80::1"), net.ParseIP("ff02::1")),
28 nil,
29 }
30 }
31 for i, tm := range tms {
32 for _, psh := range pshs {
33 b, err := tm.Marshal(psh)
34 if err != nil {
35 t.Fatalf("#%d: %v", i, err)
36 }
37 m, err := icmp.ParseMessage(proto, b)
38 if err != nil {
39 t.Fatalf("#%d: %v", i, err)
40 }
41 if m.Type != tm.Type || m.Code != tm.Code {
42 t.Errorf("#%d: got %#v; want %#v", i, m, &tm)
43 continue
44 }
45 if !reflect.DeepEqual(m.Body, tm.Body) {
46 t.Errorf("#%d: got %#v; want %#v", i, m.Body, tm.Body)
47 continue
48 }
49 }
50 }
51 }
52
53 t.Run("IPv4", func(t *testing.T) {
54 fn(t, iana.ProtocolICMP,
55 []icmp.Message{
56 {
57 Type: ipv4.ICMPTypeDestinationUnreachable, Code: 15,
58 Body: &icmp.DstUnreach{
59 Data: []byte("ERROR-INVOKING-PACKET"),
60 },
61 },
62 {
63 Type: ipv4.ICMPTypeTimeExceeded, Code: 1,
64 Body: &icmp.TimeExceeded{
65 Data: []byte("ERROR-INVOKING-PACKET"),
66 },
67 },
68 {
69 Type: ipv4.ICMPTypeParameterProblem, Code: 2,
70 Body: &icmp.ParamProb{
71 Pointer: 8,
72 Data: []byte("ERROR-INVOKING-PACKET"),
73 },
74 },
75 {
76 Type: ipv4.ICMPTypeEcho, Code: 0,
77 Body: &icmp.Echo{
78 ID: 1, Seq: 2,
79 Data: []byte("HELLO-R-U-THERE"),
80 },
81 },
82 {
83 Type: ipv4.ICMPTypeExtendedEchoRequest, Code: 0,
84 Body: &icmp.ExtendedEchoRequest{
85 ID: 1, Seq: 2,
86 Extensions: []icmp.Extension{
87 &icmp.InterfaceIdent{
88 Class: 3,
89 Type: 1,
90 Name: "en101",
91 },
92 },
93 },
94 },
95 {
96 Type: ipv4.ICMPTypeExtendedEchoReply, Code: 0,
97 Body: &icmp.ExtendedEchoReply{
98 State: 4 , Active: true, IPv4: true,
99 },
100 },
101 })
102 })
103 t.Run("IPv6", func(t *testing.T) {
104 fn(t, iana.ProtocolIPv6ICMP,
105 []icmp.Message{
106 {
107 Type: ipv6.ICMPTypeDestinationUnreachable, Code: 6,
108 Body: &icmp.DstUnreach{
109 Data: []byte("ERROR-INVOKING-PACKET"),
110 },
111 },
112 {
113 Type: ipv6.ICMPTypePacketTooBig, Code: 0,
114 Body: &icmp.PacketTooBig{
115 MTU: 1<<16 - 1,
116 Data: []byte("ERROR-INVOKING-PACKET"),
117 },
118 },
119 {
120 Type: ipv6.ICMPTypeTimeExceeded, Code: 1,
121 Body: &icmp.TimeExceeded{
122 Data: []byte("ERROR-INVOKING-PACKET"),
123 },
124 },
125 {
126 Type: ipv6.ICMPTypeParameterProblem, Code: 2,
127 Body: &icmp.ParamProb{
128 Pointer: 8,
129 Data: []byte("ERROR-INVOKING-PACKET"),
130 },
131 },
132 {
133 Type: ipv6.ICMPTypeEchoRequest, Code: 0,
134 Body: &icmp.Echo{
135 ID: 1, Seq: 2,
136 Data: []byte("HELLO-R-U-THERE"),
137 },
138 },
139 {
140 Type: ipv6.ICMPTypeExtendedEchoRequest, Code: 0,
141 Body: &icmp.ExtendedEchoRequest{
142 ID: 1, Seq: 2,
143 Extensions: []icmp.Extension{
144 &icmp.InterfaceIdent{
145 Class: 3,
146 Type: 2,
147 Index: 911,
148 },
149 },
150 },
151 },
152 {
153 Type: ipv6.ICMPTypeExtendedEchoReply, Code: 0,
154 Body: &icmp.ExtendedEchoReply{
155 State: 5 , Active: true, IPv6: true,
156 },
157 },
158 })
159 })
160 }
161
162 func TestMarshalAndParseRawMessage(t *testing.T) {
163 t.Run("RawBody", func(t *testing.T) {
164 for i, tt := range []struct {
165 m icmp.Message
166 wire []byte
167 parseShouldFail bool
168 }{
169 {
170 m: icmp.Message{
171 Type: ipv4.ICMPTypeDestinationUnreachable, Code: 127,
172 },
173 wire: []byte{
174 0x03, 0x7f, 0xfc, 0x80,
175 },
176 parseShouldFail: true,
177 },
178 {
179 m: icmp.Message{
180 Type: ipv6.ICMPTypeDestinationUnreachable, Code: 128,
181 Body: &icmp.RawBody{},
182 },
183 wire: []byte{
184 0x01, 0x80, 0x00, 0x00,
185 },
186 parseShouldFail: true,
187 },
188 {
189 m: icmp.Message{
190 Type: ipv6.ICMPTypeDuplicateAddressConfirmation, Code: 129,
191 Body: &icmp.RawBody{
192 Data: []byte{0xca, 0xfe},
193 },
194 },
195 wire: []byte{
196 0x9e, 0x81, 0x00, 0x00,
197 0xca, 0xfe,
198 },
199 parseShouldFail: false,
200 },
201 } {
202 b, err := tt.m.Marshal(nil)
203 if err != nil {
204 t.Errorf("#%d: %v", i, err)
205 continue
206 }
207 if !bytes.Equal(b, tt.wire) {
208 t.Errorf("#%d: got %#v; want %#v", i, b, tt.wire)
209 continue
210 }
211 m, err := icmp.ParseMessage(tt.m.Type.Protocol(), b)
212 if err != nil != tt.parseShouldFail {
213 t.Errorf("#%d: got %v, %v", i, m, err)
214 continue
215 }
216 if tt.parseShouldFail {
217 continue
218 }
219 if m.Type != tt.m.Type || m.Code != tt.m.Code {
220 t.Errorf("#%d: got %v; want %v", i, m, tt.m)
221 continue
222 }
223 if !bytes.Equal(m.Body.(*icmp.RawBody).Data, tt.m.Body.(*icmp.RawBody).Data) {
224 t.Errorf("#%d: got %#v; want %#v", i, m.Body, tt.m.Body)
225 continue
226 }
227 }
228 })
229 t.Run("RawExtension", func(t *testing.T) {
230 for i, tt := range []struct {
231 m icmp.Message
232 wire []byte
233 }{
234 {
235 m: icmp.Message{
236 Type: ipv6.ICMPTypeDestinationUnreachable, Code: 130,
237 Body: &icmp.DstUnreach{
238 Data: []byte("ERROR-INVOKING-PACKET"),
239 },
240 },
241 wire: []byte{
242 0x01, 0x82, 0x00, 0x00,
243 0x00, 0x00, 0x00, 0x00,
244 'E', 'R', 'R', 'O',
245 'R', '-', 'I', 'N',
246 'V', 'O', 'K', 'I',
247 'N', 'G', '-', 'P',
248 'A', 'C', 'K', 'E',
249 'T',
250 },
251 },
252 {
253 m: icmp.Message{
254 Type: ipv6.ICMPTypeDestinationUnreachable, Code: 131,
255 Body: &icmp.DstUnreach{
256 Data: []byte("ERROR-INVOKING-PACKET"),
257 Extensions: []icmp.Extension{
258 &icmp.RawExtension{},
259 },
260 },
261 },
262 wire: []byte{
263 0x01, 0x83, 0x00, 0x00,
264 0x02, 0x00, 0x00, 0x00,
265 'E', 'R', 'R', 'O',
266 'R', '-', 'I', 'N',
267 'V', 'O', 'K', 'I',
268 'N', 'G', '-', 'P',
269 'A', 'C', 'K', 'E',
270 'T',
271 0x20, 0x00, 0xdf, 0xff,
272 },
273 },
274 {
275 m: icmp.Message{
276 Type: ipv6.ICMPTypeExtendedEchoRequest, Code: 132,
277 Body: &icmp.ExtendedEchoRequest{
278 ID: 1, Seq: 2, Local: true,
279 },
280 },
281 wire: []byte{
282 0xa0, 0x84, 0x00, 0x00,
283 0x00, 0x01, 0x02, 0x01,
284 },
285 },
286 {
287 m: icmp.Message{
288 Type: ipv6.ICMPTypeExtendedEchoRequest, Code: 133,
289 Body: &icmp.ExtendedEchoRequest{
290 ID: 1, Seq: 2, Local: true,
291 Extensions: []icmp.Extension{
292 &icmp.RawExtension{},
293 },
294 },
295 },
296 wire: []byte{
297 0xa0, 0x85, 0x00, 0x00,
298 0x00, 0x01, 0x02, 0x01,
299 0x20, 0x00, 0xdf, 0xff,
300 },
301 },
302 {
303 m: icmp.Message{
304 Type: ipv6.ICMPTypeExtendedEchoRequest, Code: 134,
305 Body: &icmp.ExtendedEchoRequest{
306 ID: 1, Seq: 2, Local: true,
307 Extensions: []icmp.Extension{
308 &icmp.RawExtension{
309 Data: []byte("CRAFTED"),
310 },
311 },
312 },
313 },
314 wire: []byte{
315 0xa0, 0x86, 0x00, 0x00,
316 0x00, 0x01, 0x02, 0x01,
317 0x20, 0x00, 0xc3, 0x21,
318 'C', 'R', 'A', 'F',
319 'T', 'E', 'D',
320 },
321 },
322 } {
323 b, err := tt.m.Marshal(nil)
324 if err != nil {
325 t.Errorf("#%d: %v", i, err)
326 continue
327 }
328 if !bytes.Equal(b, tt.wire) {
329 t.Errorf("#%d: got %#v; want %#v", i, b, tt.wire)
330 continue
331 }
332 m, err := icmp.ParseMessage(tt.m.Type.Protocol(), b)
333 if err != nil {
334 t.Errorf("#%d: %v", i, err)
335 continue
336 }
337 if m.Type != tt.m.Type || m.Code != tt.m.Code {
338 t.Errorf("#%d: got %v; want %v", i, m, tt.m)
339 continue
340 }
341 }
342 })
343 }
344
View as plain text