Re: NFQUEUE the plot is growing...

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 12/May/11 11:40, nowhere wrote:
>> It seems enough to avoid delaying the call to nfq_set_verdict for the
>> first packet of a burst.  For a shot in the dark, packets seem to get
>> lost if they arrive between the first one and the corresponding call
>> to nfq_set_verdict.  Indeed, setting a fixed real_delay of 0.2, with
>> ping -i 0.2 it looses no packets, with ping -i 0.19 it looses just the
>> second one, with ping -i 0.09 icmp_reqs #2 and #3.
>> 
>> No error is returned, whether NETLINK_NO_ENOBUFS is set or not.
> 
> Well, seems like this is the case. If nfqueue becomes empty, first
> enqueued packet must not be delayed.

I retract, possibly I've been too hasty blaming nfnetlink queue.  I
made a simple variation of nfqnl_test.c --which I attach.  It just
accepts the previous packet id.  The "last" packet is obviously always
lost.  Because of this bug(?), I also loose the second packet of a
sequence of pings, no matter the speed.

However, if I "ping -c 1" using two terminal windows, I correctly
receive all odd ids in one window and even ones in the other (except
last pkt).  In this case, I delay every packet.  Also, if I run a
sequence from a window, and, immediately after it starts, run a single
ping using the other window, then both the single ping and the
sequence (except last pkt) go correctly through.

I don't understand how come the kernel+filter system can distinguish
between a second packet coming as part of a sequence and a second
packet coming asynchronously, given that packets are not inspected.
Nice puzzle, isn't it?


NB, I used iptables -t mangle -A POSTROUTING -p icmp -d 172.25.197.158
-j NFQUEUE --queue-num 13, as in
http://www.spinics.net/lists/netfilter/msg50829.html
/*

$ ping -c 8 172.25.197.158
PING 172.25.197.158 (172.25.197.158) 56(84) bytes of data.
64 bytes from 172.25.197.158: icmp_req=1 ttl=128 time=1010 ms
64 bytes from 172.25.197.158: icmp_req=3 ttl=128 time=1000 ms
64 bytes from 172.25.197.158: icmp_req=4 ttl=128 time=1000 ms
64 bytes from 172.25.197.158: icmp_req=5 ttl=128 time=999 ms
64 bytes from 172.25.197.158: icmp_req=6 ttl=128 time=1000 ms
64 bytes from 172.25.197.158: icmp_req=7 ttl=128 time=1010 ms

--- 172.25.197.158 ping statistics ---
8 packets transmitted, 6 received, 25% packet loss, time 7020ms
rtt min/avg/max/mdev = 999.452/1003.574/1010.633/4.883 ms, pipe 2


# grep -E ^ *13 /proc/net/netfilter/nfnetlink_queue
   13  13584     1 1     0     0     0        8  1

   ^queue_num,
       ^peer_pid,
                 ^queue_total,
                   ^copy_mode,
                          ^copy_range,
                               ^queue_dropped,
                                      ^queue_user_dropped,
                                              ^id_sequence,
                                                  ^1
*/



#include <stdio.h>
#include <stdlib.h>
#include <string.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>

#include <errno.h>

struct packet_data
{
	u_int32_t id, good;
};

static int cb(struct nfq_q_handle *qh, struct nfgenmsg *nu,
	      struct nfq_data *nfa, void *data)
{
	struct packet_data *pd = (struct packet_data*)data;
	struct nfqnl_msg_packet_hdr *ph = nfq_get_msg_packet_hdr(nfa);
	
	if (pd && ph)
	{
		if (pd->good) // since last time
			nfq_set_verdict(qh, pd->id, NF_ACCEPT, 0, NULL);

		pd->id = ntohl(ph->packet_id);
		pd->good = 1;
		printf("received packet %d\n", pd->id);
	}
	
	return 0;

	(void)nu;
}

int main()
{
	struct nfq_handle *h;
	struct nfq_q_handle *qh;
	struct packet_data pd;
	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);
	}

	pd.good = 0;
	qh = nfq_create_queue(h,  13 /* <--queue number here */, &cb, &pd);
	if (!qh) {
		fprintf(stderr, "error during nfq_create_queue()\n");
		exit(1);
	}

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

	fd = nfq_fd(h);

	for (;;) {
		if ((rv = recv(fd, buf, sizeof(buf), 0)) >= 0) {
			nfq_handle_packet(h, buf, rv);
			continue;
		}
		/* if the computer is slower than the network the buffer
		* may fill up. Depending on the application, this error
		* may be ignored */		
		if (errno == ENOBUFS) {
			printf("pkt lost!!\n");
			continue;
		}
		printf("recv failed: errno=%d (%s)\n",
			errno, strerror(errno));
	}

	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);
}

[Index of Archives]     [Linux Netfilter Development]     [Linux Kernel Networking Development]     [Netem]     [Berkeley Packet Filter]     [Linux Kernel Development]     [Advanced Routing & Traffice Control]     [Bugtraq]

  Powered by Linux