Linux NAT Using Conntrack and IPtables

.

Doing the Network Address Translation (NAT) into Linux kernel scales the performance up. This mechanism consists of two parts:

The Connection Tracking/Conntrack Modules

It is a tracking technique of the connections. It is used to know how the packets that pass through the system are related to their connections. The connection tracking does NOT manipulate the packets and It works independently of the NAT module. The conntrack entry looks like:

udp 17 170 src=192.168.1.2 dst=192.168.1.5 sport=137 dport=1025 src=192.168.1.5 dst=192.168.1.2 sport=1025 dport=137 [ASSURED] use=1

The conntrack entry is stored into two separate tuples (one for the original direction (red) and another for the reply direction (blue)). Tuples could belong to different linked lists/buckets in conntrack hash table. The connection tracking modules is responsible for creating and removing the tuples.

Note: The tracking of the connections is ALSO used by iptables to do packet matching based on the connection state.

The NAT Modules

The NAT modules do the NATing itself. They use the tuples and modify them based on the NATing rules. In this way the tuples in the connection tracking table remains in consistent state.

nat

If the packet belongs to an existing connection, this means there is already a conntrack entry (two tuples) in the conntrack table. The NAT module knows this by checking a field in the tuple created for the new arrived packet. Then the packet manipulation is done based on the conntrack entry (The manipulation is determined previously).

If the received packet represents a start of a new connection (first packet), the NAT module looks for a rule in the “NAT” table. If a rule is found, the NAT manipulation will be applied based on the rule and the tuples in the conntrack table will be changed. The tuples are created by conntrack at local outtput hook point before NAT for SNAT (Source NAT) so they need to be updated after doing the NAT for the first packet.

Assume the packets are leaving on network interface “eth1″(-o means “output”) to the internet and the interface “eth0” is connected to the local network. To change the source addresses to 1.2.3.4  and the ports 1-1023, you can add this rule:

# iptables -t nat -A POSTROUTING -p tcp -o eth1 -j SNAT –to 1.2.3.4:1-1023

You can specify a range of IP addresses as well (SNAT –to 1.2.3.4-1.2.3.6).

You can also use what is called MASQUERADE where the the sender’s address is replaced by the router’s address.

# iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE

Note: Here i am doing SNAT (Source NAT). You can also do Destination NAT (DNAT) where the conntrack hooks into pre routing hook point. To write DNAT rules, use the chain  PREROUTING and the target DNAT.

