Introduction To Network Filters – Linux

One of the great advantages of Linux is its networking features. Many networking products such as routers, switches  are based on Embedded Linux operating system.
Linux is open source so you can see and change the code (under the licensing limitations) and fit it to your needs.

Network filtering is a great infrastructure in Linux kernel, gives us the ability to filter and manipulate packets inside the network stack. You can build a network filter for firewall filtering , log the packets, encrypt/decrypt and more.

We can build the network filter as a kernel module and load/unload it functionality dynamically.

The post assumes you know how to write and load a simple kernel module , if not start with this post

Simple Example:

This is a simple filter example that drops all the packets from IP 192.168.0.2

The module init function register the filter in the input path before routing. To register a filter we need to specify:

  • The hook function – main_hook
  • The socket family (IPv4) – PF_INET
  • The hook type – input path before routing – 0
  • The hook priority – in case we register more than one hook in the same place – NP_IP_PRI_FIRST

The parameters depend on the family – in IPv4 there are 5 points you can register a filter:

  • Input path – before routing
  • Input path – after routing
  • Output path – before routing
  • Output path – after routing
  • Forwarding from one network adapter to another

To build the module we need to configure the kernel with net filter support:

Build the module and test it:

  • Run ping command from IP: 192.168.0.2 – should get correct reply – keep it running
  • Insert the module to the local kernel (insmod ./filter.ko)
  • You shouldn’t  see the reply now
  • Remove the module – again you can see correct reply

 

Each packet is passing through the hook function main_hook.  Lets look inside in more details:

The first parameter is the hook number – we can use the same function for more than one hook for example, if we want to log all the messages in the input and output path before routing

The second parameter is the socket buffer – data structure representing the packet

Next we have tow network adapters – in for input, out for output and both in case of forwarding

The last parameter is a function pointer to the last filter – calling it will cancel all other filters next to this one (this is why we have priorities)

The implementation

We start with setting a pointer to the packet IP header. Now we can access the source and destination IP and all other IP header fields.

Then we check the source address and drop the packet in case it is from 192.168.0.2. In any other case we accept the packet and the next filter will be called

The hook function must return one of the following values:

 

  • NF_DROP – drop the packet – and free the resources
  • NF_ACCEPT – accept the packet – continue to the next filter
  • NF_STOLEN – do not continue processing the packet but don’t free it – it is the my responsibility to free it
  • NF_QUEUE – queue the packet for user space handling
  • NF_REPEAT – call this filter again

User Space Handling

If we return NF_QUEUE , the control is delivered to user space. To implement it in user space we should use the libraries :nfnetlink , netfilter_queue

I will cover the libraries in a future post but for this post this is a very simple example only to understand the concept(without error checks and complex handling):

In the main function we open  the connection , create the queue and register the function filter_fn as our filter, then start a receive loop. In the filter function we can drop or accept the packet

Change the kernel code to return NF_QUEUE:

to build the user space application:

To test the code , build and insert the module and then run the app

 

Tagged , ,

Leave a Reply

Your email address will not be published.