Showing posts with label netfilter. Show all posts
Showing posts with label netfilter. Show all posts

Saturday, March 26, 2011

IPTables: Fun with MARK

One thing that’s always bugged me about IPTables is the lack of a way to use groups when writing rules, which can complicate things if you’ve got a potentially large rulebase. One way round this is to use something like fwbuilder, which gives you a graphical interface not unlike Checkpoint‘s SmartDashboard GUI for their Firewall-1 devices. The downside to this, though, is that the resulting IPTables ruleset is far from legible – which, to be fair, isn’t the goal of fwbuilder – and this makes hacking about with the rules nearly impossible.
So what options are there? One way is to repeat the same rule for different sources or destinations, but this can quickly get messy, especially if there’s multiple ports involved. If there was a way we could group things together and keep them tidy, maintaining the rulebase would be a lot easier. This is where MARK comes in.
The MARK target lets us set a 32-bit value (or 0xFFFFFFFF) on a packet, which we can then look for later with the mark match. This in itself can be useful, but where it gets really handy is adding the values together.

Starting out

To start off with, here’s an example
# Create a new chain, which will in effect be our source 'group'
iptables -N S-TRUSTED
# Add our sources
iptables -A S-TRUSTED -s 192.168.1.1/32 -j MARK --set-xmark 0x8/0x0
iptables -A S-TRUSTED -s 192.168.2.0/24 -j MARK --set-xmark 0x8/0x0
iptables -A S-TRUSTED -s 192.168.3.3/29 -j MARK --set-xmark 0x8/0x0

# Create a chain for the destination group
iptables -N D-DMZ
# Add our DMZ machines
iptables -A D-DMZ -d 10.1.1.1/32 -j MARK --set-xmark 0x4/0x0
iptables -A D-DMZ -d 10.1.2.0/24 -j MARK --set-xmark 0x4/0x0

# Create a chain for the services
iptables -N D-SRV-MGMT
# Add our service
iptables -A D-SRV-MGMT -p tcp -m tcp --dport 22 -j MARK --set-xmark 0x2/0x0
iptables -A D-SRV-MGMT -p tcp -m tcp --dport 80 -j MARK --set-xmark 0x2/0x0
So what we have now are three chains, which do the following
  • If the source matches, add 0×8 to the packet mark
  • If the destination matches, add 0×4 to the packet mark
  • If the service matches, add 0×2 to the packet mark
If you know your hexadecimal, you’ll already know that if all of these are true, we’ll come out with 0xE (or 14, in decimal).

Making the rule

Hopefully you’ll see where we’re going with this with the next example, which is our actual rule
# Create a new chain for our rule and add it to our FORWARD chain
iptables -N R-ALLOW-DMZ-MGMT
iptables -A FORWARD -j R-ALLOW-DMZ-MGMT
# Zero out the packet mark to make sure no previous rules interfere
iptables -A R-ALLOW-DMZ-MGMT -j MARK --set-xmark 0x0/0x0
# Jump to our 'source group' chain
iptables -A R-ALLOW-DMZ-MGMT -j S-TRUSTED
# Jump to our 'destination group' chain
iptables -A R-ALLOW-DMZ-MGMT -j D-DMZ
# Jump to our 'service group' chain
iptables -A R-ALLOW-DMZ-MGMT -j D-SRV-MGMT
# If the packet mark matches 0xE, then ACCEPT
iptables -A R-ALLOW-DMZ-MGMT -m mark --mark 0xE -j ACCEPT
And there we have it – if the packet matches the source, destination and service, the packet mark will be 0xE. If, say, it matches everything except the destination, it’ll come out as 0xC, which won’t match and so netfilter will carry on along the rest of the rules. If you want processing to stop here, you could always add a LOG and REJECT/DROP target at the end of the R-ALLOW-DMZ-MGMT chain.

Negation

Sometimes we want to be able to say ‘everything but that particular network’, whether it be for accepting or dropping packets. We can do that with this, too
# Add a new chain for negating the source
iptables -N S-NEGATE
# XOR the current packet mark with 0x8 - our 'source match' identifier
iptables -A S-NEGATE -j MARK --xor-mark 0x8
To use it, simply drop it in the R-ALLOW-DMZ-MGMT rule above after the jump to the S-TRUSTED chain, and if S-TRUSTED matched, it won’t any more, and vice versa. To negate the destination and service matches, you’ll need to create similar chains for (for example) D-NEGATE and D-SRV-NEGATE, replacing the 0×8 with 0×4 and 0×2 respectively.

Things to note

One downside of this method is that because of the way IPTables works, if you want to use the same set of networks and hosts as a source and a destination, you’ll need to duplicate them, but match on the source or destination as appropriate. Using the example given above, if we wanted a group with the same entries as S-TRUSTED, but matching on traffic going to them, we’d need to create another group (for example, D-TRUSTED), which will be identical save for the IP matches (which will need changing to -d) and the mask (which will need setting to 0×4 instead of 0×8).
Also, be careful if you’re using packet marks to do something outside of netfilter (say, for traffic control – which I’ll cover in a future post). One way round this is the facility to save the current packet mark to the current connection mark, or vice versa – if you go down this path then having a look at the iptables manpage for the MARK and CONNMARK targets will be useful.

Conclusions

This is an effective way of grouping hosts, networks and services within IPTables. It can be quite a bit of work to start with to add all the groups, but once in place it makes writing rules a lot more logical.

Taking things further

One way which you could take this further would be to group interfaces together in a similar fashion, say by adding 0×10 to the packet, and then matching on 0x1E rather than 0xE.
Usefully, if you send the packet out to syslog with the LOG target, netfilter will print out the current packet mark at the end of the log message as MARK=0xN, which can be useful when debugging.

Courtesy : http://andys.org.uk/bits/2010/01/27/iptables-fun-with-mark/

Using IP sets for best performance

IP sets are the best method for blocking specific countries using our IP prefix files for specific countries.
From the IPset homepage:
IP sets are a framework inside the Linux 2.4.x and 2.6.x kernel, which can be administered by the ipset utility. Depending on the type, currently an IP set may store IP addresses, (TCP/UDP) port numbers or IP addresses with MAC addresses in a way, which ensures lightning speed when matching an entry against a set.
If you want to
  • store multiple IP addresses or port numbers and match against the collection by iptables at one swoop;
  • dynamically update iptables rules against IP addresses or ports without performance penalty;
  • express complex IP address and ports based rulesets with one single iptables rule and benefit from the speed of IP sets

  • If you have a network or server with high traffic and using standard iptables for traffic blocking it may affect your server/network performance. With IPsets you can “group” multiple IP sets in groups and then match these in one swoop. This will provide you top performance.


    IP sets allows you to bind an entry in a set to another set, which forms a relationship between the set element and the set it is bound to. The sets may have a default binding, which is valid for every set element for which there is no binding defined at all.

    Example:

    ipset -N servers ipmap –network 10.10.10.0/16
    ipset -A servers 10.10.10.1
    ipset -A servers 10.10.10.2
    ipset -N ports portmap –from 1 –to 1024
    ipset -A ports 21
    ipset -A ports 22
    ipset -A ports 25
    ipset -B servers 10.10.10.2 -b ports
    iptables -A FORWARD -m set –set servers dst,dst -j ACCEPT
    iptables -A FORWARD -j DROP
    Courtesy :  http://www.ipdeny.com/blog/using-ip-sets-for-best-performance/