Search code examples
tcpiptablesnetfilter

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


I have a fairly basic user space firewall application. It receives data from libnetfilter_queue properly, we can see all the IP and TCP header information including source and destination IPs, ports, protocols, etc, but we don't get ANY of the TCP payload information...

The setup is pretty standard, I won't include it all but here are the highlights:

#define MAX_BUFFER_SIZE 65535
nfq_set_mode(qh, NFQNL_COPY_PACKET, MAX_BUFFER_SIZE)

So we are asking for the FULL PACKET back...

In the main thread we have:

rv = recv(fd, nfq_buffer, sizeof(nfq_buffer), 0);
printf("\nGot packet len: %d", rv);
if (rv > 0)
        nfq_handle_packet(nfq_h, (char*)nfq_buffer, rv);

Here, on a standard HTTP call I will get a packet length of 140. But, in the callback handler the PACKET length is ALWAYS 64:

static int handle_packet(struct nfq_q_handle* qh, struct nfgenmsg* nfmsg, struct nfq_data* dat, void* data)
{
    struct nfqnl_msg_packet_hdr* nfq_hdr = nfq_get_msg_packet_hdr(dat);
    unsigned char* nf_packet;
    int len = nfq_get_payload(dat,&nf_packet);
    struct iphdr *iph = ((struct iphdr *) nf_packet);
   iphdr_size = iph->ihl << 2;

    if (iph->protocol == 6){
        struct tcphdr *tcp = ((struct tcphdr *) (nf_packet + iphdr_size));    
        unsigned short tcphdr_size = (tcp->doff << 2);

        printf("\nGot a packet!! len: %d iphdr: %d tcphdr: %d", len, iphdr_size, tcphdr_size);
    }
}

In TCP, len is ALWAYS 64 (iphdr is 20, tcphdr is 44)... ALWAYS. I never get the TCP payload. What am I doing wrong???


Solution

  • 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.