Skip to content

netfilter and iptables

In this laboratory, we will explore the security implications of network connected devices and how to protect them from external attacks. You have a NanoPi device with a buildroot Linux system installed that we will modify to have the relevant tools installed. That is: netfilter and iptables.

Preparation tasks

The goal of this part of the lab is to setup your NanoPi with a newly modified configuration to that you can make use of the said tools.

For this you will need to:

  1. Ensure the target has the appropriate iptables activated in the main buildroot menuconfig

    1. Start the buildroot menu

      make menuconfig​
      

    2. Pick all the libnetfilters

      Target packages -> Libraries -> Networking -> Activate libnetfilter…​
      

    3. Activate iptables

      Target packages -> Networking applications -> iptables
      

  2. Modify the kernel configuration so as to enable netfilter at Core and IP levels.

    1. Start the linux menu and navigate to Networking support -> Networking options -> Network packet filtering framework (Netfilter)

      make linux-menuconfig​
      

    2. Core

      Networking support -> Networking options -> Network packet filtering framework (Netfilter) -> Core Netfilter Configuration -> SELECT ALL
      

    3. IP

      Networking support -> Networking options -> Network packet filtering framework (Netfilter) -> IP: Netfilter Configuration -> SELECT ALL​
      

    Important

    In our case, we will activated all of them!. So, make sure to activate them all so as to avoid wondering why on Earth something is not working.

Make sure your setup works

  1. After having started the board, making sure it is connected to a pc, check the configuration
    ip a
    
  2. Ping your pc with (here it is assumed you have configured your pc with the address 192.68.0.1)
    ping 192.168.0.1
    
  3. Stop pinging and add the command below. Does the ping still work? How can you list the rules that are presently available?
    iptables -A OUTPUT -d 192.168.0.1 -j DROP
    

Success

If your pings did not go through any longer, you made it and are ready for the next step!!! Well done!!! Just make sure you remove the rule with iptables -D OUTPUT -d 192.168.0.1 -j DROP

Warning

Make sure you add your ses_deconfig to your repository with an appropriate tag.

Understanding the commands

The general syntax is

iptables -t table -COMMAND chain  -j TARGET

-t table: 
table=FILTER, MANGLE, NAT,         // FILTER is the default table

-COMMAND chain:
COMMAND: A=append, I=insert, D=delete, C=check, R=replace, L=list, F=flush, P=policy, ..  
Chain: INPUT, OUTPUT, FORWARD

-j TARGET:
TARGET: ACCEPT, DROP, REJECT, NFQUEUE

For a complete list of TARGETs, have a look at “iptables-cheatsheet.md - (courtesy of GH user mcastelino)”.

Hint

No matter what is stated here, do remember that man iptables is your friend! Do remember 3 important things:

  • man iptables is not available on your target
  • Even though ChatGPT/Gemini/… may be (at times) helpful, they are not always available (Cloudflare outage, no Internet connection, …)
  • Most important: you shall always know what you do because you may be opening up a huge security hole if iptables is misconfigured! So, be attentive!

Here a synthesis

  1. List all existing rules in the filter table:

    iptables -L -n -v -t filter  //-n without reverse DNS, v=verbose, vv=more verbose 
    or
    iptables -L -n -v            // Filter is the default table
    iptables -S
    
  2. Flush tables

    iptables -F -t filter
    
    or
    iptables –F
    

  3. Create a new chain

    iptables –N dynamic
    

  4. Append (-A) a new rule

    iptables -A INPUT -s 200.200.200.1 -j DROP  // everything coming from 200.200.200.1
    

  5. Delete (-D) a rule

    iptables -D INPUT -s 200.200.200.1 -j DROP 
    
    or
    iptables –D INPUT 1       // Delete the 1st entry
    

A few examples

