I am using libnetfilter_queue in C to capture packets. I am setting an iptable rule to queue the incoming packets that would later be processed by the userspace implementation like this: iptables -A INPUT -j NFQUEUE --queue-num 0
. I used nfqnl_test example as a framework to implement the capture. Everything works as expected. However, I noticed that it is impossible to inspect the queue on the level of ip fragments. That is, if a packet is coming in fragments it is first reassembled before being put into the queue. But I would like to work with fragments. So is there a way to enforce that kind of behavior? What I want to have is a queue where I could observe raw incoming packets (both fragmented and unfragmented) so I would be able to act on them accordingly.
I read that the reassembly indeed happens before. On the other hand, with iptables there is -f
flag available so there should be a "fragmentation granularity" which I am looking for. I also tried adjusting iptable rules (e.g. iptables -t raw -D PREROUTING -i eth0 -j NFQUEUE --queue-num 0
), but the result is still the same. I can only observe already reassembled packet which I definitely know that arrives in fragments.
Any help is really appreciated.
So I have found a solution to the problem and I am sharing it here in case some people are interested. The credit goes to Adel from netfilter mailing list who suggested the possible workaround. Basically, the solution is to use nftables and set up a chain with the priority lower than the one for the defragmentation. I have tested this setting with C code and it seems to work pretty well (I did not notice any side effects). However, I have to mention that I used it only for observing IP fragments and I did not tamper with them.
Below there are two functions to set up nftables and then remove them.
void set_nftable() {
int status = 0;
// Create a nftable
status = system("nft add table ip filter");
// Add a chain to the nftable called "predefrag" which has lower priority than the defragmentation -450 < -400
status = system("nft add chain ip filter predefrag { type filter hook prerouting priority -- -450 \\; }");
// Set the nftable rule (queue packets to be accessed by a user-space application)
status = system("nft add filter predefrag meta iif eth0 counter queue num 0 bypass");
}
void remove_nftable() {
int status = 0;
// Flush the rules that are stored in the chains that belong to the nftable
status = system("nft flush table ip filter");
// Delete the chain from the nftable
status = system("nft delete chain ip filter predefrag");
// Delete the nftable
status = system("nft delete table ip filter");
}
With those functions the nfqnl_test code can be used to capture IP fragments. Below there are useful links for setting up nftables and understating how they work (the comments in the functions are pretty self-explanatory once get acquainted with the nftables manual).
http://wiki.nftables.org/wiki-nftables/index.php/Building_and_installing_nftables_from_sources
http://wiki.nftables.org/wiki-nftables/index.php/Configuring_tables
http://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains
http://wiki.nftables.org/wiki-nftables/index.php/Simple_rule_management
http://wiki.nftables.org/wiki-nftables/index.php/Queueing_to_userspace