github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/net/icmp/message_test.go (about) 1 // Copyright 2014 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 icmp_test 6 7 import ( 8 "bytes" 9 "net" 10 "reflect" 11 "testing" 12 13 "github.com/hxx258456/ccgo/net/icmp" 14 "github.com/hxx258456/ccgo/net/internal/iana" 15 "github.com/hxx258456/ccgo/net/ipv4" 16 "github.com/hxx258456/ccgo/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 /* Delay */, 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 /* Probe */, 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 { // Nil body 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 { // Empty body 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 { // Crafted body 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 { // Unaligned data and nil extension 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 { // Unaligned data and empty extension 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 { // Nil extension 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 { // Empty extension 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 { // Crafted extension 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 }