Thursday, September 22, 2011

Implementing IF, AND, OR, etc. in iptables...

I saw that some people accessed my blog while searching for OR, AND, IF and similar operators in iptables. These operators are indeed implemented within the subsystem but not in the usual sense, that is, they are not so obvious. In other words, they are implicit in the way you are writing rules. But, if you understand how that works, writing iptables rules becomes much easier.

Before continuing you have to understand how packets are processed by netfilter/iptables framework. Firewall rules are data driven language, but actually, the things are very simple. All the packets traverse different parts of the Linux kernel. At certain points those packets are stopped (figuratively speaking) and set of rules is "executed" that can alter, drop or pass packet. If packet is passed (or modified and passed) it goes to the other parts of the kernel where potentially another set of rules is invoked.

The points where packets are "stopped" are chains, PREROUTING, INPUT, FORWARD, POSTROUTING, OUTPUT. In each chain there are different tables, but I'll ignore those for the moment as they are not important for this post.

Set of rules at each point (chain) is added or deleted using iptables command. The iptables command needs an argument that defines in which chain rule is added. That argument is option -A after which name of the chain follows. For example, to add something to INPUT chain, you would write:
iptables -A INPUT ...
Ok, let us now start with a simple example, what if you want to do some processing on every packet that has source address 192.168.1.1, i.e.
if (src(ip) == 192.168.1.1) {
   do_something_with_packet;
}
To achieve that functionality, just write the rule as follows:
iptables -A INPUT -s 192.168.1.1 do_something_with_packet
The part do_something_with_packet I'll explain later, but basically this is a part that will do something useful with the packet on which this rule is executed.

Now, what if you want to add additional constraint, e.g. destination address is 192.168.1.2, i.e.

if (src(ip) == 192.168.1.1 and dst(ip) == 192.168.1.2) {
   do_something_with_packet;
}
Well, what you'll write is the following:
iptables -A INPUT -s 192.168.1.1 -d 192.168.1.2 do_something_with_packet
easy, isn't it? All the constraint you wish to bind with operator AND are just written one after another. Operator AND is implicit. Ok, now you can ask: But if I want to have OR, what to do then? For example, something like the following:

if (src(ip) == 192.168.1.1 or dst(ip) == 192.168.1.2) {
   do_something_with_packet;
}
Believe it or not, it's simple, write it like this:
iptables -A INPUT -s 192.168.1.1 do_something_with_packet
iptables -A INPUT -d 192.168.1.2 do_something_with_packet
I suppose that you figured it that when you add iptables one after the other, they are bound by OR, while, when you write constraints in a single command they are bound by AND. Alternatively speaking, reading from left to right is AND, and from top to bottom is OR.

2 comments:

Jonathan Davis said...

How would one add an AND or OR operator for THE SAME constant into one rule?

I need to say -d ! 192.168.18.0/24 AND -d ! 192.168.19.0/24 as an example?

Stjepan Groš (sgros) said...

OR is easier, if you want:

iptables condA OR condB target

you can write it as:

iptables condA target
iptables condB target

AND is trickier because iptables doesn't support AND operator in specifiers. But, you can do it using custom chain. Say you want:

iptables condA AND condB target

you can write it as:

iptables -N newchain
iptables condA -j newchain
iptables -A newcnain condB target

Note that the iptables statements are only conceptual. :)

About Me

scientist, consultant, security specialist, networking guy, system administrator, philosopher ;)

Blog Archive