Stateless Firewalls

  1. Log and drop all icmp (such as ping) packets (log in the file /var/log/messages)

    iptables -A INPUT -p icmp -j LOG
    iptables -A INPUT -p icmp -j DROP
    
  2. Accept the ssh service form host 10.0.0.1

    iptables -A INPUT -p tcp -s 10.0.0.1 -d 0/0 --dport 22 -j ACCEPT
    

  3. Accept the ssh service form the subnet 10.0.0.x

    iptables -A INPUT -p tcp -s 10.0.0.0/24 -d 0/0 --dport 22 -j ACCEPT
    

  4. Reject all incoming TCP traffic destined for ports 0 to 1023

    iptables -A INPUT -p tcp -s 0/0 -d 0/0 --dport 0:1023 -j REJECT
    

  5. Reject all outgoing TCP traffic except the one destined for 10.0.0.1

    iptables -A OUTPUT -p tcp -s 0/0 -d ! 10.0.0.1 -j REJECT
    

  6. Drop all SYN packets from 10.0.0.1

    iptables -A INPUT -p tcp -s 10.0.0.1 -d 0/0  --syn -j DROP
    

  7. Change the FORWARD chain to an ACCEPT policy (default rule)

    iptables -P FORWARD ACCEPT
    

    Note

    Default policies set with -P are only applied if no rule in the chain matches. If a packet matches a rule earlier in the chain, that rule’s target is used instead of the default policy.

  8. Block a incoming telnet only for the port ppp0

    iptables -A INPUT -p tcp --destination-port telnet -i ppp0 -j DROP
    

Stateful Firewalls

iptables can use extended packet matching modules with the -m or --match options, followed by the matching module name. Check https://ipset.netfilter.org/iptables-extensions.man.html for a full list of modules that can be used.

  1. Basic Stateful Firewall example uses the extended packet matching conntrack

    iptables -F           //Flush the table FILTER
    iptables -A OUTPUT -m conntrack --ctstate NEW,ESTABLISHED,RELATED -j ACCEPT
    iptables -A OUTPUT -j DROP  // drop other packet
    iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
    iptables -A INPUT -j LOG
    iptables -A INPUT -j DROP  // drop other packet
    

    Info

    Note that iptables -A INPUT -j LOG means that logging happens only for packets that are not ESTABLISHED or RELATED.

  2. Obviously, the examples from above can be used as well.

Let’s go a bit further - a few questions to you

The following questions shall be realized on the target you hold in your hands.

Question

Warning

Before answering, make sure you add your ses_deconfig to your repository with an appropriate tag.

  1. Configure your NanoPI so that all incoming ICMP are

    • logged
    • dropped

    Make sure you write down the commands used for executing the above.

  2. Configure your NanoPI so that all incoming ‘ICMP’ messages are

    • logged
    • rejected

    What commands did you use? What difference(s) have you observed compared to the previous configuration?

  3. How can you check what services are presently activated on your NanoPI?

    Hint

    Check what the netstat command is capable of doing. Eventually, also have a look at watch for continuous monitoring.

  4. Assuming the following situation

     ----               eth0 --------
    | PC | ---------------->| NanoPI | 
     ----                    --------
    192.168.0.1              192.168.0.14
    

    Configure you NanoPI so that

    • all new incoming ssh connections are accepted (from PC to NanoPI)
    • all local connections are accepted (local means using the loopback interface lo0)
    • all other communication (be that FORWARD, OUTPUT or INPUT) is dropped
  5. Assuming the following situation

     ----               eth0 --------
    | PC | ---------------->| NanoPI | 
     ----                    --------
    192.168.0.1              192.168.0.14
    

    Configure you NanoPI so that

    • all new incoming and outgoing ssh connections are accepted (from NanoPI standpoint)
    • all local connections are accepted (local means using the loopback interface lo0)
    • all other communication (be that FORWARD, OUTPUT or INPUT) is dropped
  6. Given the following configuration

    iptables –A INPUT -i lo –j ACCEPT        // Local traffics are allowed between applications
    iptables –P INPUT DROP
    iptables –P OUTPUT ACCEPT
    iptables –P FORWARD DROP
    iptables -N dynamic
    iptables -N net2fw            // New chain: Network to Firewall
    
    iptables -A INPUT -i eth0 -j net2fw
    iptables -A net2fw -m conntrack --ctstate NEW -j dynamic
    iptables -A net2fw -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
    iptables -A net2fw -p tcp -m tcp --dport 62200 -j ACCEPT
    iptables -A net2fw -j LOG --log-prefix "net2fw:DROP:" --log-level 6
    iptables -A net2fw -j DROP
    

    Can you

    • explain what rules are triggered when a connection to port 62200 is attempted?
    • rewrite it in a “safer” manner? (that is, more structured and less error prone)
  7. Can you find how many hooks there are, and in what files, in the kernel version your NanoPI is running? Find “only” the IPv4 ones.

    Hint

    Check the occurrences of the hook in output/build/linux-6.3.6/net/ipv4.

