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

如何在C语言中从IPv6套接字读取HTTP头并提取请求URL

问题根因

你现有代码的异常主要来自三个核心问题:

  • 未处理IPv6扩展头:IPv6基本头之后可能跟随0~N个扩展头(逐跳选项、路由头、分片头、认证头、封装安全载荷头、目的选项头等),你直接偏移sizeof(struct ipv6hdr)就找TCP头的逻辑,遇到带扩展头的报文必然偏移错误
  • 直接用printk("%s", data)输出payload:HTTP payload不是以'\0'结尾的C字符串,且你没有校验data指针是否在skb的线性区域内,超出范围就会读到无效内存,出现乱码甚至打印data is 0的情况
  • 缺少协议合法性校验:你默认报文是TCP协议,没有判断IPv6头的nexthdr字段,遇到UDP/ICMPv6报文也会按TCP解析,逻辑完全错误
IPv6扩展头遍历方法

内核已经提供了标准的IPv6扩展头遍历接口ipv6_skip_exthdr,不需要手动解析,该函数会自动跳过所有合法扩展头,返回传输层头的偏移量,同时输出最终的传输层协议类型。

修正后的完整代码
#include <linux/ipv6.h>
#include <linux/tcp.h>
#include <linux/skbuff.h>
#include <linux/string.h>

static int sc_get_http_info(struct sk_buff *skb)
{
    struct ipv6hdr *ip6h;
    struct tcphdr *tcph;
    unsigned char *data;
    unsigned int datalen, transport_off;
    int nexthdr;

    /* 校验IPv6报文合法性 */
    if (!skb)
        return -EINVAL;
    ip6h = ipv6_hdr(skb);
    if (ip6h->version != 6)
        return -EPROTONOSUPPORT;

    /* 遍历所有IPv6扩展头,获取传输层头偏移 */
    nexthdr = ip6h->nexthdr;
    transport_off = sizeof(struct ipv6hdr);
    transport_off = ipv6_skip_exthdr(skb, transport_off, &nexthdr);
    if (transport_off < 0)
        return -EINVAL; // 扩展头解析错误

    /* 仅处理TCP报文,需要UDP场景替换为IPPROTO_UDP即可 */
    if (nexthdr != IPPROTO_TCP)
        return -EPROTONOSUPPORT;

    /* 校验TCP头是否在skb线性区内,避免越界访问 */
    if (!pskb_may_pull(skb, transport_off + sizeof(struct tcphdr)))
        return -ENODATA;

    tcph = (struct tcphdr *)(skb_network_header(skb) + transport_off);
    /* 校验TCP头长度合法性 */
    if (tcph->doff * 4 < sizeof(struct tcphdr))
        return -EINVAL;

    /* 计算HTTP payload的起始偏移和长度 */
    unsigned int http_off = transport_off + tcph->doff * 4;
    datalen = skb->len - http_off;
    if (datalen <= 0)
        return -ENODATA; // 无应用层payload

    /* 校验payload可读,避免越界 */
    if (!pskb_may_pull(skb, http_off + 1))
        return -ENODATA;
    data = skb_network_header(skb) + http_off;

    /* 打印payload不要用%s,指定长度输出避免内存越界 */
    printk("data len: %u, first 32 bytes: %*ph\n", datalen, min(datalen, 32U), data);

    /* 提取URL逻辑示例:匹配HTTP请求行,提取第二字段 */
    if (datalen >= 4 && !strncmp(data, "GET ", 4)) {
        unsigned char *url_start = data + 4;
        unsigned char *url_end = memchr(url_start, ' ', datalen - 4);
        if (url_end) {
            int url_len = url_end - url_start;
            printk("HTTP URL: %*s\n", url_len, url_start);
        }
    }

    return 0;
}
注意事项
  • 分片报文处理:如果遇到IPv6分片报文,仅首分片携带传输层头,后续分片没有HTTP头,需要完整解析的场景需要先做分片重组
  • HTTPS报文:HTTPS payload是加密的,无法直接解析出明文URL,仅HTTP明文报文可直接提取
  • 大包处理:如果HTTP报文长度超过MTU被分段,Netfilter钩子点可能只能拿到单段数据,要完整解析需要做流级别的数据拼接

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 19:39:02