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

如何在IPv4数据包中添加选项?C语言网络工具开发疑问

实现IPv4选项的正确姿势

首先你找到的struct options是Linux内核内部用来管理IP选项的结构体,用户态开发自定义数据包根本用不上,别在这上面耗时间。

要给struct iphdr加IPv4选项,核心是直接构造符合IPv4协议规范的选项字节流,拼在IP头部后面,同时调整IP头部的ihl字段就行——IP头部长度是4字节的倍数,默认无选项时ihl是5(对应20字节),每加4字节选项就把ihl加1。

步骤1:先搞懂IPv4选项的格式

每个IPv4选项都遵循这个结构:

  • 1字节:选项类型(Type)
  • 1字节:选项长度(Length,包含Type和Length本身)
  • N字节:选项数据(Data,可选)

常见的实用选项比如:

  • 记录路由(Record Route,类型0x07)
  • 时间戳(Timestamp,类型0x44)
  • 源路由(Source Route,类型0x83严格路由/0x03宽松路由)

步骤2:手动构造IP选项字节流

举个记录路由选项的例子,我们预留3个IP地址的位置:

// 记录路由选项:类型0x07,总长度14字节(1+1+3*4)
unsigned char ip_options[] = {
    0x07,        // 选项类型:记录路由
    0x0E,        // 选项长度:14字节
    0x00,        // 指针:初始指向第一个待填充的IP位置
    0x00, 0x00, 0x00, 0x00,  // 预留IP位置1
    0x00, 0x00, 0x00, 0x00,  // 预留IP位置2
    0x00, 0x00, 0x00, 0x00   // 预留IP位置3
};

步骤3:和struct iphdr组装成完整数据包

  1. 初始化IP头部并调整ihl:

    struct iphdr ip_hdr;
    // 先填IP头部的常规字段
    ip_hdr.version = 4;
    ip_hdr.ttl = 64;
    ip_hdr.protocol = IPPROTO_TCP; // 假设是TCP数据包,按需改
    ip_hdr.saddr = inet_addr("192.168.1.100"); // 源IP
    ip_hdr.daddr = inet_addr("192.168.1.200"); // 目的IP
    
    // 处理选项的4字节对齐:不够的话用填充选项(0x00)补全
    int opt_len = sizeof(ip_options);
    int padded_opt_len = (opt_len + 3) & ~3; // 向上取整到4的倍数
    unsigned char padded_options[padded_opt_len];
    memcpy(padded_options, ip_options, opt_len);
    memset(padded_options + opt_len, 0, padded_opt_len - opt_len); // 补填充
    
    // 计算ihl:(基础IP头部20字节 + 对齐后的选项长度) /4
    ip_hdr.ihl = (20 + padded_opt_len) / 4;
    
  2. 拼接IP头部、选项和数据:

    int data_len = 100; // 假设数据长度是100字节,按需改
    unsigned char *data = malloc(data_len);
    // 填充数据内容...
    
    int total_packet_len = sizeof(struct iphdr) + padded_opt_len + data_len;
    unsigned char *packet = malloc(total_packet_len);
    if (!packet) { /* 内存分配失败,做错误处理 */ }
    
    // 依次拷贝IP头部、选项、数据
    memcpy(packet, &ip_hdr, sizeof(struct iphdr));
    memcpy(packet + sizeof(struct iphdr), padded_options, padded_opt_len);
    memcpy(packet + sizeof(struct iphdr) + padded_opt_len, data, data_len);
    
  3. 计算IP校验和:
    校验和要覆盖整个IP头部(包括选项),所以计算时要传整个头部的长度:

    // 先清零校验和字段
    ip_hdr.check = 0;
    // 计算校验和,ip_checksum是自定义的校验和函数
    ip_hdr.check = ip_checksum((unsigned short *)&ip_hdr, ip_hdr.ihl * 4);
    // 把更新后的IP头部拷贝回数据包
    memcpy(packet, &ip_hdr, sizeof(struct iphdr));
    

几个必须注意的点

  • 选项必须4字节对齐:IP头部总长度必须是4字节的倍数,不够的话一定要用填充选项(类型0x00)补全,不然数据包会被网络设备直接丢弃。
  • ihl字段不能错:ihl是IP头部(含选项)的长度除以4,算错了会导致后续解析出错。
  • 用RAW套接字发送:用户态发送自定义数据包必须创建SOCK_RAW类型的套接字,还要设置IP_HDRINCL选项,这样内核才不会自动生成IP头部,让你完全自定义。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 12:01:37