This guide will show you how to configure Snort to run inline using the NFQUEUE DAQ (referred to as NFQ). This allows your Snort server to use iptables to route traffic between any number of subnets, with Snort evaluating all traffic passing through the system. This guide will assume some knowledge of routing and IP addressing, especially as it is implemented under Linux, as well as some experience setting up Snort. Configuring Snort as an inline NIPS with NFQ is more complicated than setting snort up as a NIDS, and is more complicated than setting up Snort as a NIPS using the AFPACKET DAQ. The complexity is due to the use of iptables and the need to understand IP routing. I will assume that you have installed Snort before, so I may gloss over some concepts and explanations in this guide. If you find yourself having difficult with installing and configuring Snort, I recommend you first work through my complete guide on installing Snort which should give you a good foundation on understanding how to install and configure Snort.
This guide has been written and tested on Ubuntu 16 x64. It should work on most currently supported versions of Ubuntu and Debian derivatives, but your mileage may vary.
On Ubuntu, you can run Snort two different ways in inline mode, with AFPACKET or with NFQ. AFPACKET is simpler to setup (see my guide here), but only lets you bridge sets of paired interfaces. This means you can bridge eth0 with eth1 (pass traffic between them), and also bridge eth2 with eth3, but you can not pass traffic between eth0 and eth4. A benefit of AFPACKET is that you can install an inline Snort machine without any changes to IP addressing, routing, or networking changes. NFQ on the other hand lets you leverage the power of iptables to make routing decisions. It’s more complicated to setup (it requires you as a systems administrator to understand Linux routing), but is more powerful for network security. You can also use iptables to blottck traffic before Snort even sees it (to filter out noisy traffic sources), or use additional tools that interface with iptables to increase security (like psad or fwsnort).
Enabling NFQ with IPv6 is very similar to IPv4, the only thing to note is that you will have to run a separate instance of Snort to process IPv6 packets, and setup another iptables rule to forward IPv6 packets to a second NFQUEUE using the ip6tables command. Essentially you follow this guide twice, once for IPv4, and once for IPv6, making changes as necessary.
This guide will go through the following steps:
One thing to note: for simplicity, we will enable routing for all traffic passing through the system before we lock down the firewall rules. Because of this, I highly recommend that you test this on a development network to understand how it works before you implement on a production network. In a real environment, you would want your firewall rules in place before you enabled routing of traffic on a device that bridged networks with different security levels. For this guide, it’s much simpler to apply firewall rules at the end for the purpose of learning. I have noted a number of excellent online resources and books at the end of this guide to help understand networking, iptables, and network security.
For this guide, we will use the following network, with our Snort router having three interfaces on three different networks:
The 172.16.0.0/24 network is our internal admin or management network, and will not be routed by Snort. No traffic should pass between the 172.16.0.0 network and the other networks. This is how we will SSH into this snort system for management purposes, and if configured: Snort could send log data back to a logging server on this network. It is good practice to keep a separate network (through VLANS or separate hardware) for management purposes. We won’t lock down this network at first, but will apply firewall rules at the end of this article to prevent traffic from entering this network across our Snort router.
The 10.0.0.0/24 network is our outbound network. All traffic not destined for a locally connected network will be directed out this network to the next hop gateway (in this case the ISP router). Note that the computer on this network has the Snort router as it’s default gateway. While this works, normally you’d configure the computer to have the actual external gateway (10.0.0.1 in this case) as the gateway. It’s set this way to simplify testing.
The 192.168.0.0/24 network is our client network (screened subnet). Hosts will be configured on this network to use the Snort server as it’s gateway. Traffic passing between this network and the 10.0.0.0 network will be scanned by Snort, and will be dropped and/or logged if suspicious.
Because this server is running Ubuntu 16, the interface names no longer follow the ethX standard (eth0, eth1, …). Instead, interfaces names are assigned as Predictable Network Interface Names. This means you need to check the names of your interfaces using ifconfig -a. In my case, what was originally eth0 is now ens160.
Since you are using your Snort system as a router, you’ll want static interfaces on each address. You don’t want dynamic (DCHP) addresses for the interfaces on this system because any clients on that subnet will use the IP address of the Snort system as their gateway. For any interface that Snort will process traffic on, you need to disable LRO and GRO (there’s an explanation of this in my complete guide on installing Snort). For any interface that sends traffic to an external network, you’ll need a gateway configured.
Edit /etc/network/interfaces as an admin:
sudo vi /etc/network/interfaces
Configure your network interfaces:
# Routed subnet auto ens160 iface ens160 inet static address 10.0.0.2 netmask 255.255.255.0 network 10.0.0.0 broadcast 10.0.0.255 gateway 10.0.0.1 post-up ethtool -K ens160 gro off post-up ethtool -K ens160 lro off # Host Subnet (internal network / screened subnet) auto ens224 iface ens224 inet static address 192.168.0.2 netmask 255.255.255.0 network 192.168.0.0 broadcast 192.168.0.255 # no gateway required post-up ethtool -K ens160 gro off post-up ethtool -K ens160 lro off # Management Subnet (internal network, not routed) auto ens192 iface ens192 inet static address 172.16.0.2 netmask 255.255.255.0 network 172.16.0.0 broadcast 172.16.0.255 # no gateway # snort not processing traffic on this interface, so no need to disable LRO or GRO
Because we don’t have additional subnets connected to the 192.1668.0.0 or 172.16.0.0 networks, we don’t need to specify any routes. We only configured one gateway on this system (10.0.0.1), so all traffic not destined to a local subnet will be sent to that gateway. To verify, use the ip route command:
noah@snort-router:~ $ ip route default via 10.0.0.1 dev ens160 onlink 10.0.0.0/24 dev ens160 proto kernel scope link src 10.0.0.2 172.16.0.0/24 dev ens192 proto kernel scope link src 172.16.0.2 192.168.0.0/24 dev ens224 proto kernel scope link src 192.168.0.2
If you have multiple subnets configured off of one of those other two subnets, you would need to add a gateway for that subnet in your interfaces file, and you would need to add a static route.
Sidebar: A more complicated example (don’t follow these steps unless you have more complicated routing needs): if you had the 192.168.99.0/24 subnet connected to your 192.168.0.0/24 subnet, reachable through 192.168.0.3, as shown highlighted in red in the image below:
you would need to add two commands to the network interface for ens224: One to specify a gateway, and one to add this route. Since you now have multiple gateways on your Snort server, you want to tell the system which gateway is the default gateway (the gateway for all traffic that it does not have an explicit route for). Interface ens224 on the snort server would now look like:
# Host Subnet (internal network / screened subnet) # Additional routing example auto ens224 iface ens224 inet static address 192.168.0.2 netmask 255.255.255.0 network 192.168.0.0 broadcast 192.168.0.255 gateway 192.168.0.3 post-up ethtool -K ens160 gro off post-up ethtool -K ens160 lro off up ip route add 192.168.99.0/24 via 192.168.0.3 || true
While ens160 with the default route will look like:
# Routed subnet # Additional routing example auto ens160 iface ens160 inet static address 10.0.0.2 netmask 255.255.255.0 network 10.0.0.0 broadcast 10.0.0.255 gateway 10.0.0.1 post-up ethtool -K ens160 gro off post-up ethtool -K ens160 lro off up ip route add default via ens160 || yes
At this time, you should verify that you can ping hosts in every network from your Snort server, as well as external hosts via your gateway. Use the ip route commmand as well as tracepath to verify this is setup right. Do not continue until all this is working.
At this point, even though the system can reach all connected networks, the system will not pass traffic between the networks. Traffic from a host on the management network can not reach any hosts on the screened network, and vice versa. This is by design. Enabling this is easy, however you may want to restrict traffic between certain networks before enabling this option, for security purposes. For simplicity, we will not enable firewall rules at this time, so if your system is a live system connected to both internal sensitive networks and public networks, you may want to read through the entire article first to understand how to add firewall rules to protect the system before enabling routing.
Use vi to edit /etc/sysctl.conf
Un-comment the line:
net.ipv4.ip_forward=1
Reboot the system. At this time, you should now be able to ping between two devices connected to different networks. If your routing is setup correctly, you should be able to ping out the default route as well. If pinging between locally connected subnets work, but you can’t ping to external subnets, you probably need to look at the routing further down the line, do those devices have a path back to your locally connected subnets? If you have a large network, you may want to look at enabling a routing protocol on your Snort server to exchange routing information (probably OSPF or RIP, depending on you network configuration and level of comfort).
If you have a Snort system up and running, you will probably need to re-compile DAQ and Snort for this guide. The reason is that to enable NFQ, you need to install libraries prior to compiling DAQ.
Start by installing all pre-requisites for Snort:
sudo apt-get install -y build-essential libpcap-dev libpcre3-dev libdumbnet-dev bison flex zlib1g-dev liblzma-dev openssl libssl-dev
We need the development libraries for Nghttp2. On Ubuntu 16 this is simple:
# Ubuntu 16 only (not Ubuntu 14) sudo apt-get install -y libnghttp2-dev
On Ubuntu 14, we do this from scratch:
# Ubuntu 14 only (not Ubuntu 16) sudo apt-get install -y autoconf libtool pkg-config cd ~/snort_src wget https://github.com/nghttp2/nghttp2/releases/download/v1.17.0/nghttp2-1.17.0.tar.gz tar -xzvf nghttp2-1.17.0.tar.gz cd nghttp2-1.17.0 autoreconf -i --force automake autoconf ./configure --enable-lib-only make sudo make install
Finally we need the NFQ specific libraries:
sudo apt-get install libnetfilter-queue-dev
We will make a directory for all the source tarball files:
mkdir ~/snort_src cd ~/snort_src
Download and install Data Acquisition library (DAQ) from the Snort website:
cd ~/snort_src wget https://www.snort.org/downloads/snort/daq-2.0.6.tar.gz tar -xvzf daq-2.0.6.tar.gz cd daq-2.0.6 ./configure make sudo make install
after the ./configure option, you will see the DAQ modules that are enabled. You must have NFQ enabled here, as seen below:
Build AFPacket DAQ module.. : yes Build Dump DAQ module...... : yes Build IPFW DAQ module...... : yes Build IPQ DAQ module....... : no Build NFQ DAQ module....... : yes <<<<< MUST BE YES Build PCAP DAQ module...... : yes Build netmap DAQ module.... : no
Now we are ready to install Snort from source:
cd ~/snort_src wget https://snort.org/downloads/snort/snort-2.9.9.0.tar.gz tar -xvzf snort-2.9.9.0.tar.gz cd snort-2.9.9.0 ./configure --enable-sourcefire make sudo make install
Run the following command to update shared libraries:
sudo ldconfig
Since the Snort installation places the Snort binary at /usr/local/bin/snort, it is common to create a symlink to /usr/sbin/snort:
sudo ln -s /usr/local/bin/snort /usr/sbin/snort
The last step of our Snort installation is to test that the Snort binary runs. Execute Snort with the -V flag, which causes Snort to print the current version. You should see output similar to the following:
noah@snort-router:~ $ snort -V ,,_ -*> Snort! <*- o" )~ Version 2.9.9.0 GRE (Build 56) '''' By Martin Roesch & The Snort Team: http://www.snort.org/contact#team Copyright (C) 2014-2016 Cisco and/or its affiliates. All rights reserved. Copyright (C) 1998-2013 Sourcefire, Inc., et al. Using libpcap version 1.7.4 Using PCRE version: 8.38 2015-11-23 Using ZLIB version: 1.2.8 noah@snort-router:~ $
Now we want to verify that Snort can see the NFQ DAQ. We do this by running snort with the –daq-list flag:
noah@snort-router:~ $ snort --daq-list Available DAQ modules: pcap(v3): readback live multi unpriv nfq(v7): live inline multi <<<<<< Need this line ipfw(v3): live inline multi unpriv dump(v3): readback live inline multi unpriv afpacket(v5): live inline multi unpriv
At this point, Snort has been compiled and installed with the NFQ DAQ. Next is configuration.
Most of this configuration comes from my longer articles on installing Snort. I’ll skip over some of the details of certain steps, but more in-depth information is available in my full Snort install guide. First off, for security reasons we want Snort to run as an unprivileged user. We create a snort user and group for this purpose:
sudo groupadd snort sudo useradd snort -r -s /sbin/nologin -c SNORT_IDS -g snort
Next, we need to create a number of files and folders that Snort expects when running in NIDS mode. We will then change the ownership of those files to our new snort user:
# Create the Snort directories: sudo mkdir /etc/snort sudo mkdir /etc/snort/rules sudo mkdir /etc/snort/rules/iplists sudo mkdir /etc/snort/preproc_rules sudo mkdir /usr/local/lib/snort_dynamicrules sudo mkdir /etc/snort/so_rules # Create some files that stores rules and ip lists sudo touch /etc/snort/rules/iplists/black_list.rules sudo touch /etc/snort/rules/iplists/white_list.rules sudo touch /etc/snort/rules/local.rules sudo touch /etc/snort/sid-msg.map # Create our logging directories: sudo mkdir /var/log/snort sudo mkdir /var/log/snort/archived_logs # Adjust permissions: sudo chmod -R 5775 /etc/snort sudo chmod -R 5775 /var/log/snort sudo chmod -R 5775 /var/log/snort/archived_logs sudo chmod -R 5775 /etc/snort/so_rules sudo chmod -R 5775 /usr/local/lib/snort_dynamicrules # Change Ownership on folders: sudo chown -R snort:snort /etc/snort sudo chown -R snort:snort /var/log/snort sudo chown -R snort:snort /usr/local/lib/snort_dynamicrules
We now need to move the following files from the extracted Snort tarball to the snort configuration folder:
cd ~/snort_src/snort-2.9.9.0/etc/ sudo cp *.conf* /etc/snort sudo cp *.map /etc/snort sudo cp *.dtd /etc/snort cd ~/snort_src/snort-2.9.9.0/src/dynamic-preprocessors/build/usr/local/lib/snort_dynamicpreprocessor/ sudo cp * /usr/local/lib/snort_dynamicpreprocessor/
Disable all rule files:
sudo sed -i 's/include \$RULE\_PATH/#include \$RULE\_PATH/' /etc/snort/snort.conf
Now We need to edit our snort configuration file:
sudo vi /etc/snort/snort.conf
Set your internal networks here. I am choosing to have Snort consider the 192.168.0.0 and 172.16.0.0 networks as internal networks. This maters for rule processing, where many rules look for attacks against computers in your HOME_NET subnet ranges:
# line 45 (no spaces between IP addresses) ipvar HOME_NET [192.168.0.0/24,176.16.0.0/24]
Next we need to tell Snort about the locations of all the folders we created earlier. I have included the line numbers after the hash so you can more easily find the setting (do not write the line number, just change the path to match what is below):
var RULE_PATH /etc/snort/rules # line 104 var SO_RULE_PATH /etc/snort/so_rules # line 105 var PREPROC_RULE_PATH /etc/snort/preproc_rules # line 106 var WHITE_LIST_PATH /etc/snort/rules/iplists # line 113 var BLACK_LIST_PATH /etc/snort/rules/iplists # line 114
Enable the Local rules file. Un-comment the following line (line 545) by deleting the hash from the beginning of the line:
include $RULE_PATH/local.rules
Now we need to configure Snort to use the NFQ DAQ an run inline mode. You can choose to pass these options from the command line, but it’s neater to do it here in the configuration file. Add the following three lines to enable the NFQ DAQ in inline mode, looking at NFQ queue number 4 for packets (we will configure iptables later to pass all routed packets to this same numbered queue):
# at line 168, add the following new lines: config daq: nfq config daq_mode: inline config daq_var: queue=4
Save the file, and now we need to test the configuration. To test: we run the following command. The T flag indicates we want to test, the c flag specifies the snort.conf file, and the Q flag tells snort that we’re working in inline mode (required later for Drop rules to actually drop, instead of just alerting):
$ sudo snort -T -c /etc/snort/snort.conf -Q
You should have similar output to the following (truncated for clarity):
Enabling inline operation Running in Test mode ... nfq DAQ configured to inline. Decoding Raw IP4 --== Initialization Complete ==-- ,,_ -*> Snort! <*- o" )~ Version 2.9.9.0 GRE (Build 56) '''' By Martin Roesch & The Snort Team: http://www.snort.org/contact#team Copyright (C) 2014-2016 Cisco and/or its affiliates. All rights reserved. Copyright (C) 1998-2013 Sourcefire, Inc., et al. Using libpcap version 1.7.4 Using PCRE version: 8.38 2015-11-23 Using ZLIB version: 1.2.8 Rules Engine: SF_SNORT_DETECTION_ENGINE Version 3.0 <Build 1> Preprocessor Object: SF_SIP Version 1.1 <Build 1> Preprocessor Object: SF_SSLPP Version 1.1 <Build 4> Preprocessor Object: SF_SDF Version 1.1 <Build 1> Preprocessor Object: SF_SMTP Version 1.1 <Build 9> Preprocessor Object: SF_GTP Version 1.1 <Build 1> Preprocessor Object: SF_DNP3 Version 1.1 <Build 1> Preprocessor Object: SF_DCERPC2 Version 1.0 <Build 3> Preprocessor Object: SF_DNS Version 1.1 <Build 4> Preprocessor Object: SF_POP Version 1.0 <Build 1> Preprocessor Object: SF_IMAP Version 1.0 <Build 1> Preprocessor Object: SF_MODBUS Version 1.1 <Build 1> Preprocessor Object: SF_FTPTELNET Version 1.2 <Build 13> Preprocessor Object: SF_SSH Version 1.1 <Build 3> Preprocessor Object: SF_REPUTATION Version 1.1 <Build 1> Snort successfully validated the configuration! Snort exiting
If you are seeing similar output, then you’re in a good place. If not, troubleshoot the errors (usually Snort will output line number where the error was found) before continuing.
We will add a simple rule to detect ICMP traffic to verify that we’re detecting and passing traffic correctly. Add the following to our local.rules file:
/etc/snort/rules/local.rules:
alert icmp any any -> $HOME_NET any (msg:"ICMP test detected"; GID:1; sid:10000001; rev:001; classtype:icmp-event;)
Since we have made changes to the file that snort loads (local.rules), it is a good idea to test the configuration file again:
sudo snort -T -c /etc/snort/snort.conf -Q
If successful, you should be able to scroll up through the output and see that Snort has loaded our one rule:
+++++++++++++++++++++++++++++++++++++++++++++++++++ Initializing rule chains... 1 Snort rules read 1 detection rules 0 decoder rules 0 preprocessor rules 1 Option Chains linked into 1 Chain Headers 0 Dynamic rules +++++++++++++++++++++++++++++++++++++++++++++++++++ +-------------------[Rule Port Counts]--------------------------------------- | tcp udp icmp ip | src 0 0 0 0 | dst 0 0 0 0 | any 0 0 1 0 | nc 0 0 1 0 | s+d 0 0 0 0 +----------------------------------------------------------------------------
I will assume you don’t have any entries in your iptables at this time. You can verify with the following command:
$ sudo iptables -L
which should show the following output:
Chain INPUT (policy ACCEPT) target prot opt source destination Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination
We want to add a rule to our iptables that makes every packet that is going to be forwarded (not destined for local delivery) to be scanned by Snort. To do this, we add a single rule that moves all forwarded traffic (from the FORWARD queue) to NFQUEUE queue number 4, which is the same queue we specified in our snort.conf configuration above, where Snort is listening for it (I chose queue 4 arbitrarily, you could use any number, as long as it matched the snort.conf queue). To add this rule to the FORWARD chain, we run the following:
sudo iptables -I FORWARD -j NFQUEUE --queue-num=4
Since Snort is not running right now, the system will deliver traffic to that queue, but it will not be processed and will drop (we can change this later to a fail-open option if wanted). Let’s run Snort with the following flags to see traffic being processed:
-A console the console option prints fast mode alerts to stdout -q Quiet. Don't show banner and status report. -u snort run snort as the following user after startup -g snort run snort as the following group after startup -c /etc/snort/snort.conf the path to our snort.conf file -Q Run inline mode (required to drop packets)
Run Snort with the command below:
sudo /usr/local/bin/snort -A console -q -u snort -g snort -c /etc/snort/snort.conf -Q
If you ping from one machine to another machine, you should see alerts show on your snort machine. You can’t ping to or from the snort machine directly, because this rule only looks at traffic not destined for the local machine.
06/07-14:38:16.275283 [**] [1:10000001:1] ICMP test detected [**] [Classification: Generic ICMP event] [Priority: 3] {ICMP} 10.0.0.88 -> 192.168.0.10 06/07-14:38:17.274174 [**] [1:10000001:1] ICMP test detected [**] [Classification: Generic ICMP event] [Priority: 3] {ICMP} 10.0.0.88 -> 192.168.0.10 06/07-14:38:18.273215 [**] [1:10000001:1] ICMP test detected [**] [Classification: Generic ICMP event] [Priority: 3] {ICMP} 10.0.0.88 -> 192.168.0.10
You have to use ctrl-c to stop snort from running after the above output.
To test that snort will Drop rather than just alert on your rules, edit your local.rules and replace the first word “alert” with “drop”. Re-run Snort as above and try pinging again. You should see alerts, and your host’s should not be able to ping. Note that all other traffic is permitted, our rule is only blocking ICMP traffic. You should see alerts specifying the Drop action:
06/07-14:42:23.935433 [Drop] [**] [1:10000001:1] ICMP test detected [**] [Classification: Generic ICMP event] [Priority: 3] {ICMP} 10.0.0.88 -> 192.168.0.10 06/07-14:42:24.942280 [Drop] [**] [1:10000001:1] ICMP test detected [**] [Classification: Generic ICMP event] [Priority: 3] {ICMP} 10.0.0.88 -> 192.168.0.10
If you were to reboot your computer, you would loose all your iptables configurations. To make them persistent, we need to export the current configuration to a text file, and tell the system to load that text file each time the network starts up. To Export the current settings, we use the iptables-save tool as follows:
sudo sh -c "iptables-save > /etc/network/iptables.rules"
To load the settings, we use the iptables-restore tool in our network interfaces file (/etc/network/interfaces) for our primary network interface, so now the configuration for ens160 looks like this:
auto ens160 iface ens160 inet static address 10.0.0.2 netmask 255.255.255.0 network 10.0.0.0 broadcast 10.0.0.255 gateway 10.0.0.1 pre-up iptables-restore < /etc/network/iptables.rules post-up ethtool -K ens160 gro off post-up ethtool -K ens160 lro off
Reboot and test. You’ll need to manually re-start Snort for any traffic to be passed at this time. Remember that iptables is placing all routed traffic in NFQUEUE number 4, but if there is no application listening to that queue, traffic will not pass.
The following is optional based on your security needs. If you want traffic to pass between networks when Snort is not running (fail-open mode), if Snort crashes or stops running for some reason, you’ll want to enable the –queue-bypass flag for the iptables rule. We will need to modify the current rule. First let’s check the state of all chains:
$ sudo iptables -L --line-numbers Chain INPUT (policy ACCEPT) num target prot opt source destination Chain FORWARD (policy ACCEPT) num target prot opt source destination 1 NFQUEUE all -- anywhere anywhere NFQUEUE num 4 Chain OUTPUT (policy ACCEPT) num target prot opt source destination
we want to modify rule number 1 in the FORWARD chain. To do this, we run the following command, which Replaces (the -R flag) this rule, adding the queue-bypass option:
sudo iptables -R FORWARD 1 -j NFQUEUE --queue-num=4 --queue-bypass
you’ll want to re-save the running configuration as above (overwrite the text file), reboot, and test.
Rather than try to fit a small guide for iptables on production systems into this guide, I will refer you to a couple of other excellent short guides on how to use iptables to secure your system. You should at a minimum block all access to the system (the INPUT queue) that isn’t management related or from the management network. Configuring Drop by default rather than accept is recommended.
Basic iptables lock-downs for a system.
More in-depth iptables lock-downs for a server.
At a minimum, to block traffic from going to the management network, you would want to insert the following rule:
sudo iptables -I FORWARD -o ens192 -j DROP
this blocks all routed traffic out the management interface. You have to insert this above the NFQUEUE rule, because once Snort permits the traffic, it does not go through other chains.
You will probably also want to setup PulledPork to download rules automatically, install barnyard2 for log processing, and BASE to view alerts in a GUI. All these steps can be found in my guide on snort, here: Installing Snort
If you found yourself struggling to get routing working even before you got to the Snort portion of this guide, I highly recommend that you look into taking a networking course. I personally took the Cisco CCNA course offered by the local community college (I think it was only $45 USD a unit). I learned an amazing amount about how networks work, and it made me a much better systems administrator. Don’t think that because you’re a computer administrator that Cisco training isn’t for you, it will compliment your knowledge and abilities.
Books:
The CCNA Books offered by Cisco are excellent:
The CCNA official Cert Guide is what I used to pass my CCNA years ago, and are very well written textbooks. While it’s Cisco specific, most of the basic knowledge in these books are general enough to be useful to anyone working with networking.
The CCNA Routing and Switching Portable Command Guide is one of the few hard-copy books I keep on my shelf and refer to whenever i’m working on Cisco eqipment.
I found the O’reily Network Warior book to be quite satisfying, it gave a broad overview of a number of technologies related to network technology to really broaden my knowledge.
If you’re really serious about TCP/IP, the gold standard (and really heavy) book to have is the The TCP/IP Guide: A Comprehensive, Illustrated Internet Protocols Reference.
Links:
How to Enable IP Forwarding in Linux
Understanding the ip route command and IP routing in Linux.
Iptables Tutorial 1.2.2. If you want to know how it works at the architecture level (not the user level, and not the programming level), this is the guide you want to read. I found Chapters three through nine to be most helpful, but if you need some more info on TCP/IP, the first few chapters are quite good as well.
The second flowchart at this page is awesome for understanding how packets flow through iptables. Use it in conjunction with the iptables tutorial above.
the NFQUEUE options for iptables.
This article:
A Deep Dive into Iptables and Netfilter Architecture, may get a little deep into the internal workings of the kernel IP stack, but I found it fascinating. Compliments this SANS article as well.
A few relevant books that get good reviews, but which i haven’t read yet:
Linux iptables Pocket Reference
Linux Firewalls: Attack Detection and Response with iptables, psad, and fwsnort
How Linux Works: What Every Superuser Should Know
I hope this article has been helpful to you. Please feel free to provide feedback, both issues you experienced and recommendations that you have. The goal of this guide was not just for you to create a Snort NIPS with NFQ, but to understand how all the parts work together, and get a deeper understanding of all the components, so that you can troubleshoot and modify your Snort NIDS with confidence.