IPv6 does away with NAT, which functions much like a firewall for internal networks with IPv4, even though it was not designed for that purpose. With IPv6, a dedicated firewall now needs to provide protection against attacks from the Internet and other networks. Linux has the ip6tables tool for this purpose. In this article, I develop a basic set of rules.
The underlying scenario for this article involves a DSL router with Linux (Figure 1), which is required on the one hand to protect internal systems from attacks from the Internet and, on the other hand, to provide access to an internal server connecting to a DMZ interface. The aim is to manage both the end-to-end IPv6 network traffic and to control access to the router itself.
The router must be accessible for administrative purposes, at least using SSH and HTTPS, and it needs to act as a DNS server for the internal systems.
Since Linux kernel version 2.6.20,
ip6tables has supported stateful inspection, wherein the firewall automatically assigns response packets to a communication channel and allows communication where appropriate. This function, which is now common on almost all firewall platforms, reduces both the scope and the complexity of the rules significantly.
ip6tables in Netfilter
On Linux systems, the Netfilter framework has established itself as a kernel-based firewall software. The
iptables program is used to create IPv4 firewall and NAT rules for packet header manipulation.
iptables does not support IPv6; thus, the
ip6_tables kernel module, which is configured using the
ip6tables program, was added to the Netfilter framework. The
ip6tables program behaves in much the same way as
iptables, so hardened IPv4 veterans do not have to relearn the ropes completely.
On the other hand, the various new protocol components and communication types in IPv6 pose challenges for firewall administrators. In this article, I only address the IPv6 protocol, although, in reality, both protocols almost always need to be considered in the firewall configuration.
An IPv6 network firewall mainly controls the traffic that passes through the system. Therefore, IPv6 routing must be activated up front. This is done with the command:
sysctl -w net.ipv6.conf.all.forwarding=1
This command can also be entered in the configuration file
/etc/sysctl.conf (Figure 2). As a result,
/proc/sys/net/ipv6/conf/all contains a
1, and this value enables IPv6 routing. If you want to disable it, enter a
What Is Important?
IPv6 comes with a completely separate protocol stack. In most cases, IPv6 is used in parallel with IPv4 in dual-stack operation. Here, the question arises whether the existing firewall should be supplemented with IPv6 rules or whether a new dedicated IPv6 firewall should be built to which all IPv6 traffic is routed. The advantage of a separate IPv6 firewall is independence from the IPv4 infrastructure. Thus, you could build your own, optimized IPv6 network infrastructure and eliminate the issues of a legacy IPv4 infrastructure. However, except in very few environments, this course of action is complex and not easy to realize.
The configuration of a mature IPv6 network firewall requires in-depth expertise of IPv6. Although simple rules can be generated with just a few lines, they also offer only limited security or functionality. Because the firewall is the only protection in IPv6 for access from the Internet, and administrators cannot rely on the protection mechanism of NAT as they did with IPv4, the firewall is of fundamental importance.
Another task is to configure anti-spoofing rules. Attackers can possibly work around firewall rules by spoofing permitted addresses, so you must ensure that only valid addresses communicate on the respective interfaces.
Furthermore, IPv6 uses a number of communication types that also need to be considered: above all, the various tunneling mechanisms such as 6to4, ISATAP, or Teredo. In these cases, IPv6 is tunneled in IPv4 packets and transmitted over the IPv4 network. This practice is often undesirable, leading to unnecessary risks and must therefore be eliminated.
Preparing the Ruleset
ip6tables is usually configured with a firewall script. This step can occur at system startup, for example, from the
/etc/rc.local directory, or a separate init script can be called. For flexibility, it has proved useful to create variables for the interfaces first and then reference them in the lines of the ruleset. Also, networks or prefixes can be defined in this way. To make changes to an interface or a subnet prefix, you just need to adjust the variables.
# Interface definitions WAN_IF=eth1 LAN_IF=eth0 DMZ_IF=eth2 LAN_NET=2001:db8:1::/64 DMZ_NET=2001:db8:2::/64
Next, completely reset the firewall rules to delete any previously existing rules. You can use the
-F option for this. You also need to define a policy that applies if no other rule applies. The following applies as a general rule for firewalls: Everything that is not expressly permitted is forbidden. Accordingly, you would set the policy like this for all three chains:
# Delete the Ruleset ip6tables -F # Define a policy ip6tables -P INPUT DROP ip6tables -P FORWARD DROP ip6tables -P OUTPUT DROP
At this point, no communication to, from, or through the system is possible, not even loopback traffic (Figure 3). But, because loopback should always be allowed, you add a loopback rule:
# Allow loopback communication ip6tables -A INPUT -i lo -j ACCEPT ip6tables -A OUTPUT -o lo -j ACCEPT
Another important step is to enable stateful inspection by allowing everything that belongs to an existing communication:
# Enable stateful inspection ip6tables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT ip6tables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT ip6tables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
For all other forms of communication, sections with matching rules now follow.
To prevent an attacker from using an internal address for access to specific systems, you need to introduce some anti-spoofing measures. An approach that is supported by
ip6tables is to restrict the rules to incoming and outgoing interfaces so an internal sender address cannot arrive on any interface other than the LAN interface. Another possibility is the explicit rejection of incoming traffic from certain address ranges on the Internet interface. The two approaches are not mutually exclusive but complementary.
At this point, you can define some address ranges that should be discarded if they arrive on the external interface as the sender address. These include in particular the loopback address
1:: and the Unique Local Addresses
FC00::/7. As a result, you can define the following anti-spoofing rules:
# Anti-spoofing ip6tables -A INPUT ! -i lo -s ::1/128 -j DROP ip6tables -A INPUT -i $WAN_IF -s FC00::/7 -j DROP ip6tables -A FORWARD -s ::1/128 -j DROP ip6tables -A FORWARD -i $WAN_IF -s FC00::/7 -j DROP
The loopback rule was negated with an exclamation mark. The condition that follows must not be satisfied for the rule to apply. In this case, all packets with a sender address of
::1/128 that did not arrive via the loopback interface are blocked. Unique Local Addresses could theoretically occur on the internal network; you would thus restrict the filter for them to packets that arrive through the WAN interface. Strictly speaking, you would typically want to filter the outgoing packets in the
OUTPUT chain, but this is a secondary precaution, as long as the firewall itself has not been compromised.
You will want to save your firewall script in the meantime, then execute it and check the results. You can check the rules with
ip6tables -v -L (Figure 4).
Internal systems do not require a communication tunnel with native IPv6 connectivity. In this case, you can block the known tunnel prefixes for 6to4 and Teredo:
2001:0::/32. The following rules are the result:
# Block tunnel prefixes ip6tables -A INPUT -s 2002::/16 -j DROP ip6tables -A INPUT -s 2001:0::/32 -j DROP ip6tables -A FORWARD -s 2002::/16 -jDROP ip6tables -A FORWARD -s 2001:0::/32 -j DROP
You still have one important point to consider: IPv6 packets tunneled in IPv4 in part are not directly visible from the outside because they are prefixed with an IPv4 header. However, the protocol field in the IPv4 header contains a value of 41 to indicate IPv6 tunnel traffic. Thus, you can intercept this traffic on the IPv4 firewall; that is, using
ip6tables. The corresponding rule for tunneled traffic on the IPv4 firewall is:
# Block IPv6 in IPv4 iptables -A INPUT -p 41 -j DROP iptables -A FORWARD -p 41 -j DROP
Thus far, the firewall has been set up to block everything. Now you need to extend the firewall policy for the allowed traffic, and you should begin with the communication necessary for managing the firewall itself (i.e., incoming traffic).
Although the application protocols can vary from system to system, the following are often necessary: SSH (port 22/TCP), the secure remote shell; HTTPS (port 443/TCP), secure web access to potential web administration front ends; and SNMP (port 161/UDP), the Simple Network Management Protocol, which is often required by many monitoring systems.
Assuming that administration of the system is from the inside only, you can narrow down the interface for incoming traffic, thereby offering additional security. Additionally, you can restrict access to the LAN subnet. The bottom line is the following multiport rule:
# Administration ip6tables -A INPUT -i $LAN_IF -s $LAN_NET -p tcp -m multiport --dport 22,80,443 -j ACCEPT
Depending on the scenario, the firewall acts as a gateway to the outside world as a DNS proxy, or the internal systems use a dedicated DNS server, which can reside on the LAN or even on the Internet. DNS communication can be further limited, if necessary. In this sample scenario, you need to allow DNS traffic both on the firewall (if a DNS server is installed there) and traffic through the firewall to the Internet. Moreover, DNS traffic must be allowed from the firewall to the Internet (Listing 1).
Listing 1: Allowing DNS Traffic
# DNS Traffic ip6tables -A INPUT -i $LAN_IF -s $LAN_NET -p udp --dport 53 -j ACCEPT ip6tables -A FORWARD -i $LAN_IF -s $LAN_NET -p udp --dport 53 -j ACCEPT ip6tables -A OUTPUT -p udp --dport 53 -j ACCEPT
Web and Mail
If you only have internal systems in place that require browser and email client access to the Internet, you can handle the setup with three rules, or a single rule with the multiport option.
However, in the sample scenario, you need to allow access to the server in the DMZ via HTTP, HTTPS, and SMTP. This results in a total of six rules. With the multiport option, you can compress them to two rules (Listing 2).
Listing 2: Regions
# Web and Mail off the LAN ip6tables -A FORWARD -i $LAN_IF -s $LAN_NET -p tcp -m multiport --dport 25,80,443 -j ACCEPT # Web and mail from the Internet ip6tables -A FORWARD -i $WAN_IF -s 2000::/3 -d $DMZ_NET -p -m multiport tcp --dport 25,80,443 -j ACCEPT
At this point it would be possible to distinguish the outbound interfaces, if desired. The two rules include two important restrictions courtesy of the respective filters.
First, the sender address is limited to the IANA defined range of global unicast addresses; at the same time, access to the DMZ network is made conditional for letting the traffic pass. This means, conversely, that traffic from the outside to the internal systems is not allowed. If more applications are needed, the principle is always the same as shown.
IPv6 adds various new forms of communication that you should consider in your firewall rules, including, in particular, ICMPv6 with and without auto-configuration and path MTU (PMTU) discovery.
ICMPv6 is an integral part of IPv6 and thus obligatory – in contrast to IPv4, in which ICMP(v4) is optional. ICMPv6 implements various fundamental communication processes in IPv6: neighbor discovery (ICMPv6 types 135 and 136), router discovery (ICMPv6 types 133 and 134), and PMTU discovery (ICMPv6 type 2). Neighbor discovery and router discovery are only of interest for the
OUTPUT chains, but other ICMPv6 types must be allowed in the
FORWARD chain for smooth operation.
In particular, type 2 (Packet Too Big) is necessary for the PMTU discovery process. It involves the sender determining the smallest MTU en route to the destination and matching the IPv6 packets to this size. This step is essential because, in IPv6, routers no longer fragment packets – only the sender.
To determine the PMTU, packets are sent at the maximum size (e.g., 1500 bytes in Ethernet). If a router in the path to the target system determines that the packet is too large for the next segment of the route, it discards it and returns an ICMPv6 type 2 (Packet Too Big) to the sender. This message contains the value for the MTU that was exceeded. The sender then adjusts the packet size accordingly. If this feedback is blocked, communication with specific systems may be impossible because the sender does not know that its packet was discarded.
More ICMPv6 types that are mostly desirable and should not be blocked relate to problem reports: type 1 (Destination Unreachable), type 3 (Time Exceeded), and type 4 (Parameter Problem).
At least from the Internet, these ICMPv6 types should be allowed. Some types that exchange information also are often desirable: multicast listener discovery (130, 131, 132, INPUT, and OUTPUT) and ping (128 and 129, INPUT, OUTPUT, and FORWARD).
If you prefer to avoid giving the ICMPv6 protocol general power of attorney in allowing access, you have no alternative but to define detailed rules, as shown in Listing 3.
Listing 3: Rules for ICMPv6
# Feedback for problems ip6tables -A INPUT -p icmpv6 --icmpv6-type 1 -j ACCEPT ip6tables -A INPUT -p icmpv6 --icmpv6-type 2 -j ACCEPT ip6tables -A INPUT -p icmpv6 --icmpv6-type 3 -j ACCEPT ip6tables -A INPUT -p icmpv6 --icmpv6-type 4 -j ACCEPT ip6tables -A FORWARD -i $WAN_IF -p icmpv6 --icmpv6-type 1 -j ACCEPT ip6tables -A FORWARD -i $WAN_IF -p icmpv6 --icmpv6-type 2 -j ACCEPT ip6tables -A FORWARD -i $WAN_IF -p icmpv6 --icmpv6-type 3 -j ACCEPT ip6tables -A FORWARD -i $WAN_IF -p icmpv6 --icmpv6-type 4 -j ACCEPT # Router and neighbor discovery incoming and outgoing ip6tables -A INPUT -p icmpv6 --icmpv6-type 133 -j ACCEPT ip6tables -A INPUT -p icmpv6 --icmpv6-type 134 -j ACCEPT ip6tables -A INPUT -p icmpv6 --icmpv6-type 135 -j ACCEPT ip6tables -A INPUT -p icmpv6 --icmpv6-type 136 -j ACCEPT ip6tables -A OUTPUT -p icmpv6 --icmpv6-type 133 -j ACCEPT ip6tables -A OUTPUT -p icmpv6 --icmpv6-type 134 -j ACCEPT ip6tables -A OUTPUT -p icmpv6 --icmpv6-type 135 -j ACCEPT ip6tables -A OUTPUT -p icmpv6 --icmpv6-type 136 -j ACCEPT # Ping request to firewall from LAN and DMZ ip6tables -A INPUT ! -i $WAN_IF -p icmpv6 --icmpv6-type 128 -j ACCEPT # Ping request from firewall, LAN and DMZ ip6tables -A OUTPUT -p icmpv6 --icmpv6-type 128 -j ACCEPT ip6tables -A FORWARD ! -i $WAN_IF -p icmpv6 --icmpv6-type 128 -j ACCEPT
If multicast connections are required, you also need to consider the matching ICMPv6 types. This works like the rules in Listing 3.
To determine whether other ICMPv6 types are desirable or necessary in your production environment, detailed analysis of the respective infrastructure is necessary.
Conclusions and Outlook
In this article, I created a basic set of rules for an IPv6 firewall on which you can base a variety of additional rules specific to an environment.
Many rules apply to both worlds: IPv4 and IPv6. Although the basic configuration steps and the syntax in
ip6tables for IPv6 remain similar to
iptables for IPv4, you still need to consider some special cases in IPv6 that require individual handling – in particular, tunnel traffic and the ICMPv6 problem.
Even in a small environment, the ip6tables rules can become quite extensive. Thus, the question always arises as to whether the rules should be applied globally or to interfaces and subnets, or prefixes, or even individual hosts.
The more precisely you need the rules to filter your traffic, the more complex things become. One basic problem should be noted that is not specific to IPv6: A complex set of rules tends to give rise to administration errors. Sometimes less is more.
An aspect I have not addressed is the use of your own chains. It is usually desirable for the firewall to log what comes in and goes out and what was blocked. To do this, you create your own chains, which first log and then follow up an action – normally with DROP or ACCEPT. These filter rules are referenced by appropriate chains, which is like
iptables with IPv4.