c - iptables 的队列处理程序 : Why does it stuck during receive ICMP packets?

标签 c networking queue iptables recv

我想学习如何在用户空间处理数据包。因此,我研究了oxygen libnetfilter_queue文档中的示例队列处理程序。 [LINK]

所以我构建了防火墙来将传入的 ICMP 数据包发送到队列。我还从另一台 PC 向我的 PC 发送了 ping 并启动了该程序。

但是程序在接收请求期间停止了。 - 为什么?

这是设置:

<小时/>

-1- 防火墙:我的防火墙将所有传入的 ICMP 数据包发送到队列套接字 0

Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
NFQUEUE    icmp --  anywhere             anywhere             NFQUEUE num 0

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

-2- 我对我的电脑执行了 ping 操作,并使用wireshark 测试了数据包的存在。 - 我收到了数据包。

-3- 队列句柄程序的代码。我添加了一些 printf 输出来显示程序卡在哪里。通常,该程序会接收数据包并打印有关其 header 和数据的信息。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <linux/types.h>
#include <linux/netfilter.h>        /* for NF_ACCEPT */

#include <libnetfilter_queue/libnetfilter_queue.h>

/* returns packet id */
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;
}


static int cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg,  
          struct nfq_data *nfa, void *data)             
{
    u_int32_t id = print_pkt(nfa);
    printf("entering callback\n");
    return nfq_set_verdict(qh, id, NF_ACCEPT, 0, NULL); 
}

int main(int argc, char **argv)
{
    struct nfq_handle *h;
    struct nfq_q_handle *qh;
    int fd = 0;
    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, 1, &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_PACKET, 0xffff) < 0) {  /* nfg_set_mode stellt ein, welche Pakete in dieses Programm geladen... */
        fprintf(stderr, "can't set packet_copy mode\n");    /* ...werden sollen. Hier werden metadata und data in das Programm geladen... */
        exit(1);                        /* Die Funktion gibt bei einem Fehler -1 zurück. */
    }

    fd = nfq_fd(h);

    printf("DEBUG: The programm processed nfq_fd(h)!\n nfg_fd is: %u \n", fd);

    rv = recv(fd, buf, sizeof(buf), 0); // temporär kopiert

    printf("DEBUG: The programm arrived the receiver!\n recv is: %u \n", rv);

    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); /* closing the handler */

    exit(0);
}

-4-这是我执行程序时的输出。程序在接收请求之前/期间停止。

opening library handle
unbinding existing nf_queue handler for AF_INET (if any)
binding nfnetlink_queue as nf_queue handler for AF_INET
binding this socket to queue '0'
setting copy_packet mode
DEBUG: The programm processed nfq_fd(h)!
 nfg_fd is: 3

我希望这些信息有助于理解我想要做什么。关于 libnetfilte_queue 的主要文档在 recv 命令中非常简短。

很高兴找到这个论坛, 4 特拉斯:)

最佳答案

终于找到问题所在了。不知何故,我不小心将这一行中处理程序的 NFQUEUE 编号更改为 1:

qh = nfq_create_queue(h, 1, &cb, NULL);

结果,程序等待来自NFQUEUE num 1的数据包,但我的防火墙将所有数据包发送到NFQUEUE num 0

更正后的行:

 qh = nfq_create_queue(h, 0, &cb, NULL);

天哪...这是一个愚蠢的错误;)

我要感谢所有考虑我问题的人! - 4特拉斯

关于c - iptables 的队列处理程序 : Why does it stuck during receive ICMP packets?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22093087/

相关文章:

c++ - 如何修复此语句可能会通过 [-Werror=implicit-fallthrough=]?

networking - 如何使用 Kryonet 通过网络发送对象?

Python解码UDP

c - 通过数组实现线性队列

java - 包含 java.util.concurrent.BlockingQueue 的谓词(/find/search)?

php - Laravel 邮件不通过队列发送

c - Linux 内核定义无处不在

c++ - 为可变参数宏的元素添加前缀

c++ - 如何部分禁用 cmake C/C++ 自定义编译器检查

mysql - 如何从本地主机Windows(192.168)连接docker子网(172.18)中的mysql?