How to Build and Use libnetfilter_queue for Android

If you’re looking for general information about how to use libnetfilter_queue for Linux, please refer here.

0. Preparation
First, you’ll need to check if your Android system kernel is compiled with support for libentfilter_queue. Follow the following steps,

  • Connect your android device to your computer.
  • Enter command “adb pull /proc/config.gz” to get the config.gz file from your android device.
  • Extract config.gz file, you’ll get a file named config. This is actually your Android Linux kernel build configuration file.
  • Search for CONFIG_NETFILTER_ADVANCED, CONFIG_NETFITLER_NETLINK and CONFIG_NETFILTER_NETLINK_QUEUE in config file, make sure they’re not commented out.

If your Android build is not compiled with these features, you’ll need to compile customized kernel build to use libnetfilter_queue.

Next you’ll need to root your Android device. This is not the focus of this post, so it’s not covered here. But you can find lots of information online.

Thirdly, make sure your phone has iptables program. iptables program is used to configure the kernel packet filter table. Follow the command below to check,

adb shell

su

iptables –list

If the terminal doens’t complain about program not found, then you have iptables installed. If you don’t have iptables installed on your Android device, you may consider install busybox, or compile your own iptables program. I checked out the Android source code tree, it includes iptables in the external folder. So it should be doable to build on your own.

1. Build the Libraries and Test Executable
libnetfilter_queue depends on libnfnetlink, so we’ll need to download both libraries from here and here. After downloading, extract the libraries to your Android project jni folder.
Copy the nfqnl_test.c file from libnetfilter_queue-1.0.0/utils/ folder to jni folder. And create a Android.mk file with the content below,

#LOCAL_PATH is used to locate source files in the development tree.

#the macro my-dir provided by the build system, indicates the path of the current directory

LOCAL_PATH:=$(call my-dir)

 

#####################################################################

#            build libnflink                    #

#####################################################################

include $(CLEAR_VARS)

LOCAL_MODULE:=nflink

LOCAL_C_INCLUDES := $(LOCAL_PATH)/libnfnetlink-1.0.0/include

LOCAL_SRC_FILES:=

    libnfnetlink-1.0.0/src/iftable.c 

    libnfnetlink-1.0.0/src/rtnl.c 

    libnfnetlink-1.0.0/src/libnfnetlink.c

include $(BUILD_STATIC_LIBRARY)

#include $(BUILD_SHARED_LIBRARY)

 

#####################################################################

#            build libnetfilter_queue            #

#####################################################################

include $(CLEAR_VARS)

LOCAL_C_INCLUDES := $(LOCAL_PATH)/libnfnetlink-1.0.0/include 

    $(LOCAL_PATH)/libnetfilter_queue-1.0.0/include

LOCAL_MODULE:=netfilter_queue

LOCAL_SRC_FILES:=libnetfilter_queue-1.0.0/src/libnetfilter_queue.c

LOCAL_STATIC_LIBRARIES:=libnflink

include $(BUILD_STATIC_LIBRARY)

#include $(BUILD_SHARED_LIBRARY)

 

#####################################################################

#            build our code                    #

#####################################################################

include $(CLEAR_VARS)

LOCAL_C_INCLUDES := $(LOCAL_PATH)/libnfnetlink-1.0.0/include 

    $(LOCAL_PATH)/libnetfilter_queue-1.0.0/include

LOCAL_MODULE:=nfqnltest

LOCAL_SRC_FILES:=nfqnl_test.c

LOCAL_STATIC_LIBRARIES:=libnetfilter_queue

LOCAL_LDLIBS:=-llog -lm

#include $(BUILD_SHARED_LIBRARY)

include $(BUILD_EXECUTABLE)

Then issue “ndk-build” command to build the libraries and executable nfqnltest.

Note that you’ll probably encounter an error “undefined reference to __fswab64”. This is an known issue as indicated here. Just apply the patch (or change according to the patch) to your NDK header file (platforms/android-9/arch-arm/usr/include/linux/byteorder/swab.h, replace “android-9” in the path with your targeted android version). It will resolve the build error.

2. Running the Code on Android
Follow the command below to copy and executable to your Android device and run it,

  • adb shell
  • su
  • mkdir /data/data/nfqnltest
  • chmod 777 /data/data/nfqnltest
  • Open another terminal. Go to libs/<armeabi*> folder of your Android project. Issue command “adb push nfqnltest /data/data/nfqnltest/”
  • Switch back to first terminal, “cd /data/data/nfqnltest”
  • ./nfqnltest

To configure iptables rules, you can open a new terminal, then follow the command below,

adb shell

su

iptables -A OUTPUT -p tcp -j NFQUEUE –queue-num 0

Then in terminal you’re running nfqnltest, you can see the program outputs. If you open browser app on your phone, and try to open google.com. You’ll see some packet information displayed,

pkt received

…….

hw_protocol=0x0000 hook=3 id=0 outdev=12 payload_len=288

entering callback

pkt received

hw_protocol=0x0000 hook=3 id=1 outdev=12 payload_len=869

