Linux Security Guide for Hardening IPv6
Version 6 of Internet Protocol is now 20+ years available. You would think it is widely available now, right? Not exactly. Still many internet providers don’t have it deployed for their customers. Hosting companies are not always eager to deploy it either. Mostly because of lacking knowledge. To get at east more knowledge shared on the security side of IPv6, we have crafted this guide. Hopefully it will be a practical guide for your to configure and tune your configurations.
The Need for a New Version
The addressing scheme for version 4 was thought to sufficient at the time. With the widespread usage of the web and services on the internet in general, this turned out differently. With some trickery, we were able to extend the possibilities, like subnetting and running multiple websites on one single IP address. Last year, the last pools of available IP addresses were depleted and it is time to move forward.
Version 6 of the Internet Protocol promises that address space will never be a problem anymore. Even if we were to give every human, device, and trees, their own address. We will see if that holds true in the next 20 years to come.
Do I Really Need It?
Most guides on the internet tell you a simple thing: disable IPv6 if you don’t need it. That sounds logical and is a good hardening principle. Unfortunately, this advice might also be harmful. For example, the web really benefits if we make the transition to IPv6. Instead of fearing away for some of the known attacks, it is better to build up a good understanding of the subject and take the right measures. Still, if you feel IPv4 will do in your internal network, then use that and disable IPv6. In any case, keep reading and make the world a safer place.
Before we start talking about hardening, it makes sense to do a gentle introduction into IPv6. After all, there are still a lot of people who never used or configured it.
IPv6 Basics
Although the subject is very extensive, with lots of standards and RFCs, here are the basics of the new protocol.
- No ARP (neighbor discovery instead, based on ICMPv6)
- No broadcasts (lots of multicast instead)
- Hierarchical address space (with clear functions and separation)
- Multiple IP addresses per interface, with different scopes
- Header is simplified, modular due to extensions and chaining
Neighbor Discovery
Instead of using ARP, multicast is used other to detect other systems and routers. For the discovery of routers there are Router Advertisements and Router Solicitations, for other systems Neighbor Advertisement and Neighbor Solicitation. These advertisements and solicitations help hosts to find their way on the network. Depending on the configuration, the right device(s) will respond to a query. For example the initial task to obtain an IP address with the right prefix.
IPv6 Addresses on First Sight
If you never worked with IPv6 before, the new addresses can be overwhelming. No longer the short IP addresses we are used to, divided by dots. Instead, we get colons and additional letters. To avoid this blog post becoming a book, we will skip on all the details regarding addressing. Instead, let’s have a look at some common addresses:
- ::1/128 - Localhost (IPv4 alternative: 127.0.0.1)
- fc00::/7 - Unique Local Addresses (ULAs) (IPv4 alternative: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16)
- fe80::/10 - Link-Local Addresses, used on the internal network (IPv4 alternative: 169.254.0.0/16)
- 2001::1000::/32 - Global addresses (Teredo)
- 2002::/16 - Global addresses (6to4)
The other addresses are usually external addresses (global), or special purpose addresses. If you want to know more about these address types, use the RIPE IPv6 sheet as a handy reference.
Let’s leave addressing and move towards configuration.
IPv6 Configuration Basics
Linux distributions are all slightly different. In this guide, we will show several examples. For specific configuration of your favorite Linux distribution, have a look at the More Resources section, located at the end.
Before doing any configuration at all, why not first determine what is configured? This commands are also helpful for auditors and security professionals, to understand configurations better. Previously the ifconfig command was used by many distributions, with the ip command being its common replacement. First step is determining what interfaces are configured, and in particular which have a version 6 configuration.
ip -6 addr
This command shows address information per interface, highlighting only the interface specifics of the version 6 family. For example, any link-local IPv6 address ends with a suffix: scope link. Interfaces or addresses with a global static configuration, have the suffix scope global static. Systems configured via SLAAC will show scope global dynamic. When private extension address is used, it will show scope global temporary dynamic, and for expired items: scope global temporary deprecated. As you quickly will see on your environments, every system is differently configured. So it is good to know these types exists.
If your Linux distribution uses systemd, changes are high that you are using the systemd-networkd service. Querying its status can be done with systemctl.
systemctl status systemd-networkd
The status output of systemd will show something like “Gained IPv6LL”, when it received a Link-Local address. As with the ip command, the output depends on the type of address being configured on the interface.
These two tools can already provide some insight. Time to get closer to the in-depth configuration of IPv6 itself.
Manual versus Automatic Configuration
Time to make changes to the system and set up IPv6. The first choice to make is if we want to use automatic configuration, or do it by hand. The first option simplifies things a lot. Using manual configuration gives you more control regarding the configuration. It also counters a few known attacks, so for specifically hardening purposes it is the best bet. The best option for your environment? It really depends on your networking architecture and what type of machines are in it.
Automatic Configuration
Two common ways for providing addresses to new and existing clients, is using SLAAC (Stateless address auto-configuration) or DHCPv6. First question you might ask yourself, is which one to use. Unfortunately, the answer depends on your environment, used devices and their support for IPv6.
A quick dive into both:
SLAAC
- Uses Multicast ICMPv6
- Provides IPv6 prefixes
- Router advertisement provide addressing, routing, MTU and other options.
- Privacy issue: uses MAC address (which can be countered with privacy extensions turned on)
DHCPv6
When using the stateful configuration of DHCPv6:
- Client/Server
- Uses multicast UDP
- Provides addressing, routing, NTP, SIP, DNS, other options
The stateless DHCPv6 configuration will use SLAAC with the flag O=1 (Other Config) set, followed by extra configuration options via DHCPv6.
System Configuration on Linux Systems
Time to apply some configuration!
Arch Linux
When using netctl, use the following line and add it to your interface configuration file:
IP6=stateless
If you are using NetworkManager, you should receive automatically an IPv6 address, when advertised. When using the newer systemd-networkd, reload with:systemctl restart systemd-networkd
systemctl restart systemd-networkd
CentOS
Change the related network configuration file, with the right interface. For example /etc/sysconfig/network-scripts/ifcfg-eth0.
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_PEERDNS=yes
IPV6_PEERROUTES=yes
IPV6_FAILURE_FATAL=no
Debian and Ubuntu
Change the /etc/network/interfaces
file.
iface eth0 inet6 auto
Note: newer versions of Debian and Ubuntu most likely don’t use this file anymore
Manual Configuration
If you don’t want to use SLAAC or DHCPv6, it is time to make some serious changes. First step is turning of auto-configuration. Add the following lines to your /etc/sysctl.conf
net.ipv6.conf.all.autoconf=0
Systems running Red Hat distribution like RHEL, might need another change in their network configuration file, which is usually /etc/sysconfig/network.
NETWORKING_IPV6=yes
IPV6_AUTOCONF=no
On a regular basis people are advised to also disable the router advertisements (RA). This is done with the sysctl key net.ipv6.conf.all.accept_ra sysctl. This is actually not advised. As a starter, these RAs help hosts determining if a system is the same subnet, in other words if they are on-link or off-link. Also the configuration of DNS and packet size (MTU) is arranged with RAs. For neighbor discovery (the IPv6 equivalent of ARP), timeouts, and other settings are determined. So in other words, if you decide to disable RA, make sure you really know what you are doing. You might find trouble later on, which was simply caused by ignoring RAs.
Here are some tips for the most common Linux distributions to get you started. Note that some of these configurations can change over time, as systemd is gaining in popularity.
Arch Linux and Fedora 21+
Systems using systemd, need to be configured via systemd-networkd. Change file /etc/systemd/network/50-static.network.
[Match]
Name=eth0
[Network]
Address=192.168.1.2/24
Gateway=192.169.1.1
Address=fe80::2/64
Gateway=fe80::1
Reload network configuration:
systemctl restart systemd-networkd
IPV6 Configuration for Debian and Ubuntu
Change your /etc/network/interfaces file
iface eth0 inet6 static
address aaaa:bbbb::abcd:abcd
netmask 64
mtu 1280
gateway aaaa:bbbb::abcd::1
CentOS and Red Hat (RHEL)
Change the related interface in the directory /etc/sysconfig/network-scripts, starting with ifcfg-*.
IPV6INIT=yes
IPV6ADDR=fe80::100/64
IPV6_DEFAULTGW=fe80::1/64
DNS1=fe80::10/64
DNS2=fe80::20/64
Reload configuration (older versions of CentOS/RHEL)
service network restart
Reload configuration (CentOS/RHEL)
nmcli reload
nmcli con down "System eth0"
nmcli con up "System eth0"
Testing Connectivity
For most common utilities there is an IPv6 variant available. For ping this is ping6 and provides similar functionality.
If you get a “connect: Invalid argument” error with ping6, you might wonder why that is. Because of the routing and dual stack involved, you need to specify the interface.
ping6 -I enp0s3 fe80::800:27ff:fe00:1
An alternative is leaving out the -I parameter and append % (e.g. %eth0) to the address.
ping6 fe80::800:27ff:fe00:1%enp0s3
Another tricky item is the usage of Link-Local addresses on Linux, and the related name resolving. During testing, you may receive the error “unknown host”. Even if you are certain the hostname and IP address are correct. If you encounter this, ping the IPv6 address manually instead. Use a tool like dig or host, to check if the AAAA records are properly configured. These are the equivalent of A records for IPv4 addresses.
Troubleshooting
To find why things don’t work as expected, start using the ip command as shown before. This will provide you the interface details. Other useful sources are dmesg for kernel related messages. Check your syslog and systemd logging.
IPv6-only or Not?
Another decision to make is the communication protocol for the machine. If no IPv4 mappings are needed, a possibility is to go to IPv6-only. Change this particular sysctl key and add it to /etc/sysctl.conf to persist after a system reboot.
net.ipv6.bindv6only=1
**Relevant RFC: **RFC 3493 - Basic Socket Interface Extensions for IPv6
IPv6 Hardening on Linux
Besides the specific configuration type, we can apply additional layers of system hardening to our IPv6 network configuration.
As discussed before, disabling router advertisements can be good for hardening. At the same time, it may result in a lot more tweaking. If you decided to go for it, then add the following lines to your /etc/sysctl.conf file.
net.ipv6.conf.all.accept_ra=0
net.ipv6.conf.default.accept_ra=0
Enable IPv6 Privacy Extensions
When clients receive an address through SLAAC, it is created by combining an advertised prefix with the (physical) MAC address of the network card. If you rather don’t create addresses based upon MAC addresses, enable the privacy extensions in IPv6. Add the following lines to /etc/sysctl.conf.
# Enable the IPv6 Privacy Extensions: do not use MAC address
net.ipv6.conf.all.use_tempaddr=2
net.ipv6.conf.default.use_tempaddr=2
Configuration with NetworkManager
When using NetworkManager, ensure that it also is configured properly.
/etc/NetworkManager/NetworkManager.conf
[connection]
ipv6.ip6-privacy=2
Configuration with systemd-networkd
For systemd-networkd, open up your configuration file (e.g. /etc/systemd/network/wired.network) and locate the [Network] section. Define IPv6PrivacyExtensions and set to true.
[Network]
DHCP=yes
IPv6PrivacyExtensions=true
Rate Limiting
To protect against denial of service (DoS) attacks, limiting resources is usually a good counter measure. At the same time caution is advised, as sometimes changes can actually increase the chance of an accidental denial of service by legitimate usage. So in all cases check the business purpose of your machine and what a typical network load is expected.
- net.ipv6.icmp.ratelimit - limit in time (ms), default 1000
At this moment, IPv4 has more sysctl keys available than IPv6. The main reason for this is simply that not all features are ported yet.
net.ipv4.icmp_echo_ignore_all = 0
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_errors_use_inbound_ifaddr = 0
net.ipv4.icmp_ignore_bogus_error_responses = 1
net.ipv4.icmp_msgs_burst = 50
net.ipv4.icmp_msgs_per_sec = 1000
net.ipv4.icmp_ratelimit = 1000
net.ipv4.icmp_ratemask = 6168
Firewalling with IPv6
Firewalls are still a common hardening measure. Its effectiveness to filter out network traffic is high, while rule sets are usually fairly easy to set up. To counter some of the attacks on Linux systems, we can filter out some of the bad traffic involved with known IPv6 attacks.
ip6tables
At this moment, ip6tables is still the common firewall to be used. It has proven its stability over the years and helps with filtering out the good and bad traffic.
nftables
Most likely nftables will replace iptables and ip6tables in the upcoming years. It does simplify rule sets a lot. Another benefit of nftables is that the ip and ip6 protocol families can be merged into inet, to further simplify things. No more double rules!
Allow several types of IPv6 ICMP packets:
nft add rule ip6 traffic-filter input icmpv6 type { nd-neighbor-solicit, echo-request, nd-router-advert, nd-neighbor-advert } accept
What to Filter?
Most networks will be using a dual-stack implementation for IP traffic. Therefore it is important to ensure that both IP versions are filtered. It would be a shame if you tightened your firewall, just to find out that via IPv6 everything is available.
Another option is to filter out traffic from unexpected ranges. With the earlier mentioned guide from RIPE, you can quickly find out what you want to allow, block the rest of the traffic. Also apply DHCPv6 filtering and restrict access of UDP ports 546 and 547.
Additional reads:
IPv6 sysctl: Keys and Values Explained
With IPv6 enabled on your Linux system, a lot of additional sysctl keys will be listed. Let’s break them up and understand each section.
IPv6 Neighbor Configuration
net.ipv6.neigh.[interface].[key]
The neighbor configuration settings are applied to an interface. So you the choice to define a particular interface with specific settings. If you want to apply them all interfaces, change your /etc/sysctl.conf and override a setting to the all and default, to make them applicable for all interfaces.
IPv6 Routing
net.ipv6.route.gc_elasticity = 9
net.ipv6.route.gc_interval = 30
net.ipv6.route.gc_min_interval = 0
net.ipv6.route.gc_min_interval_ms = 500
net.ipv6.route.gc_thresh = 1024
net.ipv6.route.gc_timeout = 60
This first batch of keys within routing, determine the garbage collecting. This process cleans out old entries, usually to free up memory and increase performance. If your machine has a very particular role requiring many simultaneous connections or sessions, consider diving into tweaking these. Otherwise, leave them on their default value.
net.ipv6.route.max_size = 4096
net.ipv6.route.min_adv_mss = 1220
net.ipv6.route.mtu_expires = 600
The max_size defines the maximum routes in the kernel. Then there is min_adv_mss, the minimum advertised MSS (maximum segment size). It depends on the MTU (maximum transmission unit) of the first hop. Be careful with adjusting this, as it can introduce unexpected network behavior. Last there is the mtu_expires, which defines how long items for the MTU will be cached (in seconds).
Generic IPv6 Settings
Sysctl: net.ipv6.xfrm6_gc_thresh
Garbage collector threshold. Unless you have specific tuning requirements for your machine, keep it at the default value (e.g. 32768).
Flow labels
Flow labels help marking a connection. Normally this is done with the combination of details regarding sender and receiver, port numbers and sequence numbers. Due to fragmentation, encryption and other reasons, it may be hard to know to which previous flow a new incoming packet belongs. Flow labels solve this problem.
Normally the defaults (1) for both net.ipv6.flowlabel_consistency and net.ipv6.flowlabel_state_ranges will do.
Relevant RFC: RFC6437 - IPv6 Flow Label Specification
Firewall Marks
If you are using firewall marks, this boolean on net.ipv6.fwmark_reflect will define if the fwmark property will be set to zero, or the value to which fwmark it is applicable. For most users keeping this the default value will be fine.
ICMP Rate Limiting
The setting net.ipv6.icmp.ratelimit limits the amount of ICMP packets, expressed in miliseconds. Default value is 1000.
IPv6 Fragmentation
net.ipv6.ip6frag_high_thresh = 4194304
net.ipv6.ip6frag_low_thresh = 3145728
net.ipv6.ip6frag_secret_interval = 600
net.ipv6.ip6frag_time = 60
These keys deal with fragmentation of packets. The time determines how long one can stay in memory, before being thrown out. If you want to apply some hardening, you can lower this, depending on the type of traffic you are serving. The ip6frag_secret_interval setting defines the interval (and lifetime) of a hash secret. This secret is used to ensure fragments can be identified quickly as being from a source we already communicated with. All other unknown fragments might be malicious, with the goal to exhaust system resources.
Common IPv6 Actions and Commands
Disable IPv6
net.ipv6.conf.all.disable_ipv6=1
net.ipv6.conf.default.disable_ipv6=1
net.ipv6.conf.lo.disable_ipv6=1
Use disable_ipv6 and activate changes with sysctl -p. Change your /etc/sysctl.conf file as well. This way changes remain active after a system reboot. You can also disable IPv6 on a single network interface. In that case define the sysctl setting only for that particular interface.
Other ways include disabling it in the kernel, like disabling the related kernel modules. Add this to your modprobe configuration, which is usually stored in /etc/modprobe.d/.
install ipv6 /bin/true
Delete an IP Address
ip -6 addr del <address> dev <interface>
Deleting an address from an interface can be done with the ip command. Note that when auto-configuration is used, addresses may reappear.
Preference for IPv6
Already using IPv6 within your network? In that case you might prefer AAAA records for systems, instead of A records. You can instruct the resolver to use that instead in your resolver configuration, which is stored in the /etc/resolv.conf file.
options inet6
As always, test before you deploy.
Package Managers and IPv6
Most network services are nowadays aware of the existence of both IPv4 and IPv6. Depending on your configuration, your package manager may need some configuration to work properly as well.
APT (Debian / Ubuntu)
Use the settings Acquire::ForceIPv4 and Acquire::ForceIPv6 to specify what protocol version you want to use.
IPv6 Security Testing Utilities
There are several packages which focus specifically on testing IPv6 and some known weaknesses. Here is a quick overview if you want to test them in your lab.
THC-IPv6
The THC-IPv6 toolkit helps attacking several weaknesses in the IPv6 protocol, including ICMP6.
- 6to4test - Check if IPv4 address has dynamic 6to4 tunnel setup
- alive6 - Detects systems listening to an address
- denial6 - Denial of Service (DoS) tests againsts a specified target
- detect-new-ip6 - Detect new IPv6 devices joining the network
- dos-new-ip6 - Detect new IPv6 devices and causing Denial of Service (DoS)
- exploit6 - Test for known IPv6 vulnerabilities
- fake_mipv6 - Take away mobile IP when IPSEC is not used
- firewall6 - Firewall testing utility
- flood_advertise6 - Flood utility with neighbor advertisements
- flood_router6 - Flood utility router advertisements
- implementation6 - Perform implementation checks
- parasite6 - Spoofing utility for ICMP neighbor solicitations/advertisements
- redir6 - Spoof traffic via ICMP6
- rsmurf6 - Remote ICMP flood attack utility
- smurf6 - Local ICMP flood attack utility
- thcping6 - Custom ICMP packets
- trace6 - Alternative tool for traceroute6 (with ICMP6 echo request and TCP-SYN)
Other great tools:
- soca
- nc6
- ndisc6 (ICMPv6 Neighbor Discovery tool)
- Scapy (package manipulation)
- SI6 Networks IPv6 Toolkit
- Nmap
- Evil FOCA
More IPv6 Resources
There are many resources available regarding IPv6. To help you find more specific details for your platform, we have collected some.
Related RFCs
IP version 6 has a nice collection of Request For Comments (RFC):
- RFC 1981 - Path MTU discovery for IP version 6
- RFC 2460 - Internet protocol, version 6 (IPv6) specification
- RFC 2461 - Neighbor discovery for IP version 6 (IPv6)
- RFC 2462 - IPv6 stateless address autoconfiguration
- RFC 2464 - Transmission of IPv6 packets over Ethernet networks
- RFC 2465 - Management Information Base for IPv6: Textual Conventions and General Group
- RFC 2472 - PPPv6 (Red Hat only)
- RFC 2710 - Multicast Listener Discovery (MLD)
- RFC 3041 - Privacy Extensions
- RFC 3056 - Connection of IPv6 Domains via IPv4 Clouds
- RFC 3315 - Stateful DHCPv6
- RFC 3484 - Default Address selection
- RFC 3493 - Basic Socket Interface Extensions for IPv6
- RFC 3596 - DNS Extensions to support IPv6
- RFC 3810 - Multicast Listener Discovery Version 2 (MLDv2)
- RFC 3971 - SEcure Neighbor Discovery (SEND)
- RFC 4007 - IPv6 Scoped Address Architecture
- RFC 4193 - Unique Local IPv6 Unicast Addresses
- RFC 4213 - Transition Mechanisms for IPv6 Host and Routers
- RFC 4291 - IPv6 Addressing Architecture
- RFC 4443 - Internet Control Message Protocol (ICMPv6) for the Internet Protocol Version 6 (IPv6) Specification
- RFC 4890 - Recommendations for Filtering ICMPv6 Messages in Firewalls
- RFC 5942 - IPv6 Subnet Model: The Relationship between Links and Subnet Prefixes
- RFC 6104 - Rogue IPv6 Router Advertisement Problem Statement
- RFC 6105 - IPv6 Router Advertisement Guard
- RFC 6106 - IPv6 Router Advertisement Options for DNS Configuration
- RFC 6437 - IPv6 Flow Label Specification
- RFC 6980 - Security Implications of IPv6 Fragmentation with IPv6 Neighbor Discovery
- RFC 7381 - Enterprise IPv6 Deployment Guidelines
Operating Systems
- Arch Linux - IPv6 wiki page
- Gentoo - IPv6 Router Guide
Other
- Linux Source - Linux Cross Reference guide for IPv6
- Sysctl keys and details for networking
- Hardening guide by ERNW
Found this guide helpful, or have other tips to secure IPv6 configurations on Linux? Let it know!