github.com/MerlinKodo/gvisor@v0.0.0-20231110090155-957f62ecf90e/pkg/tcpip/header/tcp.go (about) 1 // Copyright 2018 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 header 16 17 import ( 18 "encoding/binary" 19 20 "github.com/MerlinKodo/gvisor/pkg/tcpip" 21 "github.com/MerlinKodo/gvisor/pkg/tcpip/checksum" 22 "github.com/MerlinKodo/gvisor/pkg/tcpip/seqnum" 23 "github.com/google/btree" 24 ) 25 26 // These constants are the offsets of the respective fields in the TCP header. 27 const ( 28 TCPSrcPortOffset = 0 29 TCPDstPortOffset = 2 30 TCPSeqNumOffset = 4 31 TCPAckNumOffset = 8 32 TCPDataOffset = 12 33 TCPFlagsOffset = 13 34 TCPWinSizeOffset = 14 35 TCPChecksumOffset = 16 36 TCPUrgentPtrOffset = 18 37 ) 38 39 const ( 40 // MaxWndScale is maximum allowed window scaling, as described in 41 // RFC 1323, section 2.3, page 11. 42 MaxWndScale = 14 43 44 // TCPMaxSACKBlocks is the maximum number of SACK blocks that can 45 // be encoded in a TCP option field. 46 TCPMaxSACKBlocks = 4 47 ) 48 49 // TCPFlags is the dedicated type for TCP flags. 50 type TCPFlags uint8 51 52 // Intersects returns true iff there are flags common to both f and o. 53 func (f TCPFlags) Intersects(o TCPFlags) bool { 54 return f&o != 0 55 } 56 57 // Contains returns true iff all the flags in o are contained within f. 58 func (f TCPFlags) Contains(o TCPFlags) bool { 59 return f&o == o 60 } 61 62 // String implements Stringer.String. 63 func (f TCPFlags) String() string { 64 flagsStr := []byte("FSRPAUEC") 65 for i := range flagsStr { 66 if f&(1<<uint(i)) == 0 { 67 flagsStr[i] = ' ' 68 } 69 } 70 return string(flagsStr) 71 } 72 73 // Flags that may be set in a TCP segment. 74 const ( 75 TCPFlagFin TCPFlags = 1 << iota 76 TCPFlagSyn 77 TCPFlagRst 78 TCPFlagPsh 79 TCPFlagAck 80 TCPFlagUrg 81 TCPFlagEce 82 TCPFlagCwr 83 ) 84 85 // Options that may be present in a TCP segment. 86 const ( 87 TCPOptionEOL = 0 88 TCPOptionNOP = 1 89 TCPOptionMSS = 2 90 TCPOptionWS = 3 91 TCPOptionTS = 8 92 TCPOptionSACKPermitted = 4 93 TCPOptionSACK = 5 94 ) 95 96 // Option Lengths. 97 const ( 98 TCPOptionMSSLength = 4 99 TCPOptionTSLength = 10 100 TCPOptionWSLength = 3 101 TCPOptionSackPermittedLength = 2 102 ) 103 104 // TCPFields contains the fields of a TCP packet. It is used to describe the 105 // fields of a packet that needs to be encoded. 106 type TCPFields struct { 107 // SrcPort is the "source port" field of a TCP packet. 108 SrcPort uint16 109 110 // DstPort is the "destination port" field of a TCP packet. 111 DstPort uint16 112 113 // SeqNum is the "sequence number" field of a TCP packet. 114 SeqNum uint32 115 116 // AckNum is the "acknowledgement number" field of a TCP packet. 117 AckNum uint32 118 119 // DataOffset is the "data offset" field of a TCP packet. It is the length of 120 // the TCP header in bytes. 121 DataOffset uint8 122 123 // Flags is the "flags" field of a TCP packet. 124 Flags TCPFlags 125 126 // WindowSize is the "window size" field of a TCP packet. 127 WindowSize uint16 128 129 // Checksum is the "checksum" field of a TCP packet. 130 Checksum uint16 131 132 // UrgentPointer is the "urgent pointer" field of a TCP packet. 133 UrgentPointer uint16 134 } 135 136 // TCPSynOptions is used to return the parsed TCP Options in a syn 137 // segment. 138 // 139 // +stateify savable 140 type TCPSynOptions struct { 141 // MSS is the maximum segment size provided by the peer in the SYN. 142 MSS uint16 143 144 // WS is the window scale option provided by the peer in the SYN. 145 // 146 // Set to -1 if no window scale option was provided. 147 WS int 148 149 // TS is true if the timestamp option was provided in the syn/syn-ack. 150 TS bool 151 152 // TSVal is the value of the TSVal field in the timestamp option. 153 TSVal uint32 154 155 // TSEcr is the value of the TSEcr field in the timestamp option. 156 TSEcr uint32 157 158 // SACKPermitted is true if the SACK option was provided in the SYN/SYN-ACK. 159 SACKPermitted bool 160 161 // Flags if specified are set on the outgoing SYN. The SYN flag is 162 // always set. 163 Flags TCPFlags 164 } 165 166 // SACKBlock represents a single contiguous SACK block. 167 // 168 // +stateify savable 169 type SACKBlock struct { 170 // Start indicates the lowest sequence number in the block. 171 Start seqnum.Value 172 173 // End indicates the sequence number immediately following the last 174 // sequence number of this block. 175 End seqnum.Value 176 } 177 178 // Less returns true if r.Start < b.Start. 179 func (r SACKBlock) Less(b btree.Item) bool { 180 return r.Start.LessThan(b.(SACKBlock).Start) 181 } 182 183 // Contains returns true if b is completely contained in r. 184 func (r SACKBlock) Contains(b SACKBlock) bool { 185 return r.Start.LessThanEq(b.Start) && b.End.LessThanEq(r.End) 186 } 187 188 // TCPOptions are used to parse and cache the TCP segment options for a non 189 // syn/syn-ack segment. 190 // 191 // +stateify savable 192 type TCPOptions struct { 193 // TS is true if the TimeStamp option is enabled. 194 TS bool 195 196 // TSVal is the value in the TSVal field of the segment. 197 TSVal uint32 198 199 // TSEcr is the value in the TSEcr field of the segment. 200 TSEcr uint32 201 202 // SACKBlocks are the SACK blocks specified in the segment. 203 SACKBlocks []SACKBlock 204 } 205 206 // TCP represents a TCP header stored in a byte array. 207 type TCP []byte 208 209 const ( 210 // TCPMinimumSize is the minimum size of a valid TCP packet. 211 TCPMinimumSize = 20 212 213 // TCPOptionsMaximumSize is the maximum size of TCP options. 214 TCPOptionsMaximumSize = 40 215 216 // TCPHeaderMaximumSize is the maximum header size of a TCP packet. 217 TCPHeaderMaximumSize = TCPMinimumSize + TCPOptionsMaximumSize 218 219 // TCPProtocolNumber is TCP's transport protocol number. 220 TCPProtocolNumber tcpip.TransportProtocolNumber = 6 221 222 // TCPMinimumMSS is the minimum acceptable value for MSS. This is the 223 // same as the value TCP_MIN_MSS defined net/tcp.h. 224 TCPMinimumMSS = IPv4MaximumHeaderSize + TCPHeaderMaximumSize + MinIPFragmentPayloadSize - IPv4MinimumSize - TCPMinimumSize 225 226 // TCPMinimumSendMSS is the minimum value for MSS in a sender. This is the 227 // same as the value TCP_MIN_SND_MSS in net/tcp.h. 228 TCPMinimumSendMSS = TCPOptionsMaximumSize + MinIPFragmentPayloadSize 229 230 // TCPMaximumMSS is the maximum acceptable value for MSS. 231 TCPMaximumMSS = 0xffff 232 233 // TCPDefaultMSS is the MSS value that should be used if an MSS option 234 // is not received from the peer. It's also the value returned by 235 // TCP_MAXSEG option for a socket in an unconnected state. 236 // 237 // Per RFC 1122, page 85: "If an MSS option is not received at 238 // connection setup, TCP MUST assume a default send MSS of 536." 239 TCPDefaultMSS = 536 240 ) 241 242 // SourcePort returns the "source port" field of the TCP header. 243 func (b TCP) SourcePort() uint16 { 244 return binary.BigEndian.Uint16(b[TCPSrcPortOffset:]) 245 } 246 247 // DestinationPort returns the "destination port" field of the TCP header. 248 func (b TCP) DestinationPort() uint16 { 249 return binary.BigEndian.Uint16(b[TCPDstPortOffset:]) 250 } 251 252 // SequenceNumber returns the "sequence number" field of the TCP header. 253 func (b TCP) SequenceNumber() uint32 { 254 return binary.BigEndian.Uint32(b[TCPSeqNumOffset:]) 255 } 256 257 // AckNumber returns the "ack number" field of the TCP header. 258 func (b TCP) AckNumber() uint32 { 259 return binary.BigEndian.Uint32(b[TCPAckNumOffset:]) 260 } 261 262 // DataOffset returns the "data offset" field of the TCP header. The return 263 // value is the length of the TCP header in bytes. 264 func (b TCP) DataOffset() uint8 { 265 return (b[TCPDataOffset] >> 4) * 4 266 } 267 268 // Payload returns the data in the TCP packet. 269 func (b TCP) Payload() []byte { 270 return b[b.DataOffset():] 271 } 272 273 // Flags returns the flags field of the TCP header. 274 func (b TCP) Flags() TCPFlags { 275 return TCPFlags(b[TCPFlagsOffset]) 276 } 277 278 // WindowSize returns the "window size" field of the TCP header. 279 func (b TCP) WindowSize() uint16 { 280 return binary.BigEndian.Uint16(b[TCPWinSizeOffset:]) 281 } 282 283 // Checksum returns the "checksum" field of the TCP header. 284 func (b TCP) Checksum() uint16 { 285 return binary.BigEndian.Uint16(b[TCPChecksumOffset:]) 286 } 287 288 // UrgentPointer returns the "urgent pointer" field of the TCP header. 289 func (b TCP) UrgentPointer() uint16 { 290 return binary.BigEndian.Uint16(b[TCPUrgentPtrOffset:]) 291 } 292 293 // SetSourcePort sets the "source port" field of the TCP header. 294 func (b TCP) SetSourcePort(port uint16) { 295 binary.BigEndian.PutUint16(b[TCPSrcPortOffset:], port) 296 } 297 298 // SetDestinationPort sets the "destination port" field of the TCP header. 299 func (b TCP) SetDestinationPort(port uint16) { 300 binary.BigEndian.PutUint16(b[TCPDstPortOffset:], port) 301 } 302 303 // SetChecksum sets the checksum field of the TCP header. 304 func (b TCP) SetChecksum(xsum uint16) { 305 checksum.Put(b[TCPChecksumOffset:], xsum) 306 } 307 308 // SetDataOffset sets the data offset field of the TCP header. headerLen should 309 // be the length of the TCP header in bytes. 310 func (b TCP) SetDataOffset(headerLen uint8) { 311 b[TCPDataOffset] = (headerLen / 4) << 4 312 } 313 314 // SetSequenceNumber sets the sequence number field of the TCP header. 315 func (b TCP) SetSequenceNumber(seqNum uint32) { 316 binary.BigEndian.PutUint32(b[TCPSeqNumOffset:], seqNum) 317 } 318 319 // SetAckNumber sets the ack number field of the TCP header. 320 func (b TCP) SetAckNumber(ackNum uint32) { 321 binary.BigEndian.PutUint32(b[TCPAckNumOffset:], ackNum) 322 } 323 324 // SetFlags sets the flags field of the TCP header. 325 func (b TCP) SetFlags(flags uint8) { 326 b[TCPFlagsOffset] = flags 327 } 328 329 // SetWindowSize sets the window size field of the TCP header. 330 func (b TCP) SetWindowSize(rcvwnd uint16) { 331 binary.BigEndian.PutUint16(b[TCPWinSizeOffset:], rcvwnd) 332 } 333 334 // SetUrgentPointer sets the window size field of the TCP header. 335 func (b TCP) SetUrgentPointer(urgentPointer uint16) { 336 binary.BigEndian.PutUint16(b[TCPUrgentPtrOffset:], urgentPointer) 337 } 338 339 // CalculateChecksum calculates the checksum of the TCP segment. 340 // partialChecksum is the checksum of the network-layer pseudo-header 341 // and the checksum of the segment data. 342 func (b TCP) CalculateChecksum(partialChecksum uint16) uint16 { 343 // Calculate the rest of the checksum. 344 return checksum.Checksum(b[:b.DataOffset()], partialChecksum) 345 } 346 347 // IsChecksumValid returns true iff the TCP header's checksum is valid. 348 func (b TCP) IsChecksumValid(src, dst tcpip.Address, payloadChecksum, payloadLength uint16) bool { 349 xsum := PseudoHeaderChecksum(TCPProtocolNumber, src, dst, uint16(b.DataOffset())+payloadLength) 350 xsum = checksum.Combine(xsum, payloadChecksum) 351 return b.CalculateChecksum(xsum) == 0xffff 352 } 353 354 // Options returns a slice that holds the unparsed TCP options in the segment. 355 func (b TCP) Options() []byte { 356 return b[TCPMinimumSize:b.DataOffset()] 357 } 358 359 // ParsedOptions returns a TCPOptions structure which parses and caches the TCP 360 // option values in the TCP segment. NOTE: Invoking this function repeatedly is 361 // expensive as it reparses the options on each invocation. 362 func (b TCP) ParsedOptions() TCPOptions { 363 return ParseTCPOptions(b.Options()) 364 } 365 366 func (b TCP) encodeSubset(seq, ack uint32, flags TCPFlags, rcvwnd uint16) { 367 binary.BigEndian.PutUint32(b[TCPSeqNumOffset:], seq) 368 binary.BigEndian.PutUint32(b[TCPAckNumOffset:], ack) 369 b[TCPFlagsOffset] = uint8(flags) 370 binary.BigEndian.PutUint16(b[TCPWinSizeOffset:], rcvwnd) 371 } 372 373 // Encode encodes all the fields of the TCP header. 374 func (b TCP) Encode(t *TCPFields) { 375 b.encodeSubset(t.SeqNum, t.AckNum, t.Flags, t.WindowSize) 376 b.SetSourcePort(t.SrcPort) 377 b.SetDestinationPort(t.DstPort) 378 b.SetDataOffset(t.DataOffset) 379 b.SetChecksum(t.Checksum) 380 b.SetUrgentPointer(t.UrgentPointer) 381 } 382 383 // EncodePartial updates a subset of the fields of the TCP header. It is useful 384 // in cases when similar segments are produced. 385 func (b TCP) EncodePartial(partialChecksum, length uint16, seqnum, acknum uint32, flags TCPFlags, rcvwnd uint16) { 386 // Add the total length and "flags" field contributions to the checksum. 387 // We don't use the flags field directly from the header because it's a 388 // one-byte field with an odd offset, so it would be accounted for 389 // incorrectly by the Checksum routine. 390 tmp := make([]byte, 4) 391 binary.BigEndian.PutUint16(tmp, length) 392 binary.BigEndian.PutUint16(tmp[2:], uint16(flags)) 393 xsum := checksum.Checksum(tmp, partialChecksum) 394 395 // Encode the passed-in fields. 396 b.encodeSubset(seqnum, acknum, flags, rcvwnd) 397 398 // Add the contributions of the passed-in fields to the checksum. 399 xsum = checksum.Checksum(b[TCPSeqNumOffset:TCPSeqNumOffset+8], xsum) 400 xsum = checksum.Checksum(b[TCPWinSizeOffset:TCPWinSizeOffset+2], xsum) 401 402 // Encode the checksum. 403 b.SetChecksum(^xsum) 404 } 405 406 // SetSourcePortWithChecksumUpdate implements ChecksummableTransport. 407 func (b TCP) SetSourcePortWithChecksumUpdate(new uint16) { 408 old := b.SourcePort() 409 b.SetSourcePort(new) 410 b.SetChecksum(^checksumUpdate2ByteAlignedUint16(^b.Checksum(), old, new)) 411 } 412 413 // SetDestinationPortWithChecksumUpdate implements ChecksummableTransport. 414 func (b TCP) SetDestinationPortWithChecksumUpdate(new uint16) { 415 old := b.DestinationPort() 416 b.SetDestinationPort(new) 417 b.SetChecksum(^checksumUpdate2ByteAlignedUint16(^b.Checksum(), old, new)) 418 } 419 420 // UpdateChecksumPseudoHeaderAddress implements ChecksummableTransport. 421 func (b TCP) UpdateChecksumPseudoHeaderAddress(old, new tcpip.Address, fullChecksum bool) { 422 xsum := b.Checksum() 423 if fullChecksum { 424 xsum = ^xsum 425 } 426 427 xsum = checksumUpdate2ByteAlignedAddress(xsum, old, new) 428 if fullChecksum { 429 xsum = ^xsum 430 } 431 432 b.SetChecksum(xsum) 433 } 434 435 // ParseSynOptions parses the options received in a SYN segment and returns the 436 // relevant ones. opts should point to the option part of the TCP header. 437 func ParseSynOptions(opts []byte, isAck bool) TCPSynOptions { 438 limit := len(opts) 439 440 synOpts := TCPSynOptions{ 441 // Per RFC 1122, page 85: "If an MSS option is not received at 442 // connection setup, TCP MUST assume a default send MSS of 536." 443 MSS: TCPDefaultMSS, 444 // If no window scale option is specified, WS in options is 445 // returned as -1; this is because the absence of the option 446 // indicates that the we cannot use window scaling on the 447 // receive end either. 448 WS: -1, 449 } 450 451 for i := 0; i < limit; { 452 switch opts[i] { 453 case TCPOptionEOL: 454 i = limit 455 case TCPOptionNOP: 456 i++ 457 case TCPOptionMSS: 458 if i+4 > limit || opts[i+1] != 4 { 459 return synOpts 460 } 461 mss := uint16(opts[i+2])<<8 | uint16(opts[i+3]) 462 if mss == 0 { 463 return synOpts 464 } 465 synOpts.MSS = mss 466 if mss < TCPMinimumSendMSS { 467 synOpts.MSS = TCPMinimumSendMSS 468 } 469 i += 4 470 471 case TCPOptionWS: 472 if i+3 > limit || opts[i+1] != 3 { 473 return synOpts 474 } 475 ws := int(opts[i+2]) 476 if ws > MaxWndScale { 477 ws = MaxWndScale 478 } 479 synOpts.WS = ws 480 i += 3 481 482 case TCPOptionTS: 483 if i+10 > limit || opts[i+1] != 10 { 484 return synOpts 485 } 486 synOpts.TSVal = binary.BigEndian.Uint32(opts[i+2:]) 487 if isAck { 488 // If the segment is a SYN-ACK then store the Timestamp Echo Reply 489 // in the segment. 490 synOpts.TSEcr = binary.BigEndian.Uint32(opts[i+6:]) 491 } 492 synOpts.TS = true 493 i += 10 494 case TCPOptionSACKPermitted: 495 if i+2 > limit || opts[i+1] != 2 { 496 return synOpts 497 } 498 synOpts.SACKPermitted = true 499 i += 2 500 501 default: 502 // We don't recognize this option, just skip over it. 503 if i+2 > limit { 504 return synOpts 505 } 506 l := int(opts[i+1]) 507 // If the length is incorrect or if l+i overflows the 508 // total options length then return false. 509 if l < 2 || i+l > limit { 510 return synOpts 511 } 512 i += l 513 } 514 } 515 516 return synOpts 517 } 518 519 // ParseTCPOptions extracts and stores all known options in the provided byte 520 // slice in a TCPOptions structure. 521 func ParseTCPOptions(b []byte) TCPOptions { 522 opts := TCPOptions{} 523 limit := len(b) 524 for i := 0; i < limit; { 525 switch b[i] { 526 case TCPOptionEOL: 527 i = limit 528 case TCPOptionNOP: 529 i++ 530 case TCPOptionTS: 531 if i+10 > limit || (b[i+1] != 10) { 532 return opts 533 } 534 opts.TS = true 535 opts.TSVal = binary.BigEndian.Uint32(b[i+2:]) 536 opts.TSEcr = binary.BigEndian.Uint32(b[i+6:]) 537 i += 10 538 case TCPOptionSACK: 539 if i+2 > limit { 540 // Malformed SACK block, just return and stop parsing. 541 return opts 542 } 543 sackOptionLen := int(b[i+1]) 544 if i+sackOptionLen > limit || (sackOptionLen-2)%8 != 0 { 545 // Malformed SACK block, just return and stop parsing. 546 return opts 547 } 548 numBlocks := (sackOptionLen - 2) / 8 549 opts.SACKBlocks = []SACKBlock{} 550 for j := 0; j < numBlocks; j++ { 551 start := binary.BigEndian.Uint32(b[i+2+j*8:]) 552 end := binary.BigEndian.Uint32(b[i+2+j*8+4:]) 553 opts.SACKBlocks = append(opts.SACKBlocks, SACKBlock{ 554 Start: seqnum.Value(start), 555 End: seqnum.Value(end), 556 }) 557 } 558 i += sackOptionLen 559 default: 560 // We don't recognize this option, just skip over it. 561 if i+2 > limit { 562 return opts 563 } 564 l := int(b[i+1]) 565 // If the length is incorrect or if l+i overflows the 566 // total options length then return false. 567 if l < 2 || i+l > limit { 568 return opts 569 } 570 i += l 571 } 572 } 573 return opts 574 } 575 576 // EncodeMSSOption encodes the MSS TCP option with the provided MSS values in 577 // the supplied buffer. If the provided buffer is not large enough then it just 578 // returns without encoding anything. It returns the number of bytes written to 579 // the provided buffer. 580 func EncodeMSSOption(mss uint32, b []byte) int { 581 if len(b) < TCPOptionMSSLength { 582 return 0 583 } 584 b[0], b[1], b[2], b[3] = TCPOptionMSS, TCPOptionMSSLength, byte(mss>>8), byte(mss) 585 return TCPOptionMSSLength 586 } 587 588 // EncodeWSOption encodes the WS TCP option with the WS value in the 589 // provided buffer. If the provided buffer is not large enough then it just 590 // returns without encoding anything. It returns the number of bytes written to 591 // the provided buffer. 592 func EncodeWSOption(ws int, b []byte) int { 593 if len(b) < TCPOptionWSLength { 594 return 0 595 } 596 b[0], b[1], b[2] = TCPOptionWS, TCPOptionWSLength, uint8(ws) 597 return int(b[1]) 598 } 599 600 // EncodeTSOption encodes the provided tsVal and tsEcr values as a TCP timestamp 601 // option into the provided buffer. If the buffer is smaller than expected it 602 // just returns without encoding anything. It returns the number of bytes 603 // written to the provided buffer. 604 func EncodeTSOption(tsVal, tsEcr uint32, b []byte) int { 605 if len(b) < TCPOptionTSLength { 606 return 0 607 } 608 b[0], b[1] = TCPOptionTS, TCPOptionTSLength 609 binary.BigEndian.PutUint32(b[2:], tsVal) 610 binary.BigEndian.PutUint32(b[6:], tsEcr) 611 return int(b[1]) 612 } 613 614 // EncodeSACKPermittedOption encodes a SACKPermitted option into the provided 615 // buffer. If the buffer is smaller than required it just returns without 616 // encoding anything. It returns the number of bytes written to the provided 617 // buffer. 618 func EncodeSACKPermittedOption(b []byte) int { 619 if len(b) < TCPOptionSackPermittedLength { 620 return 0 621 } 622 623 b[0], b[1] = TCPOptionSACKPermitted, TCPOptionSackPermittedLength 624 return int(b[1]) 625 } 626 627 // EncodeSACKBlocks encodes the provided SACK blocks as a TCP SACK option block 628 // in the provided slice. It tries to fit in as many blocks as possible based on 629 // number of bytes available in the provided buffer. It returns the number of 630 // bytes written to the provided buffer. 631 func EncodeSACKBlocks(sackBlocks []SACKBlock, b []byte) int { 632 if len(sackBlocks) == 0 { 633 return 0 634 } 635 l := len(sackBlocks) 636 if l > TCPMaxSACKBlocks { 637 l = TCPMaxSACKBlocks 638 } 639 if ll := (len(b) - 2) / 8; ll < l { 640 l = ll 641 } 642 if l == 0 { 643 // There is not enough space in the provided buffer to add 644 // any SACK blocks. 645 return 0 646 } 647 b[0] = TCPOptionSACK 648 b[1] = byte(l*8 + 2) 649 for i := 0; i < l; i++ { 650 binary.BigEndian.PutUint32(b[i*8+2:], uint32(sackBlocks[i].Start)) 651 binary.BigEndian.PutUint32(b[i*8+6:], uint32(sackBlocks[i].End)) 652 } 653 return int(b[1]) 654 } 655 656 // EncodeNOP adds an explicit NOP to the option list. 657 func EncodeNOP(b []byte) int { 658 if len(b) == 0 { 659 return 0 660 } 661 b[0] = TCPOptionNOP 662 return 1 663 } 664 665 // AddTCPOptionPadding adds the required number of TCPOptionNOP to quad align 666 // the option buffer. It adds padding bytes after the offset specified and 667 // returns the number of padding bytes added. The passed in options slice 668 // must have space for the padding bytes. 669 func AddTCPOptionPadding(options []byte, offset int) int { 670 paddingToAdd := -offset & 3 671 // Now add any padding bytes that might be required to quad align the 672 // options. 673 for i := offset; i < offset+paddingToAdd; i++ { 674 options[i] = TCPOptionNOP 675 } 676 return paddingToAdd 677 } 678 679 // Acceptable checks if a segment that starts at segSeq and has length segLen is 680 // "acceptable" for arriving in a receive window that starts at rcvNxt and ends 681 // before rcvAcc, according to the table on page 26 and 69 of RFC 793. 682 func Acceptable(segSeq seqnum.Value, segLen seqnum.Size, rcvNxt, rcvAcc seqnum.Value) bool { 683 if rcvNxt == rcvAcc { 684 return segLen == 0 && segSeq == rcvNxt 685 } 686 if segLen == 0 { 687 // rcvWnd is incremented by 1 because that is Linux's behavior despite the 688 // RFC. 689 return segSeq.InRange(rcvNxt, rcvAcc.Add(1)) 690 } 691 // Page 70 of RFC 793 allows packets that can be made "acceptable" by trimming 692 // the payload, so we'll accept any payload that overlaps the receieve window. 693 // segSeq < rcvAcc is more correct according to RFC, however, Linux does it 694 // differently, it uses segSeq <= rcvAcc, we'd want to keep the same behavior 695 // as Linux. 696 return rcvNxt.LessThan(segSeq.Add(segLen)) && segSeq.LessThanEq(rcvAcc) 697 } 698 699 // TCPValid returns true if the pkt has a valid TCP header. It checks whether: 700 // - The data offset is too small. 701 // - The data offset is too large. 702 // - The checksum is invalid. 703 // 704 // TCPValid corresponds to net/netfilter/nf_conntrack_proto_tcp.c:tcp_error. 705 func TCPValid(hdr TCP, payloadChecksum func() uint16, payloadSize uint16, srcAddr, dstAddr tcpip.Address, skipChecksumValidation bool) (csum uint16, csumValid, ok bool) { 706 if offset := int(hdr.DataOffset()); offset < TCPMinimumSize || offset > len(hdr) { 707 return 708 } 709 710 if skipChecksumValidation { 711 csumValid = true 712 } else { 713 csum = hdr.Checksum() 714 csumValid = hdr.IsChecksumValid(srcAddr, dstAddr, payloadChecksum(), payloadSize) 715 } 716 return csum, csumValid, true 717 }