Libnetfilter_Queue Programming, How to Know Which Program Send The Packet

Using libnetfilter_queue, a reinjected packet dosnt affect change, However inject copy of the packet succeeds. Why?

need to use NF_REPEAT verdict to reinject packet to the
same chain. Using NF_ACCEPT verdict injects packet to the subsequent
chain. But for this purpose you should mark packets to avoid loop,
i.e.:

iptables -t raw -A PREROUTING -p tcp -m tcp --dport 80 -m mark !
--mark 0x1/0x1 -m tcp -j NFQUEUE
iptables -t raw -A PREROUTING -p tcp -m tcp --dport 80 -m mark --mark
0x80/0x80 -m tcp ACCEPT # altered packets
iptables -t raw -A PREROUTING -p tcp -m tcp --dport 80 -m mark --mark
0x1/0x1 -m tcp ACCEPT # rest

The network packet is rejected if i make a change in it using libnetfilter_queue

If you change anything you have to update the checksum to prevent rejection, otherwise the packet will be considered to be corrupted...

edit: assuming you are working on IP packets, the above only applies for changes in the IP header, since only the header, not the payload, is 'protected' by the IP checksum.

libnetfilter_queue recv() function

recv() may return -1 and errno is set to ENOBUFS in case your application is not fast enough to retrieve the packets from the kernel. In that case, you can increase the socket buffer size by means of nfnl_rcvbufsiz(). Although this delays ENOBUFS errors, you may hit it again sooner or later.

Source: libnetfilter_queue Documentation

Rewriting network packets on the fly using libnetfilter_queue

I can't believe I missed this previously. As reticent as I am to post questions on SO, I thought I would never work this one out myself. :)

I didn't look at the function prototype properly. It turns out in the "verdict" function (outlined below),

int nfq_set_verdict(struct nfq_q_handle *qh,
u_int32_t id,
u_int32_t verdict,
u_int32_t data_len,
const unsigned char *buf
)

The last two parameters are for the data to be returned to the network stack. Obvious in hindsight, but I missed it completely as the print_pkt function doesn't take the packet data as a parameter, but extracts it from the struct nfq_data.

The key is to NF_ACCEPT the packet and pass the suitably modified packet back to the kernel.

simple program using libnetfilter_queue isn't working

Yes, you have. If your firewall lets the packets trough the rules nothing will happen and the packets wont left the kernel space. But if you setting up some rules that send the packets to the user space, your programm will work.

iptables -A INPUT -i eth0 -j NFQUEUE --queue-num 0

This line will send all packets from the INPUT with the --in-interface eth0 into the userspace.

Sending queued packets with NFQUEUE?

Your idea makes sense. In fact I've seen a very similar scheme implemented in a commercial product I worked on. It had to process individual packets at high rates, so it would always copy the incoming packet and immediately set an NF_DROP verdict. It would then perform the processing, and if it decided that the packet should be forwarded, it would send the copy to the outbound interface. So you're not alone.

As far as I know, nfq_set_verdict can be called only once per packet. Once the verdict is set, NFQUEUE sends the packet to the destination (which is packet heaven in your case). It doesn't keep an extra copy of the packet just in case you change your mind. So to send the packet back to the network you'll have to store a copy of it and send it using your own socket. And yes, if you want to send the received packet as-is (including headers) the outbound socket would have to be raw.

forwarding packets to service in same host without using loopback network

I propose the following solution:

  • store packets in the application and return verdict NF_DROP
  • re-inject packets into the network stack using RAW sockets
  • tag concatenated UDP packets with a DSCP (see IP packet format)
  • in iptables, add a rule to match on this DSCP (--dscp) and ACCEPT the packet directly, without it passing through your netfilter application

If your provider already tags some packets with DSCP, you can add some iptables rules to clear them, like:

iptables -t mangle -A INPUT -j DSCP --set-dscp 0

I hope this solves your use-case.

libnetfilter_queue: Why can't I see the TCP payload of packets from nfq_get_payload?

Thanks to Joel for pointing out that problem was not in the C code, but in the iptables rules. There was a -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT rule prior to the NFQUEUE rule, so I was only getting the connection setup packets... whoops.



Related Topics



Leave a reply



Submit