插件窝 干货文章 linux中iphdr是什么

linux中iphdr是什么

头部 内核 IP iphdr 636    来源:    2025-05-03

在 Linux 中,iphdr 是一个与网络协议栈相关的数据结构,用于表示 IPv4 头部(IP header)。它定义在 Linux 内核的头文件中,通常用于网络编程(如原始套接字编程)或内核模块开发中,用于直接操作 IP 数据包的头部信息。


1. 定义与结构

iphdr 结构体的定义通常位于内核头文件 <linux/ip.h> 中,其结构如下:

struct iphdr {
    __u8    ihl:4,      // 头部长度(以 4 字节为单位)
            version:4;  // IP 版本(IPv4 为 4)
    __u8    tos;        // 服务类型(Type of Service)
    __be16  tot_len;    // 数据包总长度(包括头部和数据)
    __be16  id;         // 标识符(用于分片重组)
    __be16  frag_off;   // 分片偏移和标志
    __u8    ttl;        // 生存时间(Time To Live)
    __u8    protocol;   // 上层协议(如 TCP=6, UDP=17)
    __be16  check;      // 头部校验和
    __be32  saddr;      // 源 IP 地址
    __be32  daddr;      // 目标 IP 地址
    /* 可选的选项字段(如果有) */
};

2. 关键字段说明

  • version: IPv4 固定为 4
  • ihl: IP 头部长度(Internet Header Length),单位为 4 字节。最小值为 5(即 20 字节,无选项字段)。
  • protocol: 指定上层协议类型,常见值:
    • 6:TCP
    • 17:UDP
    • 1:ICMP
  • saddr/daddr: 源和目标 IP 地址,以网络字节序(大端序)存储。
  • check: 头部校验和,由内核自动计算(需调用 checksum 相关函数)。

3. 常见用途

  • 原始套接字(Raw Socket)编程
    通过 SOCK_RAW 创建原始套接字时,可以直接构造或解析 iphdr 结构体,实现自定义 IP 数据包(如 Ping 工具、网络嗅探等)。

    #include <linux/ip.h>
    
    struct iphdr *ip_header = (struct iphdr *)buffer;
    ip_header->version = 4;
    ip_header->ihl = 5;
    ip_header->ttl = 64;
    ip_header->saddr = inet_addr("192.168.1.1");
    
  • 内核网络模块开发
    在内核中处理网络数据包时(如 Netfilter 钩子),会直接操作 iphdr 结构体。

  • 网络抓包分析
    工具如 tcpdumpWireshark 在底层会解析 iphdr 字段显示 IP 层信息。


4. 示例代码(原始套接字发送 IP 包)

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

int main() {
    int sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
    if (sock < 0) {
        perror("socket");
        return 1;
    }

    char packet[1024];
    struct iphdr *ip = (struct iphdr *)packet;

    // 填充 IP 头部
    ip->version = 4;
    ip->ihl = 5;
    ip->tos = 0;
    ip->tot_len = htons(sizeof(struct iphdr));
    ip->id = htons(12345);
    ip->frag_off = 0;
    ip->ttl = 64;
    ip->protocol = IPPROTO_ICMP; // 假设上层是 ICMP
    ip->saddr = inet_addr("192.168.1.2");
    ip->daddr = inet_addr("8.8.8.8");
    ip->check = 0; // 内核会自动计算校验和(若设置 IP_HDRINCL)

    // 发送数据包
    struct sockaddr_in dest;
    dest.sin_family = AF_INET;
    dest.sin_addr.s_addr = ip->daddr;

    sendto(sock, packet, sizeof(struct iphdr), 0, 
           (struct sockaddr *)&dest, sizeof(dest));

    close(sock);
    return 0;
}

5. 注意事项

  • 权限要求:使用原始套接字需要 CAP_NET_RAW 权限(通常需以 root 运行)。
  • 字节序:IP 头部字段多为网络字节序(大端序),需用 htons()/ntohs() 等函数转换。
  • 校验和:若手动构造头部,需正确计算校验和(或依赖内核自动计算)。

总结

iphdr 是 Linux 中描述 IPv4 头部信息的关键数据结构,广泛应用于网络编程和内核开发。理解其字段和用法有助于实现自定义网络协议或分析网络流量。