entering callback

With libnetfilter_queue, you can do a lot of interesting stuff, like user space NATing, packet sniffing/capturing etc.

How to Configure, Install and Use libnefilter_queue on Linux

According to libnetfilter_queue home page, libnetfilter_queue is a userspace library that allows one to retrieve and manipulate the packets that have been queued by kernel packet filter. It is supposed to replace the old ip_queue/libipq mechanism.
0. Dependencies
libnetfilter_queue requires a kernel that includes nfnetlink_queue subsystem. If you Linux kernel is 2.6.14 or later, the subsystem is normally enabled.

You can confirm this by looking into your kernel configuration file. The configuration file is normally located at your system /boot/ directory, with the name like config-<your kernel version>. Open the file, and look for CONFIG_NETFILTER_NETLINK_QUEUE and CONFIG_NETFILTER_ADVANCED.  Make sure the two lines are not commented out.

In addition, libnetfilter_queue library depends on libnfnetlink. A lower-level library for netfitler related kernel/userspace communication. And since this library depends on nfnetlink kernel subsystem, you’ll need to ensure CONFIG_NETFITLER_NETLINK is not commented out in your kernel configuration file.

In summary, you’ll need to check CONFIG_NETFILTER_ADVANCED, CONFIG_NETFITLER_NETLINK and CONFIG_NETFILTER_NETLINK_QUEUE in you kernel configuration file, and install libnfnetlink and libnetfilter_queue user space libraries.
2. Installation
This is simple. First, you need to install libnfnetlink library. Download the tar file here.
Then go the directory where the file is downloaded, follow the commands below,

tar -xvf libnfnetlink-1.0.0.tar.bz2

cd libnfnetlink-1.0.0/

./configure

make

sudo make install

Next, you need to install libnetfilter_queue library. Download the tar file here.  Then follow the same procedure above. Build and install the library.

After installation, issue sudo ldconfig command to create necessary links and cache to the newly installed libraries.
3. Understand the Sample Code
There’re not many tutorials and examples around, but libnetfilter_queue has provided a simple example and some documentation. You can find the sample code at the utiles/ nfqnl_test.c of the libnetfilter_queue folder you downloaded.

The basic idea of the code is to set up libnetfiter_queue library, and bind the program to a queue. You can refer to documentation here and here to help you understand the code.
To compile the sample code, use the command below,

gcc -Wall -o test nfqnl_test.c -lnfnetlink -lnetfilter_queue

To run the code, use the command below,

sudo ./test

Note that you’ll need to set up a queue in kernel packet filter table in order to see how the program working. Suppose we want to queue all TCP packets sending out from our local machine, you’ll need to enter the command below,

sudo iptables -A OUTPUT -p tcp -j NFQUEUE –queue-num 0

Now you can see the test program is outputing some information about the packet,

…..
hw_protocol=0x0000 hook=3 id=422 outdev=2 payload_len=52

entering callback

pkt received

hw_protocol=0x0000 hook=3 id=423 outdev=2 payload_len=52

entering callback

To stopping running the program, kill test and then issue the command

iptables –flush

4. Additional Notes
libnetfilter_queue can be quite powerful combined with iptables rules. It doesn’t only allow you to receive the packet, but also provide the ability to modify the packet and inject the modified packet back to kernel. With these APIs, you can implement user space NATing, packet sniffing/capturing programs etc.

References:
1. libnetfilter_queue home page: http://www.netfilter.org/projects/libnetfilter_queue/

How to Calculate IP/TCP/UDP Checksum–Part 3 Usage Example and Validation

This is a follow up of the previous post IP/TCP/UDP Checksum Calculation part 1 theory, and part 2 implementation.

This post gives an example using libnetfiler_queue library and the checksum code we implemented in part 2 to illustrate how to use the checksum code and verify that our code is actually computing correctly.

Note this post is not a post for libnetfilter_queue library. So the usage of this library is not covered here. I’ve written separate posts for libnetfilter_queue.

The code (let’s call it test.c) is as below,

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <linux/types.h>
#include <linux/netfilter.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <libnetfilter_queue/libnetfilter_queue.h>

#include "checksum.h"

