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

libnetfilter_queue修改的数据包无法到达目标端问题排查

修改IP头TTL后数据包无法到达目标端,调用nfq_udp_mangle_ipv4后恢复正常的原因

我尝试使用libnetfilter_queue为特定数据包的IP头添加自定义选项,先做了个测试:修改libnetfilter_queue文档中的示例程序nf-queue.c,将IP头的TTL值从默认64改为88。修改后的数据包能在Wireshark中捕获到,但无法到达目标端。

修改后的回调函数

static int queue_cb(const struct nlmsghdr *nlh, void *data)
{
    struct nfqnl_msg_packet_hdr *ph = NULL;
    struct nlattr *attr[NFQA_MAX+1] = {};
    uint32_t id = 0, skbinfo;
    int queue_num;
    struct nfgenmsg *nfg;

    uint16_t plen;
    void *payload;
    struct pkt_buff *pktb;
    uint8_t new_ttl = 88;

    char buf[MNL_SOCKET_BUFFER_SIZE];
    struct nlmsghdr *nlh_verdict;
    struct nlattr *nest;

    /* Parse netlink message received from the kernel, the array of
     * attributes is set up to store metadata and the actual packet.
     */
    if (nfq_nlmsg_parse(nlh, attr) < 0) {
        perror("problems parsing");
        return MNL_CB_ERROR;
    }

    nfg = mnl_nlmsg_get_payload(nlh);

    if (attr[NFQA_PACKET_HDR] == NULL) {
        fputs("metaheader not set\n", stderr);
        return MNL_CB_ERROR;
    }

    /* Access packet metadata, which provides unique packet ID, hook number
     * and ethertype. See struct nfqnl_msg_packet_hdr for details.
     */
    ph = mnl_attr_get_payload(attr[NFQA_PACKET_HDR]);
    id = ntohl(ph->packet_id);
    queue_num = ntohs(nfg->res_id);

    /* Access actual packet data length. */
    plen = mnl_attr_get_payload_len(attr[NFQA_PAYLOAD]);

    /* Access actual packet data */
    payload = mnl_attr_get_payload(attr[NFQA_PAYLOAD]);

    /* Copy to packet buffer with extra space for mangling */
    pktb = pktb_alloc(AF_INET, payload, plen, 255);

    /* Change TTL */
    nfq_ip_mangle(
        pktb,
        0,
        offsetof(struct iphdr, ttl),
        sizeof(((struct iphdr *)0)->ttl),
        &new_ttl,
        sizeof(new_ttl)
    );

    /* Accept mangled packet */
    nlh_verdict = nfq_nlmsg_put(buf, NFQNL_MSG_VERDICT, ntohs(nfg->res_id));
    if (pktb_mangled(pktb)) {
        nfq_nlmsg_verdict_put_pkt(nlh_verdict, pktb_data(pktb), pktb_len(pktb));
    }
    nfq_nlmsg_verdict_put(nlh_verdict, id, NF_ACCEPT);
    if (mnl_socket_sendto(nl, nlh_verdict, nlh_verdict->nlmsg_len) < 0) {
        perror("mnl_socket_send");
        exit(EXIT_FAILURE);
    }

    return MNL_CB_OK;
}

测试配置与步骤

nftables入队规则

nft add table inet test-table
nft add chain inet test-table test-chain '{ type filter hook output priority 0; }'
nft add rule inet test-table test-chain counter queue

测试命令

  • 接收端:nc -u -l -p 4444
  • 发送端:nc -u localhost 4444 <<< Hello

现象

Wireshark能捕获到修改TTL后的数据包,但接收端nc无输出。即使将TTL改回原值64,现象依然相同。

更新与疑问

添加nfq_udp_mangle_ipv4调用(即使未修改任何数据)后,接收端能正常接收并打印消息。查看该函数源码,发现其仅调用nfq_ip_mangle并更新UDP校验和,为何此调用是必要的?


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 14:15:27