gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/packetimpact/testbench/layers_test.go (about) 1 // Copyright 2020 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package testbench 16 17 import ( 18 "bytes" 19 "encoding/hex" 20 "net" 21 "testing" 22 23 "github.com/mohae/deepcopy" 24 "gvisor.dev/gvisor/pkg/tcpip" 25 "gvisor.dev/gvisor/pkg/tcpip/header" 26 ) 27 28 func TestLayerMatch(t *testing.T) { 29 var nilPayload *Payload 30 noPayload := &Payload{} 31 emptyPayload := &Payload{Bytes: []byte{}} 32 fullPayload := &Payload{Bytes: []byte{1, 2, 3}} 33 emptyTCP := &TCP{SrcPort: Uint16(1234), LayerBase: LayerBase{nextLayer: emptyPayload}} 34 fullTCP := &TCP{SrcPort: Uint16(1234), LayerBase: LayerBase{nextLayer: fullPayload}} 35 for _, tt := range []struct { 36 a, b Layer 37 want bool 38 }{ 39 {nilPayload, nilPayload, true}, 40 {nilPayload, noPayload, true}, 41 {nilPayload, emptyPayload, true}, 42 {nilPayload, fullPayload, true}, 43 {noPayload, noPayload, true}, 44 {noPayload, emptyPayload, true}, 45 {noPayload, fullPayload, true}, 46 {emptyPayload, emptyPayload, true}, 47 {emptyPayload, fullPayload, false}, 48 {fullPayload, fullPayload, true}, 49 {emptyTCP, fullTCP, true}, 50 } { 51 if got := tt.a.match(tt.b); got != tt.want { 52 t.Errorf("%s.match(%s) = %t, want %t", tt.a, tt.b, got, tt.want) 53 } 54 if got := tt.b.match(tt.a); got != tt.want { 55 t.Errorf("%s.match(%s) = %t, want %t", tt.b, tt.a, got, tt.want) 56 } 57 } 58 } 59 60 func TestLayerMergeMismatch(t *testing.T) { 61 tcp := &TCP{} 62 otherTCP := &TCP{} 63 ipv4 := &IPv4{} 64 ether := &Ether{} 65 for _, tt := range []struct { 66 a, b Layer 67 success bool 68 }{ 69 {tcp, tcp, true}, 70 {tcp, otherTCP, true}, 71 {tcp, ipv4, false}, 72 {tcp, ether, false}, 73 {tcp, nil, true}, 74 75 {otherTCP, otherTCP, true}, 76 {otherTCP, ipv4, false}, 77 {otherTCP, ether, false}, 78 {otherTCP, nil, true}, 79 80 {ipv4, ipv4, true}, 81 {ipv4, ether, false}, 82 {ipv4, nil, true}, 83 84 {ether, ether, true}, 85 {ether, nil, true}, 86 } { 87 if err := tt.a.merge(tt.b); (err == nil) != tt.success { 88 t.Errorf("%s.merge(%s) got %s, wanted the opposite", tt.a, tt.b, err) 89 } 90 if tt.b != nil { 91 if err := tt.b.merge(tt.a); (err == nil) != tt.success { 92 t.Errorf("%s.merge(%s) got %s, wanted the opposite", tt.b, tt.a, err) 93 } 94 } 95 } 96 } 97 98 func TestLayerMerge(t *testing.T) { 99 zero := Uint32(0) 100 one := Uint32(1) 101 two := Uint32(2) 102 empty := []byte{} 103 foo := []byte("foo") 104 bar := []byte("bar") 105 for _, tt := range []struct { 106 a, b Layer 107 want Layer 108 }{ 109 {&TCP{AckNum: nil}, &TCP{AckNum: nil}, &TCP{AckNum: nil}}, 110 {&TCP{AckNum: nil}, &TCP{AckNum: zero}, &TCP{AckNum: zero}}, 111 {&TCP{AckNum: nil}, &TCP{AckNum: one}, &TCP{AckNum: one}}, 112 {&TCP{AckNum: nil}, &TCP{AckNum: two}, &TCP{AckNum: two}}, 113 {&TCP{AckNum: nil}, nil, &TCP{AckNum: nil}}, 114 115 {&TCP{AckNum: zero}, &TCP{AckNum: nil}, &TCP{AckNum: zero}}, 116 {&TCP{AckNum: zero}, &TCP{AckNum: zero}, &TCP{AckNum: zero}}, 117 {&TCP{AckNum: zero}, &TCP{AckNum: one}, &TCP{AckNum: one}}, 118 {&TCP{AckNum: zero}, &TCP{AckNum: two}, &TCP{AckNum: two}}, 119 {&TCP{AckNum: zero}, nil, &TCP{AckNum: zero}}, 120 121 {&TCP{AckNum: one}, &TCP{AckNum: nil}, &TCP{AckNum: one}}, 122 {&TCP{AckNum: one}, &TCP{AckNum: zero}, &TCP{AckNum: zero}}, 123 {&TCP{AckNum: one}, &TCP{AckNum: one}, &TCP{AckNum: one}}, 124 {&TCP{AckNum: one}, &TCP{AckNum: two}, &TCP{AckNum: two}}, 125 {&TCP{AckNum: one}, nil, &TCP{AckNum: one}}, 126 127 {&TCP{AckNum: two}, &TCP{AckNum: nil}, &TCP{AckNum: two}}, 128 {&TCP{AckNum: two}, &TCP{AckNum: zero}, &TCP{AckNum: zero}}, 129 {&TCP{AckNum: two}, &TCP{AckNum: one}, &TCP{AckNum: one}}, 130 {&TCP{AckNum: two}, &TCP{AckNum: two}, &TCP{AckNum: two}}, 131 {&TCP{AckNum: two}, nil, &TCP{AckNum: two}}, 132 133 {&Payload{Bytes: nil}, &Payload{Bytes: nil}, &Payload{Bytes: nil}}, 134 {&Payload{Bytes: nil}, &Payload{Bytes: empty}, &Payload{Bytes: empty}}, 135 {&Payload{Bytes: nil}, &Payload{Bytes: foo}, &Payload{Bytes: foo}}, 136 {&Payload{Bytes: nil}, &Payload{Bytes: bar}, &Payload{Bytes: bar}}, 137 {&Payload{Bytes: nil}, nil, &Payload{Bytes: nil}}, 138 139 {&Payload{Bytes: empty}, &Payload{Bytes: nil}, &Payload{Bytes: empty}}, 140 {&Payload{Bytes: empty}, &Payload{Bytes: empty}, &Payload{Bytes: empty}}, 141 {&Payload{Bytes: empty}, &Payload{Bytes: foo}, &Payload{Bytes: foo}}, 142 {&Payload{Bytes: empty}, &Payload{Bytes: bar}, &Payload{Bytes: bar}}, 143 {&Payload{Bytes: empty}, nil, &Payload{Bytes: empty}}, 144 145 {&Payload{Bytes: foo}, &Payload{Bytes: nil}, &Payload{Bytes: foo}}, 146 {&Payload{Bytes: foo}, &Payload{Bytes: empty}, &Payload{Bytes: empty}}, 147 {&Payload{Bytes: foo}, &Payload{Bytes: foo}, &Payload{Bytes: foo}}, 148 {&Payload{Bytes: foo}, &Payload{Bytes: bar}, &Payload{Bytes: bar}}, 149 {&Payload{Bytes: foo}, nil, &Payload{Bytes: foo}}, 150 151 {&Payload{Bytes: bar}, &Payload{Bytes: nil}, &Payload{Bytes: bar}}, 152 {&Payload{Bytes: bar}, &Payload{Bytes: empty}, &Payload{Bytes: empty}}, 153 {&Payload{Bytes: bar}, &Payload{Bytes: foo}, &Payload{Bytes: foo}}, 154 {&Payload{Bytes: bar}, &Payload{Bytes: bar}, &Payload{Bytes: bar}}, 155 {&Payload{Bytes: bar}, nil, &Payload{Bytes: bar}}, 156 } { 157 a := deepcopy.Copy(tt.a).(Layer) 158 if err := a.merge(tt.b); err != nil { 159 t.Errorf("%s.merge(%s) = %s, wanted nil", tt.a, tt.b, err) 160 continue 161 } 162 if a.String() != tt.want.String() { 163 t.Errorf("%s.merge(%s) merge result got %s, want %s", tt.a, tt.b, a, tt.want) 164 } 165 } 166 } 167 168 func TestLayerStringFormat(t *testing.T) { 169 for _, tt := range []struct { 170 name string 171 l Layer 172 want string 173 }{ 174 { 175 name: "TCP", 176 l: &TCP{ 177 SrcPort: Uint16(34785), 178 DstPort: Uint16(47767), 179 SeqNum: Uint32(3452155723), 180 AckNum: Uint32(2596996163), 181 DataOffset: Uint8(5), 182 Flags: TCPFlags(header.TCPFlagRst | header.TCPFlagAck), 183 WindowSize: Uint16(64240), 184 Checksum: Uint16(0x2e2b), 185 }, 186 want: "&testbench.TCP{" + 187 "SrcPort:34785 " + 188 "DstPort:47767 " + 189 "SeqNum:3452155723 " + 190 "AckNum:2596996163 " + 191 "DataOffset:5 " + 192 "Flags: R A " + 193 "WindowSize:64240 " + 194 "Checksum:11819" + 195 "}", 196 }, 197 { 198 name: "UDP", 199 l: &UDP{ 200 SrcPort: Uint16(34785), 201 DstPort: Uint16(47767), 202 Length: Uint16(12), 203 }, 204 want: "&testbench.UDP{" + 205 "SrcPort:34785 " + 206 "DstPort:47767 " + 207 "Length:12" + 208 "}", 209 }, 210 { 211 name: "IPv4", 212 l: &IPv4{ 213 IHL: Uint8(5), 214 TOS: Uint8(0), 215 TotalLength: Uint16(44), 216 ID: Uint16(0), 217 Flags: Uint8(2), 218 FragmentOffset: Uint16(0), 219 TTL: Uint8(64), 220 Protocol: Uint8(6), 221 Checksum: Uint16(0x2e2b), 222 SrcAddr: Address(tcpip.AddrFrom4Slice([]byte{197, 34, 63, 10})), 223 DstAddr: Address(tcpip.AddrFrom4Slice([]byte{197, 34, 63, 20})), 224 }, 225 want: "&testbench.IPv4{" + 226 "IHL:5 " + 227 "TOS:0 " + 228 "TotalLength:44 " + 229 "ID:0 " + 230 "Flags:2 " + 231 "FragmentOffset:0 " + 232 "TTL:64 " + 233 "Protocol:6 " + 234 "Checksum:11819 " + 235 "SrcAddr:197.34.63.10 " + 236 "DstAddr:197.34.63.20" + 237 "}", 238 }, 239 { 240 name: "Ether", 241 l: &Ether{ 242 SrcAddr: LinkAddress(tcpip.LinkAddress([]byte{0x02, 0x42, 0xc5, 0x22, 0x3f, 0x0a})), 243 DstAddr: LinkAddress(tcpip.LinkAddress([]byte{0x02, 0x42, 0xc5, 0x22, 0x3f, 0x14})), 244 Type: NetworkProtocolNumber(4), 245 }, 246 want: "&testbench.Ether{" + 247 "SrcAddr:02:42:c5:22:3f:0a " + 248 "DstAddr:02:42:c5:22:3f:14 " + 249 "Type:4" + 250 "}", 251 }, 252 { 253 name: "Payload", 254 l: &Payload{ 255 Bytes: []byte("Hooray for packetimpact."), 256 }, 257 want: "&testbench.Payload{Bytes:\n" + 258 "00000000 48 6f 6f 72 61 79 20 66 6f 72 20 70 61 63 6b 65 |Hooray for packe|\n" + 259 "00000010 74 69 6d 70 61 63 74 2e |timpact.|\n" + 260 "}", 261 }, 262 } { 263 t.Run(tt.name, func(t *testing.T) { 264 if got := tt.l.String(); got != tt.want { 265 t.Errorf("%s.String() = %s, want: %s", tt.name, got, tt.want) 266 } 267 }) 268 } 269 } 270 271 func TestConnectionMatch(t *testing.T) { 272 conn := Connection{ 273 layerStates: []layerState{ðerState{}}, 274 } 275 protoNum0 := tcpip.NetworkProtocolNumber(0) 276 protoNum1 := tcpip.NetworkProtocolNumber(1) 277 for _, tt := range []struct { 278 description string 279 override, received Layers 280 wantMatch bool 281 }{ 282 { 283 description: "shorter override", 284 override: []Layer{&Ether{}}, 285 received: []Layer{&Ether{}, &Payload{Bytes: []byte("hello")}}, 286 wantMatch: true, 287 }, 288 { 289 description: "longer override", 290 override: []Layer{&Ether{}, &Payload{Bytes: []byte("hello")}}, 291 received: []Layer{&Ether{}}, 292 wantMatch: false, 293 }, 294 { 295 description: "ether layer mismatch", 296 override: []Layer{&Ether{Type: &protoNum0}}, 297 received: []Layer{&Ether{Type: &protoNum1}}, 298 wantMatch: false, 299 }, 300 { 301 description: "both nil", 302 override: nil, 303 received: nil, 304 wantMatch: false, 305 }, 306 { 307 description: "nil override", 308 override: nil, 309 received: []Layer{&Ether{}}, 310 wantMatch: true, 311 }, 312 } { 313 t.Run(tt.description, func(t *testing.T) { 314 if gotMatch := conn.match(tt.override, tt.received); gotMatch != tt.wantMatch { 315 t.Fatalf("conn.match(%s, %s) = %t, want %t", tt.override, tt.received, gotMatch, tt.wantMatch) 316 } 317 }) 318 } 319 } 320 321 func TestLayersDiff(t *testing.T) { 322 for _, tt := range []struct { 323 x, y Layers 324 want string 325 }{ 326 { 327 Layers{&Ether{Type: NetworkProtocolNumber(12)}, &TCP{DataOffset: Uint8(5), SeqNum: Uint32(5)}}, 328 Layers{&Ether{Type: NetworkProtocolNumber(13)}, &TCP{DataOffset: Uint8(7), SeqNum: Uint32(6)}}, 329 "Ether: Type: 12 13\n" + 330 " TCP: SeqNum: 5 6\n" + 331 " DataOffset: 5 7\n", 332 }, 333 { 334 Layers{&Ether{Type: NetworkProtocolNumber(12)}, &UDP{SrcPort: Uint16(123)}}, 335 Layers{&Ether{Type: NetworkProtocolNumber(13)}, &TCP{DataOffset: Uint8(7), SeqNum: Uint32(6)}}, 336 "Ether: Type: 12 13\n" + 337 "(UDP doesn't match TCP)\n" + 338 " UDP: SrcPort: 123 \n" + 339 " TCP: SeqNum: 6\n" + 340 " DataOffset: 7\n", 341 }, 342 { 343 Layers{&UDP{SrcPort: Uint16(123)}}, 344 Layers{&Ether{Type: NetworkProtocolNumber(13)}, &TCP{DataOffset: Uint8(7), SeqNum: Uint32(6)}}, 345 "(UDP doesn't match Ether)\n" + 346 " UDP: SrcPort: 123 \n" + 347 "Ether: Type: 13\n" + 348 "(missing matches TCP)\n", 349 }, 350 { 351 Layers{nil, &UDP{SrcPort: Uint16(123)}}, 352 Layers{&Ether{Type: NetworkProtocolNumber(13)}, &TCP{DataOffset: Uint8(7), SeqNum: Uint32(6)}}, 353 "(nil matches Ether)\n" + 354 "(UDP doesn't match TCP)\n" + 355 "UDP: SrcPort: 123 \n" + 356 "TCP: SeqNum: 6\n" + 357 " DataOffset: 7\n", 358 }, 359 { 360 Layers{&Ether{Type: NetworkProtocolNumber(13)}, &IPv4{IHL: Uint8(4)}, &TCP{DataOffset: Uint8(7), SeqNum: Uint32(6)}}, 361 Layers{&Ether{Type: NetworkProtocolNumber(13)}, &IPv4{IHL: Uint8(6)}, &TCP{DataOffset: Uint8(7), SeqNum: Uint32(6)}}, 362 "(Ether matches Ether)\n" + 363 "IPv4: IHL: 4 6\n" + 364 "(TCP matches TCP)\n", 365 }, 366 { 367 Layers{&Payload{Bytes: []byte("foo")}}, 368 Layers{&Payload{Bytes: []byte("bar")}}, 369 "Payload: Bytes: [102 111 111] [98 97 114]\n", 370 }, 371 { 372 Layers{&Payload{Bytes: []byte("")}}, 373 Layers{&Payload{}}, 374 "", 375 }, 376 { 377 Layers{&Payload{Bytes: []byte("")}}, 378 Layers{&Payload{Bytes: []byte("")}}, 379 "", 380 }, 381 { 382 Layers{&UDP{}}, 383 Layers{&TCP{}}, 384 "(UDP doesn't match TCP)\n" + 385 "(UDP)\n" + 386 "(TCP)\n", 387 }, 388 } { 389 if got := tt.x.diff(tt.y); got != tt.want { 390 t.Errorf("%s.diff(%s) = %q, want %q", tt.x, tt.y, got, tt.want) 391 } 392 if tt.x.match(tt.y) != (tt.x.diff(tt.y) == "") { 393 t.Errorf("match and diff of %s and %s disagree", tt.x, tt.y) 394 } 395 if tt.y.match(tt.x) != (tt.y.diff(tt.x) == "") { 396 t.Errorf("match and diff of %s and %s disagree", tt.y, tt.x) 397 } 398 } 399 } 400 401 func TestTCPOptions(t *testing.T) { 402 for _, tt := range []struct { 403 description string 404 wantBytes []byte 405 wantLayers Layers 406 }{ 407 { 408 description: "without payload", 409 wantBytes: []byte{ 410 // IPv4 Header 411 0x45, 0x00, 0x00, 0x2c, 0x00, 0x01, 0x00, 0x00, 0x40, 0x06, 412 0xf9, 0x77, 0xc0, 0xa8, 0x00, 0x02, 0xc0, 0xa8, 0x00, 0x01, 413 // TCP Header 414 0x30, 0x39, 0xd4, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 415 0x00, 0x00, 0x60, 0x02, 0x20, 0x00, 0xf5, 0x1c, 0x00, 0x00, 416 // WindowScale Option 417 0x03, 0x03, 0x02, 418 // NOP Option 419 0x00, 420 }, 421 wantLayers: []Layer{ 422 &IPv4{ 423 IHL: Uint8(20), 424 TOS: Uint8(0), 425 TotalLength: Uint16(44), 426 ID: Uint16(1), 427 Flags: Uint8(0), 428 FragmentOffset: Uint16(0), 429 TTL: Uint8(64), 430 Protocol: Uint8(uint8(header.TCPProtocolNumber)), 431 Checksum: Uint16(0xf977), 432 SrcAddr: Address(tcpip.AddrFrom4Slice(net.ParseIP("192.168.0.2").To4())), 433 DstAddr: Address(tcpip.AddrFrom4Slice(net.ParseIP("192.168.0.1").To4())), 434 }, 435 &TCP{ 436 SrcPort: Uint16(12345), 437 DstPort: Uint16(54321), 438 SeqNum: Uint32(0), 439 AckNum: Uint32(0), 440 Flags: TCPFlags(header.TCPFlagSyn), 441 WindowSize: Uint16(8192), 442 Checksum: Uint16(0xf51c), 443 UrgentPointer: Uint16(0), 444 Options: []byte{3, 3, 2, 0}, 445 }, 446 &Payload{Bytes: nil}, 447 }, 448 }, 449 { 450 description: "with payload", 451 wantBytes: []byte{ 452 // IPv4 header 453 0x45, 0x00, 0x00, 0x37, 0x00, 0x01, 0x00, 0x00, 0x40, 0x06, 454 0xf9, 0x6c, 0xc0, 0xa8, 0x00, 0x02, 0xc0, 0xa8, 0x00, 0x01, 455 // TCP header 456 0x30, 0x39, 0xd4, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 457 0x00, 0x00, 0x60, 0x02, 0x20, 0x00, 0xe5, 0x21, 0x00, 0x00, 458 // WindowScale Option 459 0x03, 0x03, 0x02, 460 // NOP Option 461 0x00, 462 // Payload: "Sample Data" 463 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x44, 0x61, 0x74, 0x61, 464 }, 465 wantLayers: []Layer{ 466 &IPv4{ 467 IHL: Uint8(20), 468 TOS: Uint8(0), 469 TotalLength: Uint16(55), 470 ID: Uint16(1), 471 Flags: Uint8(0), 472 FragmentOffset: Uint16(0), 473 TTL: Uint8(64), 474 Protocol: Uint8(uint8(header.TCPProtocolNumber)), 475 Checksum: Uint16(0xf96c), 476 SrcAddr: Address(tcpip.AddrFrom4Slice(net.ParseIP("192.168.0.2").To4())), 477 DstAddr: Address(tcpip.AddrFrom4Slice(net.ParseIP("192.168.0.1").To4())), 478 }, 479 &TCP{ 480 SrcPort: Uint16(12345), 481 DstPort: Uint16(54321), 482 SeqNum: Uint32(0), 483 AckNum: Uint32(0), 484 Flags: TCPFlags(header.TCPFlagSyn), 485 WindowSize: Uint16(8192), 486 Checksum: Uint16(0xe521), 487 UrgentPointer: Uint16(0), 488 Options: []byte{3, 3, 2, 0}, 489 }, 490 &Payload{Bytes: []byte("Sample Data")}, 491 }, 492 }, 493 } { 494 t.Run(tt.description, func(t *testing.T) { 495 layers := parse(parseIPv4, tt.wantBytes) 496 if !layers.match(tt.wantLayers) { 497 t.Fatalf("match failed with diff: %s", layers.diff(tt.wantLayers)) 498 } 499 gotBytes, err := layers.ToBytes() 500 if err != nil { 501 t.Fatalf("ToBytes() failed on %s: %s", &layers, err) 502 } 503 if !bytes.Equal(tt.wantBytes, gotBytes) { 504 t.Fatalf("mismatching bytes, gotBytes: %x, wantBytes: %x", gotBytes, tt.wantBytes) 505 } 506 }) 507 } 508 } 509 510 func TestIPv6ExtHdrOptions(t *testing.T) { 511 for _, tt := range []struct { 512 description string 513 wantBytes []byte 514 wantLayers Layers 515 }{ 516 { 517 description: "IPv6/HopByHop", 518 wantBytes: []byte{ 519 // IPv6 Header 520 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x40, 0x00, 0x00, 521 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 522 0x00, 0x00, 0x00, 0x01, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 523 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0xad, 0xbe, 0xef, 524 // HopByHop Options 525 0x3b, 0x00, 0x05, 0x02, 0x00, 0x00, 0x01, 0x00, 526 }, 527 wantLayers: []Layer{ 528 &IPv6{ 529 SrcAddr: Address(tcpip.AddrFrom16Slice(net.ParseIP("::1"))), 530 DstAddr: Address(tcpip.AddrFrom16Slice(net.ParseIP("fe80::dead:beef"))), 531 }, 532 &IPv6HopByHopOptionsExtHdr{ 533 NextHeader: IPv6ExtHdrIdent(header.IPv6NoNextHeaderIdentifier), 534 Options: []byte{0x05, 0x02, 0x00, 0x00, 0x01, 0x00}, 535 }, 536 &Payload{ 537 Bytes: nil, 538 }, 539 }, 540 }, 541 { 542 description: "IPv6/HopByHop/Payload", 543 wantBytes: []byte{ 544 // IPv6 Header 545 0x60, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x40, 0x00, 0x00, 546 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 547 0x00, 0x00, 0x00, 0x01, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 548 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0xad, 0xbe, 0xef, 549 // HopByHop Options 550 0x3b, 0x00, 0x05, 0x02, 0x00, 0x00, 0x01, 0x00, 551 // Sample Data 552 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x44, 0x61, 0x74, 0x61, 553 }, 554 wantLayers: []Layer{ 555 &IPv6{ 556 SrcAddr: Address(tcpip.AddrFromSlice(net.ParseIP("::1"))), 557 DstAddr: Address(tcpip.AddrFromSlice(net.ParseIP("fe80::dead:beef"))), 558 }, 559 &IPv6HopByHopOptionsExtHdr{ 560 NextHeader: IPv6ExtHdrIdent(header.IPv6NoNextHeaderIdentifier), 561 Options: []byte{0x05, 0x02, 0x00, 0x00, 0x01, 0x00}, 562 }, 563 &Payload{ 564 Bytes: []byte("Sample Data"), 565 }, 566 }, 567 }, 568 { 569 description: "IPv6/HopByHop/Destination/ICMPv6", 570 wantBytes: []byte{ 571 // IPv6 Header 572 0x60, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x40, 0x00, 0x00, 573 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 574 0x00, 0x00, 0x00, 0x01, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 575 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0xad, 0xbe, 0xef, 576 // HopByHop Options 577 0x3c, 0x00, 0x05, 0x02, 0x00, 0x00, 0x01, 0x00, 578 // Destination Options 579 0x3a, 0x00, 0x05, 0x02, 0x00, 0x00, 0x01, 0x00, 580 // ICMPv6 Param Problem 581 0x04, 0x00, 0x5f, 0x98, 0x00, 0x00, 0x00, 0x06, 582 }, 583 wantLayers: []Layer{ 584 &IPv6{ 585 SrcAddr: Address(tcpip.AddrFromSlice(net.ParseIP("::1"))), 586 DstAddr: Address(tcpip.AddrFromSlice(net.ParseIP("fe80::dead:beef"))), 587 }, 588 &IPv6HopByHopOptionsExtHdr{ 589 NextHeader: IPv6ExtHdrIdent(header.IPv6DestinationOptionsExtHdrIdentifier), 590 Options: []byte{0x05, 0x02, 0x00, 0x00, 0x01, 0x00}, 591 }, 592 &IPv6DestinationOptionsExtHdr{ 593 NextHeader: IPv6ExtHdrIdent(header.IPv6ExtensionHeaderIdentifier(header.ICMPv6ProtocolNumber)), 594 Options: []byte{0x05, 0x02, 0x00, 0x00, 0x01, 0x00}, 595 }, 596 &ICMPv6{ 597 Type: ICMPv6Type(header.ICMPv6ParamProblem), 598 Code: ICMPv6Code(header.ICMPv6ErroneousHeader), 599 Checksum: Uint16(0x5f98), 600 Pointer: Uint32(6), 601 }, 602 }, 603 }, 604 { 605 description: "IPv6/HopByHop/Fragment", 606 wantBytes: []byte{ 607 // IPv6 Header 608 0x60, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 609 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 610 0x00, 0x00, 0x00, 0x01, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 611 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0xad, 0xbe, 0xef, 612 // HopByHop Options 613 0x2c, 0x00, 0x05, 0x02, 0x00, 0x00, 0x01, 0x00, 614 // Fragment ExtHdr 615 0x3b, 0x00, 0x03, 0x20, 0x00, 0x00, 0x00, 0x2a, 616 }, 617 wantLayers: []Layer{ 618 &IPv6{ 619 SrcAddr: Address(tcpip.AddrFromSlice(net.ParseIP("::1"))), 620 DstAddr: Address(tcpip.AddrFromSlice(net.ParseIP("fe80::dead:beef"))), 621 }, 622 &IPv6HopByHopOptionsExtHdr{ 623 NextHeader: IPv6ExtHdrIdent(header.IPv6FragmentExtHdrIdentifier), 624 Options: []byte{0x05, 0x02, 0x00, 0x00, 0x01, 0x00}, 625 }, 626 &IPv6FragmentExtHdr{ 627 NextHeader: IPv6ExtHdrIdent(header.IPv6NoNextHeaderIdentifier), 628 FragmentOffset: Uint16(100), 629 MoreFragments: Bool(false), 630 Identification: Uint32(42), 631 }, 632 &Payload{ 633 Bytes: nil, 634 }, 635 }, 636 }, 637 { 638 description: "IPv6/DestOpt/Fragment/Payload", 639 wantBytes: []byte{ 640 // IPv6 Header 641 0x60, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x3c, 0x40, 0x00, 0x00, 642 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 643 0x00, 0x00, 0x00, 0x01, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 644 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0xad, 0xbe, 0xef, 645 // Destination Options 646 0x2c, 0x00, 0x05, 0x02, 0x00, 0x00, 0x01, 0x00, 647 // Fragment ExtHdr 648 0x3b, 0x00, 0x03, 0x21, 0x00, 0x00, 0x00, 0x2a, 649 // Sample Data 650 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x44, 0x61, 0x74, 0x61, 651 }, 652 wantLayers: []Layer{ 653 &IPv6{ 654 SrcAddr: Address(tcpip.AddrFromSlice(net.ParseIP("::1"))), 655 DstAddr: Address(tcpip.AddrFromSlice(net.ParseIP("fe80::dead:beef"))), 656 }, 657 &IPv6DestinationOptionsExtHdr{ 658 NextHeader: IPv6ExtHdrIdent(header.IPv6FragmentExtHdrIdentifier), 659 Options: []byte{0x05, 0x02, 0x00, 0x00, 0x01, 0x00}, 660 }, 661 &IPv6FragmentExtHdr{ 662 NextHeader: IPv6ExtHdrIdent(header.IPv6NoNextHeaderIdentifier), 663 FragmentOffset: Uint16(100), 664 MoreFragments: Bool(true), 665 Identification: Uint32(42), 666 }, 667 &Payload{ 668 Bytes: []byte("Sample Data"), 669 }, 670 }, 671 }, 672 { 673 description: "IPv6/Fragment/Payload", 674 wantBytes: []byte{ 675 // IPv6 Header 676 0x60, 0x00, 0x00, 0x00, 0x00, 0x13, 0x2c, 0x40, 0x00, 0x00, 677 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 678 0x00, 0x00, 0x00, 0x01, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 679 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0xad, 0xbe, 0xef, 680 // Fragment ExtHdr 681 0x3b, 0x00, 0x03, 0x21, 0x00, 0x00, 0x00, 0x2a, 682 // Sample Data 683 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x44, 0x61, 0x74, 0x61, 684 }, 685 wantLayers: []Layer{ 686 &IPv6{ 687 SrcAddr: Address(tcpip.AddrFromSlice(net.ParseIP("::1"))), 688 DstAddr: Address(tcpip.AddrFromSlice(net.ParseIP("fe80::dead:beef"))), 689 }, 690 &IPv6FragmentExtHdr{ 691 NextHeader: IPv6ExtHdrIdent(header.IPv6NoNextHeaderIdentifier), 692 FragmentOffset: Uint16(100), 693 MoreFragments: Bool(true), 694 Identification: Uint32(42), 695 }, 696 &Payload{ 697 Bytes: []byte("Sample Data"), 698 }, 699 }, 700 }, 701 } { 702 t.Run(tt.description, func(t *testing.T) { 703 layers := parse(parseIPv6, tt.wantBytes) 704 if !layers.match(tt.wantLayers) { 705 t.Fatalf("match failed with diff: %s", layers.diff(tt.wantLayers)) 706 } 707 // Make sure we can generate correct next header values and checksums 708 for _, layer := range layers { 709 switch layer := layer.(type) { 710 case *IPv6HopByHopOptionsExtHdr: 711 layer.NextHeader = nil 712 case *IPv6DestinationOptionsExtHdr: 713 layer.NextHeader = nil 714 case *IPv6FragmentExtHdr: 715 layer.NextHeader = nil 716 case *ICMPv6: 717 layer.Checksum = nil 718 } 719 } 720 gotBytes, err := layers.ToBytes() 721 if err != nil { 722 t.Fatalf("ToBytes() failed on %s: %s", &layers, err) 723 } 724 if !bytes.Equal(tt.wantBytes, gotBytes) { 725 t.Fatalf("mismatching bytes, gotBytes: %x, wantBytes: %x", gotBytes, tt.wantBytes) 726 } 727 }) 728 } 729 } 730 731 func TestEthernetPadding(t *testing.T) { 732 packet := []byte{ 733 0x3a, 0xd6, 0x90, 0x36, 0x18, 0xce, 0x64, 0x4f, 0x16, 0x3f, 734 0x5f, 0x0f, 0x08, 0x00, 0x45, 0x00, 0x00, 0x2c, 0xf5, 0x0e, 735 0x00, 0x00, 0x40, 0x06, 0x2d, 0xba, 0xac, 0x00, 0x00, 0x02, 736 0xac, 0x00, 0x00, 0x01, 0x7c, 0x3e, 0xe3, 0x91, 0x2b, 0xe4, 737 0xb0, 0xe7, 0x9a, 0xcb, 0x04, 0x43, 0x60, 0x12, 0x72, 0x00, 738 0xf2, 0x67, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x00, 0x00, 739 } 740 parsed := parse(parseEther, packet) 741 wanted := Layers{ 742 &Ether{ 743 SrcAddr: LinkAddress(tcpip.LinkAddress("\x64\x4f\x16\x3f\x5f\x0f")), 744 DstAddr: LinkAddress(tcpip.LinkAddress("\x3a\xd6\x90\x36\x18\xce")), 745 Type: NetworkProtocolNumber(header.IPv4ProtocolNumber), 746 }, 747 &IPv4{ 748 IHL: Uint8(20), 749 TOS: Uint8(0), 750 TotalLength: Uint16(44), 751 ID: Uint16(0xf50e), 752 Flags: Uint8(0), 753 FragmentOffset: Uint16(0), 754 TTL: Uint8(64), 755 Protocol: Uint8(uint8(header.TCPProtocolNumber)), 756 Checksum: Uint16(0x2dba), 757 SrcAddr: Address(tcpip.AddrFromSlice([]byte("\xac\x00\x00\x02"))), 758 DstAddr: Address(tcpip.AddrFromSlice([]byte("\xac\x00\x00\x01"))), 759 }, 760 &TCP{ 761 SrcPort: Uint16(31806), 762 DstPort: Uint16(58257), 763 SeqNum: Uint32(736407783), 764 AckNum: Uint32(2596996163), 765 DataOffset: Uint8(24), 766 Flags: TCPFlags(header.TCPFlagSyn | header.TCPFlagAck), 767 WindowSize: Uint16(29184), 768 Checksum: Uint16(0xf267), 769 UrgentPointer: Uint16(0), 770 }, 771 &Payload{ 772 Bytes: []byte{}, 773 }, 774 } 775 if !parsed.match(wanted) { 776 t.Fatalf("parse(parseEther, %s) = %s, want %s)", hex.Dump(packet), parsed, wanted) 777 } 778 }