====== Firewall and Advanced Routing Under Linux ====== ===== Introduction ===== This page content was cloned from [[http://ornellas.apanela.com/dokuwiki/pub:firewall_and_adv_routing]] for safe keeping. --- //[[nmartin@gmail.com|Nathan Martin]] 2011/10/04 14:57// ==== Objective ===== To present different tools and functionalities present on [[http://www.kernel.org/|Linux]] systems to implement [[wp>Firewall_(networking)|firewall]] and [[wp>Router|routers]]. Specific usage of each tool will not be covered by this article and it is up to the reader to learn more about them by reading the manuals. ==== Requirements ==== It is assumed that the author has basic knowledge about [[http://www.gnu.org/|GNU]] / [[http://www.kernel.org/|Linux]] systems and [[wp>Internet_Protocol|TCP / IP]] networking (including [[wp>Firewall_(networking)|firewall]] and [[wp>Router|routing]]). It is recommended that the reader follow the article together with each tool´s manual in hand for reference. ====== Firewall: IP Tables ====== The current tool for firewall under Linux is [[http://www.netfilter.org/projects/iptables/|iptables]]. IP Tables is composed of a series of [[wp>Userland_(computing)|userland]] tools that interact with [[http://www.netfilter.org/|netfilter]], which is Linux firewall implementation in [[wp>Kernel_(computer_science)|kernel]] space. IP Tables behavior is based on pairs of //rules// and //actions//. Rules define in which [[wp>Packet|packets]] (eg. packets from a certain network) a certain action (eg. to drop the packets) will be executed. Netfilter will process all rules sequentially for each package. When it finds one that matches a certain rule, it will act by calling the defined action for that rule. Actions taken can be either terminative or not. For example, an action which asks netfilter to ignore a certain packet will be called and no other rules will be applied. This is a terminative action. However, if the action specifies to only log the existence of the package, it will do its job and let netfilter process the following rules. This is a non terminative action. The main tool is the command ''iptables'', which manual can be accessed via: # man iptables The next sections will explain how the explained behavior works inside iptables and how to configure it. ===== Tables ===== The name ''iptables'' comes from the fact that internally iptables works based on tables, each one specialized on a certain type of packets treatment. These are the tables existent on a Linux 2.6.8 (different kernel versions can have different tables): ^ Table ^ Meaning ^ | ''raw'' | Low level alteration of packets. | | ''nat'' | Changes on packets headers (where [[wp>NAT]] takes place). | | ''mangle'' | Used to make specialized packet alterations. | | ''filter'' | Packet filtering. | Thus, depending on what you wish to do with a certain packet, there is an adequate table for that. ===== Chains ===== In IP Tables, there are several //chains// glued to each table and each one associated a certain kind of traffic. Here they are: ^ Chain ^ Meaning ^ | ''PREROUTING'' | Incoming traffic to the machine (including local generated traffic destined to the machine itself) before routing takes place (can be either local or passing traffic). | | ''INPUT'' | Traffic destined to the machine itself. | | ''FORWARD'' | Matches passing traffic (remote generated, remote destination). | | ''OUTPUT'' | Locally generated traffic (either local or remote destination). | | ''POSTROUTING'' | Outgoing traffic (including locally generating traffic, destined to the machine itself). | It is also possible to create personalized chains, topic that will not be covered on this article. The ''FORWARD'' chain has a special treatment inside Linux kernel. It comes with a lock that blocks traffic through this chain by default. To allow such traffic, it is needed to change the following kernel parameter: net.ipv4.ip_forward=1 to allow [[wp>IPv4]] traffic (there is a similar switch to [[wp>IPv6]] traffic). This parameter can be changed using ''sysctl(8)'' command: # sysctl -w net.ipv4.ip_forward=1 This can be automated by adding the following line to ''sysctl.conf(5)'' (usually ''/etc/sysctl.conf'') and should be set up at boot time: net.ipv4.ip_forward=1 **Note:** [[http://www.debian.org/|Debian]] versions previous (and including) Sarge have a file named ''/etc/network/options'' that can also be used to set up this parameter. This is wrong and is not present any more in future releases. ===== Data Flow Diagram ===== The data flow inside each table / chain inside the Linux kernel is described by the graph below. In each box, it is labeled the acting chain and the names of the valid tables for each chain. Traffic flows through each one of the tables in series for each chain. For example, at ''PREROUTING'' chain, there are the tables ''raw'', ''mangle'' e ''nat''. Traffic flowing through this chain will pass by each one of the three tables sequentially. Incoming Traffic | | V +----------+ |PREROUTING| +----------+ | raw | <--------------+ | mangle | | | nat | | +----------+ | | | | | Routing | +- Decision -+ | | | | | | | V V | Local Remote | Destination Destination | | | | | | | V V | +--------+ +---------+ | | INPUT | | FORWARD | | +--------+ +---------+ | | mangle | | mangle | | | filter | | filter | | +--------+ +---------+ | | | | | | | V | | Local | | Machine | | | | | | | | V | | Routing | | Decision | | | | | | | | V | | +--------+ | | | OUTPUT | | | +--------+ | | | raw | | | | mangle | | | | nat | | | | filter | | | +--------+ | | | | | | +-------------+ | | | POSTROUTING | Local +----> +-------------+ --> Traffic | mangle | | nat | +-------------+ | | V Outgoing Traffic Let´s take as an example an access from the machine to itself. Traffic will flow sequentially by each one of the following chains / tables: - Packet generated by a local process / kernel - Routing decision - ''OUTPUT'': ''raw'' - ''OUTPUT'': ''mangle'' - ''OUTPUT'': ''nat'' - ''OUTPUT'': ''filter'' - ''POSTROUTING'': ''mangle'' - ''POSTROUTING'': ''nat'' - ''PREROUTING'': ''raw'' - ''PREROUTING'': ''mangle'' - ''PREROUTING'': ''nat'' - Routing decision - ''INPUT'': ''mangle'' - ''INPUT'': ''filter'' - Packet delivered to a local process / kernel Thus, if one wish to allow such traffic, there must have no rule / action pair prohibiting the traffic in any of the above cases. ===== Rules ===== Given a certain chain / table, it is necessary to use //rules// to select in which packets a certain action will take place. Not all rules applies to all chains. For example, a rule specifying the outgoing interface of a packet does not apply to the chain ''PREROUTING'', since routing decision has not been taken at that point. There are general rules (referred as ''PARAMETERS'' on the manual ''iptables(8)'') and extensions (see ''MATCH EXTENSIONS'' on the same manual). General rules are usually the same across different kernel versions. Match extensions depends on the running kernel and IP Tables version (remember that IP Tables is only a userland tool to interface with netfilter). It is possible to have the case where a certain rule exists in IP Tables but it's corresponding implementation is missing in the running kernel. In this case, trying to use such rule will fail. General rules are: ^ Rule ^ Description ^ | ''-p PROTOCOL'' | Specify an IP protocol (eg. [[wp>Transmission_Control_Protocol|TCP]] or [[wp>User_Datagram_Protocol|UDP]]). | | ''-s ADDRESS'' | Specify a source address. | | ''-d ADDRESS'' | Specify a destination address. | | ''-i INTERFACE'' | Specify a local interface of incoming traffic. | | ''-o INTERFACE'' | Specify a local interface of outgoing traffic. | Match extensions will be treated to follow. ===== Target ===== A target specify the action to be taken when a certain packet match a certain rule. This target can be one of the default (should be available on all kernels) or one target extension (refer to ''TARGET EXTENSIONS'' at ''iptables(8)''). The default targets are: ^ Target ^ Meaning ^ | ''ACCEPT'' | Allow the packet through. | | ''DROP'' | Instruct netfilter to ignore the packet. | | ''QUEUE'' | Pass the packet to userspace. | | ''RETURN'' | From the manual: "stop traversing this chain and resume at the next rule in the previous (calling) chain. If the end of a built-in chain is reached or a rule in a built-in chain with target RETURN is matched, the target specified by the chain policy determines the fate of the packet." | In practice, most times you will be using either ''ACCEPT'' or ''DROP''. ===== Writing rules ===== According to ''iptables(8)'', there are many ways to add / remove rules. All add rule actions, are discrete operation. This suggests the creation of a shell script containing all ''iptables(8)'' calls that compose the whole firewall. Remember to clean all pre-existing rules at the beginning of the script. To add a single rule (at the end of the existing ones), follow this general form: # iptables -t [TABLE] -A [CHAIN] [RULES] -j [TARGET] Where: ^ Variable ^ Meaning ^ | ''TABLE'' | Specify the table. | | ''CHAIN'' | Specify the chain. | | ''RULES'' | Packet selection rules. | | ''TARGET'' | Action to take place. | For example, to allow the network 192.168.0.0/24 connected through the network interface named eth0 to send traffic to the network 192.168.1.0/24, connected to the network interface eth1, one can write the following rule: # iptables -t filter -A FORWARD -s 192.168.0.0/24 -d 192.168.1.0/24 -i eth0 -o eth1 -j ACCEPT Follow the data flow on the above data flow graph to note that this rule would not be enough, since the packet flows through many other table / chains. In the case that no rule matches a certain traffic, there is a way to set up a default policy to a certain table / chain. This default policy configure a target to be executed in the case no other terminative rule on the same target / table match the traffic. To define a default policy try: # iptables -t [TABLE] -P [CHAIN] [TARGET] For example: # iptables -t raw -P OUTPUT ACCEPT This rule will allow free traffic by default on the table raw, chain OUTPUT Up to here, resources to control traffic are limited. The neTABELAxt topic will cover some extensions that give much more control / power over the firewall. ==== Match extensions ==== As said previously, there are match extensions that allow to better select packets. The general form is: ... -m [NAME] [OPTIONS] where ^ Variable ^ Meaning ^ | ''NAME'' | Name of the match extension in use. | | ''OPTIONS'' | Match extension options. | Please reffer to the topic ''MATCH EXTENSIONS'' of ''iptables(8)'' to get more information on available match extensions and its options. === Examples === Here are presented some common match extensions, that will be used most of the times. == tcp == Allow to specify a certain source / destination TCP port: ... -m tcp --dport www This will match TCP connections which destination port is www (number 80, please reffer to ''/etc/services''). == udp == Allow to specify a certain source / destination UDP port: ... -m udp --dport www === Connection tracking === IP Tables is a so called [[wp>Stateful_firewall|stateful firewall]]. This means it is possible to match all packets related to a certain connection, having no need to make a rule to allow packets going and another to allow packets coming from the same connection. This is direct for TCP connections, but there are extensions to allow UDP traffic windows, thus defining an "UDP connection". Example: # iptables -t filter -A FORWARD -d [WEB_SERVER] -i [EXTERNAL_INTERFACE] -o [INTERNAL_INTERFACE] -j ACCEPT # iptables -t filter -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT The first rule allows external traffic coming via ''EXTERNAL_INTERFACE'' to reach ''WEB_SERVER'' on ''INTERNAL_INTERFACE''. The second rule says that any forwarding traffic related to an existing connection, will be allowed (eg. traffic coming from ''WEB_SERVER'' to ''EXTERNAL_INTERFACE''). The match extension ''state'' tracks the connections, and matches the respective traffic. Note that in this case, all forwarding traffic related to a pre-existing connection will be allowed, not only the traffic from the first rule. The connection tracking system from netfilter has many different modules, being able to track specific protocols, such as FTP, to allow related (data) connections to work with no additional rule or the need of a proxy server. In the case where no connection is defined (eg. UDP or ICMP) after the traffic goes, a window is opened to allow its return. Thus, everything works like if there was actually an "UDP connection". It is recommended to let a rule similar to the above second one. It is better to have a generic rule "catch all" than writing an specific connection rule for each traffic. Since this rule will not allow traffic if it was not allowed before, it is not security problem to do this. It is also recommended to allow ICMP traffic to flow freely. Please refer to iptables manual to find out more about connection tracking and more uses of this tool. ==== Target Extensions ==== Target extensions allow some specialized actions and packet treatment to be done, such as [[wp>Network_address_translation|NAT]] or load balancing. Please refer to iptables manual to know more about available target extensions. Here are some important ones: * **LOG** This one allow to log (via kernel logging, you can see using the command ''dmesg'') any message you wish when a certain packet matches. A good rule is to include a logging rule right before any rejected traffic. This way, finding out problems with your firewall is easy, as you can see what and when it is dropping something. This target accepts an option ''--log-prefix'', that allow to prefix a text to each log message. * **MASQUERADE, SNAT, DNAT** Those are three possibilities of implementing [[wp>Network_address_translation|NAT]] ([[http://www.faqs.org/rfcs/rfc1631.html|RFC1631]]). This way, it is possible to integrate a private network ([[http://www.faqs.org/rfcs/rfc1918.html|RFC1918]]) to the internet with no problems. Please refer to the manual on the use of each target. ====== Advanced Routing ====== Linux has a different approach for routing than other UNIX. The way things are implemented on Linux is more flexible and powerful than traditional ways. Legacy utilities such as ''ifconfig'' and ''route'' are still valid, but incomplete. This is because they do not give access to the advanced routing layer present on Linux. The utility ''ip'' (part of ''iproute2'') is the current tool for networking related stuff under Linux. This tool will be the focus of this section. Linux advanced routing is implemented in two parts: - Rules - [[wp>Routing_table|Routing tables]] It is possible to have multiple routing tables under Linux and the rules indicate when to use each one of them. ===== Rules ===== To list existing routing rules, one can try: # ip rule list 0: from all lookup local 32766: from all lookup main 32767: from all lookup default Rules are processed in increasing priority (1st) column). In the above case, priority 0 rule instruct the kernel to look for a routing decision inside table named ''local'' for traffic comming from any origin. The content of this table can be accessed via: # ip route list table local local 192.168.1.1 dev eth3 proto kernel scope host src 192.168.1.1 local 200.170.111.237 dev eth0 proto kernel scope host src 200.170.111.233 broadcast 192.168.1.0 dev eth3 proto kernel scope link src 192.168.1.1 broadcast 192.168.2.255 dev eth1 proto kernel scope link src 192.168.2.1 local 200.170.111.236 dev eth0 proto kernel scope host src 200.170.111.233 broadcast 127.255.255.255 dev lo proto kernel scope link src 127.0.0.1 broadcast 200.170.111.239 dev eth0 proto kernel scope link src 200.170.111.233 local 200.170.111.239 dev eth0 proto kernel scope host src 200.170.111.233 local 200.170.111.238 dev eth0 proto kernel scope host src 200.170.111.233 local 200.170.111.233 dev eth0 proto kernel scope host src 200.170.111.233 broadcast 200.170.111.232 dev eth0 proto kernel scope link src 200.170.111.233 local 200.170.111.235 dev eth0 proto kernel scope host src 200.170.111.233 local 201.20.202.11 dev eth0 proto kernel scope host src 201.20.202.11 broadcast 201.6.149.0 dev eth2 proto kernel scope link src 201.6.149.41 local 200.170.111.234 dev eth0 proto kernel scope host src 200.170.111.233 local 192.168.2.1 dev eth1 proto kernel scope host src 192.168.2.1 broadcast 192.168.1.255 dev eth3 proto kernel scope link src 192.168.1.1 broadcast 192.168.2.0 dev eth1 proto kernel scope link src 192.168.2.1 broadcast 201.20.207.255 dev eth0 proto kernel scope link src 201.20.202.11 broadcast 201.20.200.0 dev eth0 proto kernel scope link src 201.20.202.11 broadcast 127.0.0.0 dev lo proto kernel scope link src 127.0.0.1 broadcast 201.6.149.255 dev eth2 proto kernel scope link src 201.6.149.41 local 201.6.149.41 dev eth2 proto kernel scope host src 201.6.149.41 local 127.0.0.1 dev lo proto kernel scope host src 127.0.0.1 local 127.0.0.0/8 dev lo proto kernel scope host src 127.0.0.1 This table is long, but is managed by the kernel itself, thus, do not worry about it. This table contains information regarding local addresses (the ones associated with network interfaces), informing that they are resolved locally. In the case the table does not solve a certain destination address (eg. traffic to another machine in this case), Linux kernel look for the next rule with lower priority (higher priority number) to find out a routing solution. In this case, the next rule is the one with priority 32766, which says to go to table ''main'': # ip route list table main 200.170.111.232/29 dev eth0 proto kernel scope link src 200.170.111.233 192.168.2.0/24 dev eth1 proto kernel scope link src 192.168.2.1 192.168.1.0/24 dev eth3 proto kernel scope link src 192.168.1.1 201.6.149.0/24 dev eth2 proto kernel scope link src 201.6.149.41 201.20.200.0/21 dev eth0 proto kernel scope link src 201.20.202.11 default via 201.6.149.1 dev eth2 This table contain exactly the same information displayed by the ''route'' command: # route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 200.170.111.232 0.0.0.0 255.255.255.248 U 0 0 0 eth0 192.168.2.0 0.0.0.0 255.255.255.0 U 0 0 0 eth1 192.168.1.0 0.0.0.0 255.255.255.0 U 0 0 0 eth3 201.6.149.0 0.0.0.0 255.255.255.0 U 0 0 0 eth2 201.20.200.0 0.0.0.0 255.255.248.0 U 0 0 0 eth0 0.0.0.0 201.6.149.1 0.0.0.0 UG 0 0 0 eth2 So, this table contains the traditional routing information. The last table named ''default'' comes empty (try it). The rules and tables described here contain all the traditional routing information. It is possible however to insert new rules and new tables to fit demands of a more complex environment. ==== Custom Rules ==== One can for example, add a rule specifying that traffic from a certain source must be routed using a specific routing table: # ip rule add type unicast from 192.168.4.0/24 priority 55 table 55 This will instruct the kernel to when it finds traffic coming from 192.168.4.0/24 network, look for a routing solution inside table number 55, with priority 55. The table 55 must be created containing routing information regarding only to the source network in question. In this case: # ip rule list 0: from all lookup local 55: from 192.168.4.0/24 lookup 55 32766: from all lookup main 32767: from all lookup default Note that priority number 55 and table number 55 are absolutely arbitrary and have no need to be the same number. These numbers must only make sense to fit your routing needs. Please look at ''ip'' manual to obtain more information on how to add or remove rules and all possible parameters. ===== Tables ===== Routing tables are identified by numbers from 0 to 255. Tables ''local'' and ''main'' have the numbers 255 and 254 associated with it. There is a configuration file that one can associate a name to each table number (as for ''local'' and ''main'') that will not be covered by this article. The existence of a table containing routing rules inside does not imply that it is in use. A table will only be used if there is a rule pointing to it. Please consult ''ip'' manual on how to add routing rules inside tables. It should not be a problem, since its operation is similar to classic routing utility ''route''. ===== Note ===== Linux kernel comes with an anti-spoof protection apart from firewall. This protection protects an internal network against external attacks. Depending on the routing situation you need (specially when connected to multiple ISPs) this setting must be disable in order for your routing rules to work. This option is accessible vis sysctl net.ipv4.conf.all.rp_filter which changes configuration for all network interfaces. There is also the possibility to enable / disable by interface (substituting ''.all'' by ''.eth0'' for example, to change only interface eth0). The line: net.ipv4.conf.all.rp_filter=0 at ''/etc/sysctl.conf'', should disable this feature at boot time. Please refer to distribution specific settings. ====== Integrating Firewall and Routing ====== One possible routing rule matching filter is ''fwmark''. This option makes packets marked by the firewall to be matched and fall into desired table. # ip rule list 0: from all lookup local 33: from all fwmark 0x1 lookup 33 32766: from all lookup main 32767: from all lookup default In this case, packets marked as 0x1 by the firewall (0x1 is 1 noted in hexa-decimal) to be solved by the table numbered 33. The number 0x1 is absolutely arbitrary. It is important to know that this mark is local and internal to the Linux kernel and in any way alters the packets. ===== Marking packets ===== To mark a packet with iptables, use the target ''MARK'': # iptables -t mangle -A PREROUTING -i eth0 -j MARK --set-mark 1 In this example, all traffic coming through interface eth0 will be marked as 1 (an arbitrary number). After this, it is possible to include a routing rule matching these packets, as explained on the previous topic. Thus, this iptables rule and the routing rule will make specific routing for packets coming by interface eth0. Note by the above iptables fluxogram that the mark is being done before routing table. In this case, traffic is entering the machine, thus the ''PREROUTING''. In the case you wish to mark traffic generated locally, you should use the ''OUTPUT'' chain. ==== Connections ==== It is also possible to mark all packets related to a connection. The target ''CONNMARK'' allows marking of a connection (referred as //connection mark//, internal to the firewall), that is **not** the same marking seen by routing (referred as //netfilter mark//, accessible by routing rules), do not confuse them. Thus, one can make the following to mark packets of a connection to the routing rules: # iptables -t mangle -A OUTPUT -d SERVER -j CONNMARK --set-mark 1 # iptables -t mangle -A OUTPUT -m connmark --mark 1 -j MARK --set-mark 1 The first rule mark all desired connections. The second rule uses the match extension ''-m connmark'' to identify those //connection marks// and create //netfilter marks// by using the target ''MARK'' (to be saved by routing rules).