我想学习如何在用户空间处理数据包。因此,我研究了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/