我在使用iptables时遇到了一些麻烦,一套新的眼球可能会看出问题出在哪里。
我正在尝试使用netfilter队列标记数据包(通过nfq_set_verdict_mark - 旧文档说使用nfq_set_verdict2,但该函数似乎不再在标题或库中)在mangle表的PREROUTING链中。然后数据包应该移动到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;
}
此外,主要功能(也取自示例代码并且之前正在工作):
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);
}
重定向是我的测试代码中的预期行为,但它没有发生。什么是缺失的链接?我花了好几个小时来解决这个问题(这是事先按预期工作)无济于事。帮助!
答案 0 :(得分:0)
旧文档说使用nfq_set_verdict2但该函数似乎不再出现在标题或库中
也许您使用的是libnetfilter_queue hdrs + lib的过时版本? 版本1.0.2(netfilter.org)似乎是最新版本,具有此功能。
答案 1 :(得分:0)
是的,使用最新的 libnetfilter_queue,应该只使用 nfq_set_verdict2 函数,如下所示
nfq_set_verdict2(handle,
packet_id,
NF_AXXEPT,
nfq_get_nfmark(nfa) | 0xFFFFFFFF,
0,
NULL);
它对我有用。