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