iptables and iprules

Follow the (ip) Rules

Hopefully, you have already read and/or understand these concepts:

Now, it's time to talk about rules; particularly ip rules. Rules are the lifeblood of the Routing Policy DataBase (RPDB). Rules are processed prior to routes. In order to get to a route, a packet must be directed there by a rule. Rules direct traffic to a specific action or routing table. This is why you'll notice rules use the terminology "lookup" and then reference a routing table. This is because the rules effectively do "lookup" or read and execute the contents of the directed routing table name. For example, the default Linux rules allow all traffic and direct both incoming and outgoing traffic and 'lookup' the default routing tables (e.g. localhost, main).

WARNING: Routes and rules are not automatically available during the current session. To activate new rules and routes created with ip rule and ip route, you must flush the cache; either by rebooting the server or forcibly flushing the cache. To activate new iptables rules that are persistent between server reboots, the process is a bit more involved and is explained in Persistence: Making iptables Changes Stick.

New rules are created with the ip rule add command.

IP Rule Syntax

Like almost everything on this site, I'm not going to delve into every possible parameter and switch in ip rule, but I shall go over the most common variants. The syntax of a rule looks like this:

ip rule add {prefix} {selector} {predicate}

Sounds simple enough, eh? But, what is a selector? What is an action?

The rule type add - as its name implies - adds a new rule to the RPDB. Within the context of the ip rule add command there are three components: prefix, selector, and predicate. The prefix determines if the rule applies to incoming or outgoing traffic. The selector is the filter or what conditions are being applied. The predicate is the object of the selector or an action. Their syntax looks like this:


from {addr} | to {addr}