NAT Settings

  • You need to load the “nf_conntrack”: # modprobe nf_conntrack
  • You need to start iptables service: # systemctl start iptables
  • You need to enable IP_Forwarding:
    • Temporarily: # echo “1” > /proc/sys/net/ipv4/ip_forward
    • Permanently:  Write net.ipv4.ip_forward = 1 in the file “/etc/sysctl.conf ” and reload (# sysctl -p).
  • Then set NATing rules as mentioned above.
  • Add Forwarding rules to forward packets from one interface to another in both direction:

From the public (interface:eth1) to private(interface eth0):

# iptables -A FORWARD -i eth1 -o eth0 -m state –state RELATED,ESTABLISHED -j ACCEPT

From private(eth0) to public(eth1):

# iptables -A FORWARD -i eth0 -o eth1 -j ACCEPT

  • Finally you need to save the IPtables rules to be persistent: # iptables-save

Note

  • If you got this error “nf_conntrack: table full, dropping packet“ and you have enough free memory , you can expand the size of conntrack table, click here.

More Information


RTPEngine Manual Compilation and Installation In Fedora RedHat

.

RTPEngine Main Features

  • OpenSource and free
  • Media traffic running over either IPv4 or IPv6
  • Bridging between IPv4 and IPv6 user agents
  • TOS/QoS field setting
  • Customizable port range
  • Multi-threaded
  • Advertising different addresses for operation behind NAT
  • In-kernel packet forwarding for low-latency and low-CPU performance
  • Automatic fallback to normal userspace operation if kernel module is unavailable
  • OpenSIPS/Kamailio Support.

Installation and Compilation

1- Install The Packages Required To Compile The Daemon:

# yum install glib glib-devel gcc zlib zlib-devel openssl openssl-devel pcre pcre-devel libcurl libcurl-devel xmlrpc-c xmlrpc-c-devel

Note: glib version must be higher than 2.0. Note in the Makefile of the daemon: CFLAGS+= `pkg-config –cflags glib-2.0`

2- Get The Latest Release Of RTPEngine Source From RTPEngine’s GitHub Repository:

Go to the place where “GitHub.com” is remotely storing RTPEngine and get the RTPEngine ‘s repo HTTP-address “https://github.com/sipwise/rtpengine.git“. Then clone the repo.

# git clone https://github.com/sipwise/rtpengine.git

Install redis client and server (If you want to have it on the same server):

# yum install  hiredis hiredis-devel redis

Be sure the server is running: # systemctl status redis

3- Compile The Daemon:

# cd /usr/local/src/rtpengine/daemon
# make

Now the daemon is compiled and we have the executable file rtpengine. Copy this file to /usr/sbin:

 # cp rtpengine /usr/sbin/rtpengine

4- Compile IPtables-Extension “libxt_RTPENGINE” Which Is User-Space Module Used For “In-Kernel” Packet Forwarding (Adding the forwarding rules):

  • Install IPtables development headers: # yum install iptables-devel
  • Compile the iptables extension

# cd /usr/local/src/rtpengine/iptables-extension

# make

After compilation we get the plugin “libxt_RTPENGINE.so” (user-space module). Copy this file to “/lib/xtables/” or “/lib64/xtables/” (see your system):

# cp libxt_RTPENGINE.so /lib64/xtables

5- Compile The Kernel Module “xt_RTPENGINE” Required For In-Kernel Packet Forwarding:

To compile a kernel module, we need the kernel development headers to be installed in “/lib/modules/$VERSION/build/” where VERSION is the kernel version. To know the kernel version, execute  “uname -r”. Here i have 3.11.10-301.fc20.x86_64 so the kernel headers must be here “/lib/modules/3.11.10-301.fc20.x86_64/build/”. where 3.11.10-301.fc20.x86_64 is the kernel that we compile the module with. To install the header files of specific kernel: # yum install kernel-devel-$(uname -r)

Then:

# cd /usr/local/src/rtpengine/kernel-module

# make

After compilation we get this file “xt_RTPENGINE.ko” which is a kernel module. Copy this module into “/lib/modules/3.11.10-301.fc20.x86_64/extra”.

# cp xt_RTPENGINE.ko /lib/modules/3.11.10-301.fc20.x86_64/extra

After this creates a list of module dependencies and add the list to “modules.dep”:

# depmod  /lib/modules/3.11.10-301.fc20.x86_64/extra/xt_RTPENGINE.ko
or for all modules:
# depmod -a

Note: Instead of manually coping the module to extra sub-folder and create the list of dependencies by calling “depmod”, you can add modules_install rule in the Makefile. This will copy the file to “extra” and create the dependencies list:

modules_install:

make -C $(KSRC) M=$(PWD) modules_install

and execute: # make modules_install

Load the module:

You need to boot from the kernel that you compiled the module against. Then yo can load the module as following:

# modprobe xt_RTPENGINE

To check if the module is loaded: # lsmod |grep xt_RTPENGINE

Output: xt_RTPENGINE           27145  0

After the module has been loaded, a new directory called /proc/rtpengine will appear. In this directory you find  two files: control (write-only, used for creating and deleting the forwarding tables) and list (read-only, list the current forwarding tables, it could be an empty list):

 # ls -l   /proc/rtpengine/control

–w–w—-. 1 root root 0 Oct 16 11:54 /proc/rtpengine/control

 # ls -l   /proc/rtpengine/list

 -r–r–r–. 1 root root 0 Oct 16 11:55 /proc/rtpengine/list

To add a forwarding table (done by the daemon) with an ID=$TableID (number between 0-63):

# echo ‘add $TableID’ > /proc/rtpengine/control

The folder  /proc/rtpengine/$TableID will be created. It will contain these files: blist (read-only), control (write-only, used by the daemon to update the forwarding rules), list (read-only), and status (read-only).

To delete a table: # echo ‘del $TableID’ > /proc/rtpengine/control

You can delete the table if it is not used by the rtpengine (the rtpengine is not running).

To display the list of the current tables: # cat /proc/rtpengine/list

You can unload the kernel module “xt_RTPENGINE” when there is no related iptables rules or forwarding tables:

# rmmod xt_RTPENGINE

Adding iptables rules to forward the incoming packets to xt_RTPENGINE module

# iptables -I INPUT -p udp -j RTPENGINE –id $TableID

# ip6tables -I INPUT -p udp -j RTPENGINE –id $TableID

Start The Daemon

Recommendation: Start the RTPEngine as systemd service with a configuration file to specify the options. Click here. Otherwise continue:

# ./rtpengine ….Options…..

Example:

# rtpengine –table=TableID –interface=$IPAddress –listen-ng=127.0.0.1:2223 –pidfile=/var/run/rtpengine.pid –no-fallback

For logging to file:

  • When you start rtpengine, add the options: log-level and log-facility:

# rtpengine –table=$TableID –interface=127.0.0.1 –listen-ng=127.0.0.1:2223 –pidfile=/var/run/rtpengine.pid –no-fallback –log-level=3  –log-facility=local1

The max value of log-level is 7

  • Assuming the /var/log/rtpengine.log will be the log file:

# vim  /etc/rsyslog.conf and add this entry:

local1.*                        /var/log/rtpengine.log

For the connection with Redis database:

  • Check the IP and the port of the Redis server: #  netstat -lpn |grep redis
  • Add the following options when you start the RTPEngine: –redis=IP:PORT and –redis-db=INT

See the list of command-line options in the project’s GitHub repository page. There you can find explanation about all RTPEngine’s stuffs with examples.


More Information