Let’s programme! Making use of NFQUEUE target

You are now about to implement a small programme that makes use of NFQUEUE capabilities to explore what one can do with it.

To do so

  1. Take the following code and save it in a .c file (say test.c):

    #include <stdint.h>
    #include <stdio.h>
    #include <stdlib.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>
    
    static uint32_t print_pkt(struct nfq_data *tb);
    static int callback(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg,
                        struct nfq_data *nfa, void *data);
    
    int main(int argc, char **argv)
    {
    struct nfq_handle *h;
    struct nfq_q_handle *qh;
    int fd, rv;
    char buf[4096] __attribute__ ((aligned(4)));
    
        h = nfq_open();                    //opening library handle
        nfq_unbind_pf(h, AF_INET);         //unbinding existing nf_queue handler for AF_INET
    
        nfq_bind_pf(h, AF_INET);           // binding nfnetlink_queue as nf_queue handler for AF_INET
        qh = nfq_create_queue(h,  0, &callback, NULL); // binding this socket to queue '0'
    
        nfq_set_mode(qh, NFQNL_COPY_PACKET, 0xffff); // setting copy_packet mode
        fd = nfq_fd(h);
        while ((rv = recv(fd, buf, sizeof(buf), 0)) && rv >= 0) {
           printf("pkt received\n");
           nfq_handle_packet(h, buf, rv);
        }
        nfq_destroy_queue(qh);
        nfq_close(h);
        exit(0);
    }
    
    static u_int32_t print_pkt (struct nfq_data *tb)
    {
        int id = 0;
        struct nfqnl_msg_packet_hdr *ph;
        ph = nfq_get_msg_packet_hdr(tb);
        if (ph) {
           id = ntohl(ph->packet_id);
           printf("hw_protocol=0x%04x hook=%u id=%u \n ",ntohs(ph->hw_protocol), ph->hook, id);
        }
        return id;
    }
    
    static int callback(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_data *nfa, void *data)
    {
       u_int32_t id = print_pkt(nfa);
       printf("entering callback\n");
       return nfq_set_verdict(qh, id, NF_ACCEPT, 0, NULL);
    }
    

  2. Once you are ready with your file, you can compile it to generate the nfq-icmp programme using the toolchain you created.

    ./output/host/bin/aarch64-buildroot-linux-gnu-gcc -Wall -o nfq-icmp test.c -Ioutput/host/aarch64-buildroot-linux-gnu/sysroot/usr/include -Loutput/host/aarch64-buildroot-linux-gnu/sysroot/usr/lib -lnetfilter_queue
    

    Warning

    Note: you may have called the c file differently - it is called test.c above - and shall make sure it aligns with your version.

    Info

    Thanks to -I and L we pass explicit include/lib paths.

  3. Download it to your target (e.g. using scp) and run it. Do remember to instantiate the corresponding queue prior to answering the questions below.

Question

Transfer the programme to the NanoPI target and write down

  • what commands you used to transfer the file and launch it
  • what results you observed when issuing ping 192.168.0.14 from your pc (assuming you have not changed the IP address of your NanoPI)
  • what would you need to do in case you wanted, after having printed the packet content, DROP all packets? What would be the effect on the recipient of the ICMP response?

Hint

Do not forget to create the NFQUEUE prior to launching the programme.



INTERESTING USE

For those who would like to understand how iptables can be used in a way larger scale to defend against massive attacks, have a look at Cloudflare’s presentation titled Defending from DDoS Attacks - youtube.com.