to {addr} | priority {#} | fwmark {fwmark} | iif {name} | oif {name} | tos {value}


{ blackhole | prohibited | unreachable } | lookup {table id}

It's helpful to break these down a bit further.

The prefix is a combination of a from and/or to statement, and a single IP address or range of IP addresses, with our without a netmask.


An address or range of addresses with the given source IPv4 address or range.*


An address or range of addresses with the given destination IPv4 address or range.*

* Note: "all" is an acceptable wildcard, and means "all addresses."

A prefix of from pertains to an incoming filter where the associated IP address is a source address/range, with or without a netmask. A prefix of to pertains to an outgoing filter where the associated IP address or range is a destination address/range. These source and/or destination addresses are used to determine whether or not the current rule up for evaluation should be applied to the current network packet.

After the prefix comes the next step in the filtering process: the selector. Multiple selectors may be used in the same rule. These are filtering screens. The selector is comprised of the following choices:

Selector Description
fwmark a means of marking packets; decimal values are converted to hexadecimal
iif in-bound interface {name}
oif out-bound interface {name}
priority rule # you wish assigned; must be unique; lower # = higher priority
tos ToS=Type of Service; rarely used by home users; for more info see ToS

The predicate is a bit easier to follow. There are four possible outcomes:

Predicate Description
lookup return route found in the referenced routing table
blackhole drop packet silently
prohibited reject packet and error, "Communication is administratively prohibited"
unreachable drop packet and return error, "network unreachable"

FYI on FireWall Marks (fwmark): ip rule cannot create or add a mark to a packet. It can detect the presence of an fwmark and apply branching logic (filtering) if an fwmark exists, but it cannot manipulate firewall marks.

IP Rule Examples

Here are some examples to demonstrate the concepts discussed above. An example that points to a new table called custom.

ip rule add to lookup custom

Let's pick apart this example. The "to" prefixing an IP address means it is a destination address. "Lookup custom" means the corresponding action is to lookup or read the routing table named custom. So, an English reading of the corresponding new rule would be something like,

"If the current packet destination address is, lookup and execute a route in the table named custom."

Here are more examples of rules you could create:

# match a source network and direct its traffic to a particular table
ip rule add from lookup mytable

# prohibit traffic from a source network
ip rule add from prohibit

# blackhole any traffic headed for a particular sub-net
ip rule add to blackhole

# direct traffic addressed from a specific address to a specific sub-net
ip rule add from to lookup default

# direct packet from specific IP to specific sub-net to table named test123
ip rule add from to lookup test123

# silently drop any traffic attempting to reach between two sub-nets
ip rule add blackhole from to

# direct marked packets to table test123
ip rule add from fwmark 1 lookup test123

# set priority and filter specific addr to specific addr
ip rule add priority 22 from to lookup default

Rule Priority

Rule priorities are processed in order from lowest to highest number. Take a look at your current rules.

ip rule show

An unaltered, new ip rule table will look similar to this:

0: 	from all lookup local
32766:	from all lookup main
32767: 	from all lookup default

Rules are evaluated in order against packets based on the longest match principle. It means the rule matches the current packet and is also the longest character length rule in the RPDB that meets the matching criteria. In the case of a tie, when more than one rule both matches the logical criteria and is the longest matching length rule and is of equal length as another matching rule, only then does priority come into play. At that point the highest priority match wins the battle. Functionally, because it applies to IP addresses, this model normally equates to a model of most specific, because logically that is going to be the longest matching bit pattern. However, that is not always the case as the length of the rule (in bytes within the rule table) influences the outcome. Therefore, if you have more than one potential matching rule for a particular scenario, it's a good idea to place your preferred outcomes at lower rule numbers (higher priorities), just in case.

Important Concept: When adding a new rule via the command line, if the rule number is not specified, the next sequential rule number preceding the last used rule number will be selected. For example, if the previous rule you created has a priority of 100, and you then add another new rule but don't specify a priority number, the number 99 will be assigned to the new rule.

To re-cap, the process works like this:

Rule filter -> Rule Match [Longest + Highest Priority] -> Routing Table -> Most Specific Route

Rules filter the packet first, which identifies the appropriate routing table. Rules are evaluated in order. They are numbered from 0-32767. The routing table is then scanned for a matching route based on the source or destination IP of the packet.

Let's break down how these components interact with one another to derive at a route for each packet. Linux evaluates routing requests in this order:

  1. Process the rules in order starting with rule #0
  2. Check each rule in the database to see if it matches the packet
  3. If there is more than one match, choose the longest matching rule (presumed to be the most specific)
  4. If no matching rule is found, return a non-reachable error

Take a look at the incumbent rule set after installing Ubuntu. You can see it's very simple and contains just three rules.

0:      from all lookup local
32766:  from all lookup main
32767:  from all lookup default

If you were to create a new rule and not specify a priority for it, such as this rule:

ip rule add from all iif eth0 lookup main

Your RPDB table would then look like this:

0: 	from all lookup local
32765:	from all iif eth0 lookup main
32766:	from all lookup main
32767: 	from all lookup default

Incidentally, the new rule above would instruct the kernel to route all traffic coming from the incoming interface eth0 to the main router table.

Don't forget to pay attention to the order of your rules and the order of when/how each table is called.

If your server doesn't have custom tables yet you may view your current RPDB rule collection using this command:

ip rule show

All RPDB rules are loaded into the kernel’s memory when the server starts up. If you make changes to ip rules or ip routes and wish to utilize them prior to the next system reboot, you must flush the cache. This forces the kernel to reload the rule and routing databases. To do this, run:

ip route flush cache

How Default RPDB Rules Function

While reading the Rule Priority section above, you might have wondered how the default ip rules can possibly be useful. After all, they are simply three "from" rules. Let's review them.

ip rule show


0:      from all lookup local
32766:  from all lookup main
32767:  from all lookup default

How is it possible that all packets are moved through the RPDB if there are no corresponding "to" rules? How is it that outgoing packets originating from the server don't get stuck? The answer is that every local packet - whether outgoing or addressed to localhost - still has a "from" or source IP address, regardless of its "to" or destination address. This fact allows all traffic to move through the rules because all traffic is coming "from" some address. The rules are checked in order from 0 - 32767. The kernel looks through the entire list to figure out which route is the most specific for the packet. The default rules simply pass all traffic through each table - local, main, default - in succession until a match is found or the packet fails to be matched to anything in any of these tables.

Routing Marked Packets with fwmark

The FireWall MARK (fwmark) can only be set by iptables, while both iptables and ip rule can read fwmarks (the ip rule system can only read its value and act on it as a selector). Note fwmark converts decimal values to hexadecimal, though a query regarding its value may use either decimal or hexadecimal numbers. If referencing it in hexadecimal form, precede the value notation with an "x." For example, these two statements are identical:

ip rule add fwmark 32 lookup mytable
ip rule add fwmark x20 lookup mytable

Either statement will forward packets with an fwmark value of 32 to the routing table named "mytable."