static int cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_data *nfa, void *data) {
    printf("entering callbackn");
    struct nfqnl_msg_packet_hdr *ph;
    int payload_len;
    unsigned char *payloadData;
    struct iphdr *ipHeader;
    struct tcphdr *tcpHeader;
    struct udphdr *udpHeader;
    unsigned short ipCheck, udpCheck, tcpCheck;
    ph = nfq_get_msg_packet_hdr(nfa);
    u_int32_t id = ntohl(ph->packet_id);
    payload_len = nfq_get_payload(nfa, &payloadData);
    printf("ip datagram len = %dn", payload_len);
    ipHeader = (struct iphdr *)payloadData;
    ipCheck = ipHeader->check;
    printf("ip checksum: %04xn", ipHeader->check);
    //calculate ip checksum, and see if the calculation matches
    compute_ip_checksum(ipHeader);
    printf("calculated ip checksum: %04xn", ipHeader->check);
    if (ipCheck != ipHeader->check) {
    printf("-------------ip checksum calculation is wrong-----------n");
    }
    if (ipHeader->protocol == IPPROTO_TCP) {
        tcpHeader = (struct tcphdr *)(payloadData + (ipHeader->ihl<<2));
    tcpCheck = tcpHeader->check;
    printf("tcp checksum: %04xn", tcpHeader->check);
    //calculate tcp checksum, and see if the calculation matches with original tcp checksum
        compute_tcp_checksum(ipHeader, (unsigned short*)tcpHeader);
    printf("calculated tcp checksum: %04xn", tcpHeader->check);
    if (tcpHeader->check != tcpCheck) {
        printf("-----------calculation is wrong-------n");
    }
    } else if (ipHeader->protocol == IPPROTO_UDP) {
    udpHeader = (struct udphdr *)(payloadData + (ipHeader->ihl<<2));
    udpCheck = udpHeader->check;
    printf("udp checksum: %04xn", udpHeader->check);
    //calculate udp checksum, and see if the calculation matches with original udp checksum
    compute_udp_checksum(ipHeader, (unsigned short*)udpHeader);
    printf("calculated udp checksum: %04xn", udpHeader->check);
        if (udpHeader->check != udpCheck) {
        printf("-----------calculation is wrong-------n");
    }
    }
    //issue a verdict on a packet
    //qh: netfilter queue handle; id: ID assigned to packet by netfilter; verdict: verdict to return to netfilter, data_len: number
    //of bytes of data pointed by buf, buf: the buffer that contains the packet data (payload)
// return nfq_set_verdict(qh, id, NF_ACCEPT, 0, NULL);
    return nfq_set_verdict(qh, id, NF_ACCEPT, payload_len, payloadData);
}

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

    /*netfilter_queue library set up step 1: call nfq_open to open a NFQUEUE handler*/
    printf("opening library handlen");
    h = nfq_open();
    if (!h) {
        fprintf(stderr, "error during nfq_open()n");
        exit(1);
    }
    /*set up step 2: tell the kernel that userspace queuing is handled by NFQUEUE for the selected protocol. This is 
 made by calling nfq_unbind_pf and nfq_bind_pf with protocol info. The idea behind this is to enable simulataneously loaded modules to be used for queuing*/
    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_INETn");
    if (nfq_bind_pf(h, AF_INET) < 0) {
        fprintf(stderr, "error during nfq_bind_pf()n");
        exit(1);
    }
    /*after the above two steps, we can set up and use a queue*/
    /*bind the program to a specific queue, cb is callback function to call for each queued packet
 *h: netfilter queue handle, 0: the number of the queue to bind to, cb: callback function for each queued packet, data: custom data to pass to callback function*/
    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);
    }
    /*set mode: NFQNL_COPY_PACKET: copy entire packet, it defines the part of data that nfqueue copies to userspace
 0xffff: size of the packet that we want to get*/
    printf("setting copy_packet moden");
    if (nfq_set_mode(qh, NFQNL_COPY_PACKET, 0xffff) < 0) {
        fprintf(stderr, "cannot set packet_copy moden");
        exit(1);
    }
    /*handle the incoming packets*/
    fd = nfq_fd(h);
    while ((rv = recv(fd, buf, sizeof(buf), 0)) && rv >= 0) {
    printf("pkt receivedn");
    nfq_handle_packet(h, buf, rv);
    }
    printf("unbinding from queue 0n");
    nfq_destroy_queue(qh);
    /*the program has finished with libnetfilter_queue, it can call nfq_close to free all associated resources*/
    printf("closing library handlen");
    nfq_close(h);
    exit(0);
}

The code basically use libnetfilter_queue to get the IP datagram of TCP/UDP packets, and retrieve their IP, TCP/UDP checksum. It then use the checksum code we implemented in part 2 to recalculate the checksum. If the calculated the checksum matches with the checksum we retrieved from the original packet, then we’re sure the computation is done correctly.

Compile and Run the Code

To compile the code, you can run the command below,

gcc -Wall -o testsum checksum.c test.c -lnfnetlink -lnetfilter_queue

Note that you’ll need libnfnetlink and libnetfilter_queue to compile the code. Please google for more info.

To run the code, save the following command to run.sh, and then use sudo ./run.sh,

#!/bin/sh
sudo iptables -t mangle –flush
sudo iptables -t mangle -A OUTPUT -p tcp  -j NFQUEUE –queue-num 0
sudo iptables -t mangle -A OUTPUT -p udp -j NFQUEUE –queue-num 0
sudo ./testsum

Note that after you finish running the code and killed the program, you won’t be able to access Internet, you’ll need to run the following command to bring your Internet back,

sudo iptables -t mangle –flush

Note that the above procedure basically set up Linux iptable rules to queue TCP and UDP packets, so the test.c program code can receive them at userspace.

Download

You can download the source code and scripts from here.