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

基于Raw Socket的C语言TCPDump捕获数据包克隆实现需求

Cloning TCPDump Captured Packets with Raw Sockets in C

Got it, let's walk through exactly how to clone those TCPDump-captured packets using raw sockets in C—we'll be directly manipulating the IP and TCP headers via the iph-> and tcph-> pointers like you mentioned.

Core Overview

Raw sockets let us bypass the OS's normal network stack and craft custom IP/TCP packets from scratch. Using iph-> (pointer to IP header) and tcph-> (pointer to TCP header) lets us directly set fields that match the packets you captured with TCPDump, like source/dest IPs, ports, acknowledgment numbers, window sizes, and TCP options.

Step-by-Step Implementation

1. Open a Raw Socket

First, we need a raw socket that lets us handle TCP packets. We'll also set the IP_HDRINCL option so we can construct our own IP header (instead of letting the OS do it).

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>

int main() {
    // Create raw socket for TCP
    int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
    if (sockfd < 0) {
        perror("Failed to create raw socket");
        exit(EXIT_FAILURE);
    }

    // Set option to include our own IP header
    int optval = 1;
    if (setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &optval, sizeof(optval)) < 0) {
        perror("Failed to set IP_HDRINCL option");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

2. Define Buffer & Header Pointers

We'll use a buffer to hold our entire packet (IP header + TCP header + options). Then we'll cast parts of the buffer to struct iphdr* and struct tcphdr* to manipulate the headers.

// Buffer to hold our crafted packet
    char buffer[4096];
    memset(buffer, 0, sizeof(buffer));

    // Pointer to IP header
    struct iphdr *iph = (struct iphdr *)buffer;
    // Pointer to TCP header (starts right after IP header)
    struct tcphdr *tcph = (struct tcphdr *)(buffer + sizeof(struct iphdr));

3. Populate IP Header (Match TCPDump Values)

Fill in the IP header fields to match your captured packets. For your examples, the source IP is SRCIP, dest is DSTIP, protocol is TCP, etc.

// Fill IP header
    iph->ihl = 5;               // IP header length (5 32-bit words = 20 bytes)
    iph->version = 4;           // IPv4
    iph->tos = 0;               // Type of Service
    iph->tot_len = sizeof(struct iphdr) + sizeof(struct tcphdr) + 12; // 20 + 20 + 12 (TCP options)
    iph->id = htons(12345);     // Packet ID (can be arbitrary)
    iph->frag_off = 0;          // No fragmentation
    iph->ttl = 64;              // Time to live
    iph->protocol = IPPROTO_TCP;// Protocol is TCP
    iph->check = 0;             // We'll calculate this later
    iph->saddr = inet_addr("SRCIP"); // Source IP from TCPDump
    iph->daddr = inet_addr("DSTIP"); // Destination IP from TCPDump

4. Populate TCP Header & Options (Match TCPDump Values)

This is where we map the TCPDump output directly to tcph-> fields. Your examples are TCP ACK packets with timestamp options, so we'll set those details:

// Fill TCP header (using first example packet values)
    tcph->source = htons(22409);    // Source port from TCPDump
    tcph->dest = htons(80);         // Dest port from TCPDump
    tcph->seq = htonl(0);           // For ACK packets, seq is the previous ack value (adjust as needed)
    tcph->ack_seq = htonl(2897);    // ACK number from TCPDump
    tcph->doff = 8;                 // TCP header length (8 32-bit words = 32 bytes: 20 base + 12 options)
    tcph->th_flags = TH_ACK;        // Flags [.] = ACK only
    tcph->window = htons(274);      // Window size from TCPDump
    tcph->check = 0;                // We'll calculate this later
    tcph->urg_ptr = 0;              // No urgent pointer

    // Add TCP options: NOP, NOP, Timestamp (matches your TCPDump options)
    unsigned char *opt_ptr = (unsigned char *)(tcph + 1);
    *opt_ptr++ = TCPOPT_NOP;        // First NOP
    *opt_ptr++ = TCPOPT_NOP;        // Second NOP
    *opt_ptr++ = TCPOPT_TIMESTAMP;  // Timestamp option code
    *opt_ptr++ = TCPOLEN_TIMESTAMP; // Option length (10 bytes)
    *(uint32_t *)opt_ptr = htonl(20513654); // TS val from TCPDump
    opt_ptr += 4;
    *(uint32_t *)opt_ptr = htonl(3515597033); // TS ecr from TCPDump

5. Calculate Checksum

Both IP and TCP require valid checksums. We'll use a helper function to compute them:

// Helper function to calculate checksum
    unsigned short csum(unsigned short *buf, int nwords) {
        unsigned long sum = 0;
        for (; nwords > 0; nwords--)
            sum += *buf++;
        sum = (sum >> 16) + (sum & 0xffff);
        sum += (sum >> 16);
        return (unsigned short)(~sum);
    }

    // Calculate IP header checksum
    iph->check = csum((unsigned short *)buffer, iph->ihl * 2);

    // Calculate TCP checksum (requires pseudo-header)
    struct pseudo_header {
        uint32_t source_address;
        uint32_t dest_address;
        uint8_t placeholder;
        uint8_t protocol;
        uint16_t tcp_length;
    } psh;

    psh.source_address = inet_addr("SRCIP");
    psh.dest_address = inet_addr("DSTIP");
    psh.placeholder = 0;
    psh.protocol = IPPROTO_TCP;
    psh.tcp_length = htons(sizeof(struct tcphdr) + 12); // TCP header + options length

    int psize = sizeof(psh) + sizeof(struct tcphdr) + 12;
    char *pseudogram = malloc(psize);
    memcpy(pseudogram, &psh, sizeof(psh));
    memcpy(pseudogram + sizeof(psh), tcph, sizeof(struct tcphdr) + 12);
    tcph->check = csum((unsigned short *)pseudogram, psize / 2);
    free(pseudogram);

6. Send the Cloned Packet

Finally, we'll send the packet to the destination IP:

// Set up destination address structure
    struct sockaddr_in dest_addr;
    memset(&dest_addr, 0, sizeof(dest_addr));
    dest_addr.sin_family = AF_INET;
    dest_addr.sin_addr.s_addr = iph->daddr;

    // Send the packet
    if (sendto(sockfd, buffer, iph->tot_len, 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr)) < 0) {
        perror("Failed to send packet");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    close(sockfd);
    return 0;
}

Adapting to Your Other Example Packets

To clone your second and third packets, just adjust the following fields:

  • tcph->ack_seq: Set to htonl(4345) for the second packet, htonl(5793) for the third
  • tcph->window: Set to htons(296) (second) and htons(319) (third)
  • If the third packet's TS val was truncated, fill in the full value from your capture

Critical Notes

  • Run as Root: Raw sockets require privileged access, so you must run the program with sudo or as the root user.
  • Header Compatibility: Some systems may use slightly different header structures (e.g., struct ip instead of struct iphdr). Check your system's headers if you run into issues.
  • Checksum Accuracy: Incorrect checksums will cause the packet to be dropped by network devices or the target OS. Double-check your calculations.
  • Libpcap Alternative: If you're reading directly from a TCPDump .pcap file instead of manually parsing text, use the libpcap library—it simplifies packet capture and parsing significantly.

内容的提问来源于stack exchange,提问作者Alemalakra Alemalakra

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 12:03:47