You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linux C语言Raw Socket实现TCP握手求标准TCP校验和

Hey there, I’ve been down this raw socket TCP rabbit hole before, so let’s get you sorted with a proper TCP checksum implementation that works with your code.

First off, the big thing to remember: TCP checksums aren’t just calculated over the TCP segment itself—you need to include a pseudo-IP header in the calculation. This is a common pitfall with raw sockets, since the kernel handles this automatically for regular sockets, but when you’re building packets from scratch, you have to do it manually.

Here’s a standard, adaptable implementation:

First, a generic checksum calculation function that works for both the pseudo-header + TCP data combo:

#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>

// Generic 16-bit checksum calculation (used for TCP, IP, etc.)
uint16_t calculate_checksum(uint16_t *data, int len) {
    uint32_t sum = 0;

    // Accumulate all 16-bit chunks
    while (len > 1) {
        sum += *data++;
        len -= 2;
    }

    // Handle odd-length data by padding with a zero byte
    if (len == 1) {
        sum += *(uint8_t *)data;
    }

    // Fold 32-bit sum into 16 bits by adding high and low halves
    while (sum >> 16) {
        sum = (sum & 0xFFFF) + (sum >> 16);
    }

    // Return the one's complement of the sum
    return (uint16_t)~sum;
}

Next, a helper function specifically for TCP checksums that builds the pseudo-header and combines it with your TCP segment:

// Pseudo-IP header structure required for TCP checksum calculation
struct pseudo_header {
    uint32_t src_ip;    // Source IP (network byte order)
    uint32_t dest_ip;   // Destination IP (network byte order)
    uint8_t reserved;   // Must be 0
    uint8_t protocol;   // Protocol (TCP = 6)
    uint16_t tcp_len;   // Length of TCP segment (header + payload, network byte order)
};

// Calculate TCP checksum using the IP header, TCP header, and payload
uint16_t tcp_checksum(struct iphdr *ip_header, struct tcphdr *tcp_header, uint8_t *payload, int payload_len) {
    int tcp_total_len = (tcp_header->doff * 4) + payload_len;
    int buffer_size = sizeof(struct pseudo_header) + tcp_total_len;
    uint8_t *buffer = malloc(buffer_size);
    if (!buffer) return 0;

    // Populate the pseudo-header
    struct pseudo_header *pseudo = (struct pseudo_header *)buffer;
    pseudo->src_ip = ip_header->saddr;
    pseudo->dest_ip = ip_header->daddr;
    pseudo->reserved = 0;
    pseudo->protocol = IPPROTO_TCP;
    pseudo->tcp_len = htons(tcp_total_len);

    // Copy TCP header and payload into the buffer
    memcpy(buffer + sizeof(struct pseudo_header), tcp_header, tcp_header->doff * 4);
    memcpy(buffer + sizeof(struct pseudo_header) + (tcp_header->doff * 4), payload, payload_len);

    // Zero out the TCP checksum field before calculation (required by spec)
    ((struct tcphdr *)(buffer + sizeof(struct pseudo_header)))->check = 0;

    // Calculate and return the checksum
    uint16_t checksum = calculate_checksum((uint16_t *)buffer, buffer_size);
    free(buffer);
    return checksum;
}

How to use this with your code:

  1. After you construct your struct iphdr (IP header) and struct tcphdr (TCP header) (and any payload data), call tcp_checksum() with these values.
  2. Assign the returned checksum to tcp_header->check (no need to convert to network byte order—the function already handles that correctly).
  3. Make sure your IP header’s saddr (source IP) is set to the exact IP you want the server to reply to (in network byte order, e.g., via inet_pton()).
  4. Double-check that tcp_header->doff is set correctly: it’s the length of the TCP header in 32-bit words. For a standard 20-byte TCP header, this should be 5.

Quick sanity checks:

  • If you’re letting the kernel handle the IP header, you’ll need to adjust the pseudo-header to match the source IP the kernel uses (but since you’re specifying a source IP manually, you should be constructing the IP header yourself with the IP_HDRINCL socket option enabled).
  • Always zero out the TCP checksum field before calculating—this is required by the TCP spec, and failing to do so will result in invalid checksums.

This implementation should work seamlessly with raw socket code that builds TCP SYN packets (or any TCP segment) from scratch. It’s compliant with RFC 793, so servers should validate the checksum correctly and send replies to your specified source IP.

内容的提问来源于stack exchange,提问作者T. Graim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:39:35