【问题标题】:Iptables netfilter queue nfq_set_verdict_mark (nfq_set_verdict2) doesn't seem to be applying a markiptables netfilter queue nfq_set_verdict_mark (nfq_set_verdict2) 似乎没有应用标记
【发布时间】:2013-12-18 19:27:05
【问题描述】:

我在使用 iptables 时遇到了一些问题,而一组新的眼球可能会发现问题所在。

我正在尝试使用 netfilter 队列在 mangle 表的 PREROUTING 链中标记数据包(通过 nfq_set_verdict_mark - 旧文档说使用 nfq_set_verdict2 但该函数似乎不再位于标头或库中)。然后数据包应该移动到 nat 表的 PREROUTING 链,在那里我有规则来读取标记并相应地重定向。确实,这在早期的测试中有效,但现在不行!

这是我的简化测试的回调函数 - 它只是用 0xFFFFFFFF 标记并接受:

static int cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg,
          struct nfq_data *nfa, void *data)
{
    uint32_t id = print_pkt(nfa); // from example code
    printf("marking packet...\n");
    return nfq_set_verdict_mark(qh,id,NF_ACCEPT,0xFFFFFFFF,0,NULL);
}

这是我正在使用的 iptable 规则:

// Using queue -- not working
iptables -t mangle -A PREROUTING -p tcp --dport 80 -j QUEUE
iptables -t nat -A PREROUTING -p tcp --dport 80 -m mark --mark 0xFFFFFFFF -j REDIRECT --to-ports 9009

我还使用conntrack --flush 重置连接状态,以确保数据包遇到 nat 表。我使用 0xFFFFFFFF 来防止可能的字节排序问题。数据包清楚地进入队列并被接受(打印“标记数据包...”,浏览器可以访问端口 80 上的内容)。但是,不会发生重定向。

如果我直接设置标记而不是在队列中,则重定向有效。就像标记没有被添加到队列中一样。之前肯定是打标的,我没有更改库版本或任何东西。

// Without queue -- redirection happens
iptables -t mangle -A PREROUTING -p tcp --dport 80 -j MARK --set-mark 0xFFFFFFFF
iptables -t nat -A PREROUTING -p tcp --dport 80 -m mark --mark 0xFFFFFFFF -j REDIRECT --to-ports 9009

这里的 print_pkt 可以很好地衡量 - 不是我写的,而是取自 netfilter_queue 示例,没有更改,并且之前可以正常工作:

static u_int32_t print_pkt (struct nfq_data *tb)
{
        int id = 0;
        struct nfqnl_msg_packet_hdr *ph;
        struct nfqnl_msg_packet_hw *hwph;
        u_int32_t mark,ifi; 
        int ret;
        char *data;

        ph = nfq_get_msg_packet_hdr(tb);
        if (ph) {
                id = ntohl(ph->packet_id);
                printf("hw_protocol=0x%04x hook=%u id=%u ",
                        ntohs(ph->hw_protocol), ph->hook, id);
        }

        hwph = nfq_get_packet_hw(tb);
        if (hwph) {
                int i, hlen = ntohs(hwph->hw_addrlen);

                printf("hw_src_addr=");
                for (i = 0; i < hlen-1; i++)
                        printf("%02x:", hwph->hw_addr[i]);
                printf("%02x ", hwph->hw_addr[hlen-1]);
        }

        mark = nfq_get_nfmark(tb);
        if (mark)
                printf("mark=%u ", mark);

        ifi = nfq_get_indev(tb);
        if (ifi)
                printf("indev=%u ", ifi);

        ifi = nfq_get_outdev(tb);
        if (ifi)
                printf("outdev=%u ", ifi);
        ifi = nfq_get_physindev(tb);
        if (ifi)
                printf("physindev=%u ", ifi);

        ifi = nfq_get_physoutdev(tb);
        if (ifi)
                printf("physoutdev=%u ", ifi);

        ret = nfq_get_payload(tb, &data);
        if (ret >= 0)
                printf("payload_len=%d ", ret);

        fputc('\n', stdout);

        return id;
}

另外,main 函数(也取自示例代码并且以前可以工作):

int main(int argc, char **argv)
{
        struct nfq_handle *h;
        struct nfq_q_handle *qh;
        struct nfnl_handle *nh;
        int fd;
        int rv;
        char buf[4096] __attribute__ ((aligned));

        printf("opening library handle\n");
        h = nfq_open();
        if (!h) {
                fprintf(stderr, "error during nfq_open()\n");
                exit(1);
        }

        printf("unbinding existing nf_queue handler for AF_INET (if any)\n");
        if (nfq_unbind_pf(h, AF_INET) < 0) {
                fprintf(stderr, "error during nfq_unbind_pf()\n");
                exit(1);
        }

        printf("binding nfnetlink_queue as nf_queue handler for AF_INET\n");
        if (nfq_bind_pf(h, AF_INET) < 0) {
                fprintf(stderr, "error during nfq_bind_pf()\n");
                exit(1);
        }

        printf("binding this socket to queue '0'\n");
        qh = nfq_create_queue(h,  0, &cb, NULL);
        if (!qh) {
                fprintf(stderr, "error during nfq_create_queue()\n");
                exit(1);
        }

        printf("setting copy_packet mode\n");
        if (nfq_set_mode(qh, NFQNL_COPY_META, 0xffff) < 0) {
                fprintf(stderr, "can't set packet_copy mode\n");
                exit(1);
        }

        fd = nfq_fd(h);

        while ((rv = recv(fd, buf, sizeof(buf), 0)) && rv >= 0) {
                printf("pkt received\n");
                nfq_handle_packet(h, buf, rv);
        }

        printf("unbinding from queue 0\n");
        nfq_destroy_queue(qh);

#ifdef INSANE
        /* normally, applications SHOULD NOT issue this command, since
         * it detaches other programs/sockets from AF_INET, too ! */
        printf("unbinding from AF_INET\n");
        nfq_unbind_pf(h, AF_INET);
#endif

        printf("closing library handle\n");
        nfq_close(h);

        exit(0);
}

重定向是我的测试代码中的预期行为,但它没有发生。缺少的链接是什么?我在这个问题上花了几个小时(之前按预期工作)无济于事。救命!!

【问题讨论】:

    标签: c linux networking iptables netfilter


    【解决方案1】:

    旧文档说要使用 nfq_set_verdict2,但该函数似乎不再位于头文件或库中

    也许您使用的是过时版本的 libnetfilter_queue hdrs+lib ? 版本 1.0.2 (netfilter.org) 似乎是最新版本,这个功能。

    【讨论】:

      【解决方案2】:

      是的,使用最新的 libnetfilter_queue,应该只使用以下方式的 nfq_set_verdict2 函数

       nfq_set_verdict2(handle,
                        packet_id,
                        NF_AXXEPT,
                        nfq_get_nfmark(nfa) | 0xFFFFFFFF,
                        0,
                        NULL);
      

      它对我有用。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-07-10
        • 2015-06-11
        • 2019-12-03
        • 1970-01-01
        • 2011-06-19
        相关资源
        最近更新 更多