TCP checksum

计算 TCP 首部中使用的校验和

  • TCP checksum is a 16-bit field in TCP header used for error detection
  • Same as IP checksum,
    TCP checksum is the 16-bit one’s complement of the one’s
    complement sum of all 16-bit words in the computation data.
  • Checksum 图:
  • TCP checksum computing includes:
    • UDP 数据报和 TCP 段中使用的校验和的计算都包含一个 12 字节长的伪首部.
      12 bytes TCP 伪首部 (12 bytes TCP pseudo header,
      from the IP header and computed), includes:
    • ipHdr srcIP 4 bytes
    • ipHdr dstIP 4 bytes
    • 1 reserved byte: 0x00
    • 1 byte protocol: from ipHdr: 0x06 for TCP
    • 2 byte computed TCP length
    • TCP “Pseudo Header” For Checksum Calculation 图:
    • Original TCP segment(length: is above TCP length), might+ padding,
      includes:
    • TCP header
    • TCP data, includes:
      • TCP data
      • Padded as needed with zero bytes at the end to make a multiple
        of two bytes

TCP “Pseudo Header” For Checksum Calculation

Field Name Bytes Description
Source Address 4 The 32-bit IP address of the originator of the datagram, taken from the IP header
Destination Address 4 The 32-bit IP address of the intended recipient of the datagram, also from the IP header
Reserved 1 8 bits of zeroes
Protocol 1 The Protocol field from the IP header. This indicates what higher-layer protocol is carried in the IP datagram. Of course, we already know what this protocol is, it’s TCP! So, this field will normally have the value 6
TCP Length 2 The length of the TCP segment, including both header and data. Note that this is not a specific field in the TCP header; it is computed
/**
 * 计算 TCP 首部中使用的校验和
 * @param cleanChecksum true to cleanup original checksum before compute
 * @param ipHdr IP首部
 * @return in network byte order
 */
uint16_t computeChecksum(
    bool const cleanChecksum, IpHdr const* const ipHdr) const
{
    // get computed TCP length, also is original TCP segment length
    size_t const protocolSize = ipHdr->computeProtocolSize();
    size_t const n = 12 + protocolSize;
    uint8_t data[n];
    // ipHdr srcIP
    ::memcpy(data, &(ipHdr->sourceIpAddress), 4);
    // ipHdr dstIP
    ::memcpy(data + 4, &(ipHdr->destinationIpAddress), 4);
    // reserved
    data[8] = 0x00;
    // protocol
    data[9] = ipHdr->protocol;
    // computed TCP length
    data[10] = (protocolSize & 0xff00) >> 8;
    data[11] = protocolSize & 0xff;
    // original TCP segment
    tcphdr* const tcpHdr = reinterpret_cast<tcphdr*>(data + 12);
    ::memcpy(tcpHdr, this->tcpHdr, protocolSize);
    // cleanup original checksum when need
    if (cleanChecksum) {
        tcpHdr->check = 0;
    }
    // compute
    return ethpacket::ComputeChecksum(
        reinterpret_cast<uint16_t const*>(data), n);
}