Debian ip6tables rules setup for IPv6

user1447499 asked:

I am setting up a firewall for ipv6 on Debian Squeeze. It is a webserver, so I think the only port that need to be open to the world for ipv6 is 80.

This is what I have:

:in-new - [0:0]
-A INPUT  -i lo -s ::1/128 -j ACCEPT
-A OUTPUT -o lo -d ::1/128 -j ACCEPT
-A INPUT -s fe80::/10 -j ACCEPT
-A INPUT -m rt --rt-type 0 -j DROP
-A OUTPUT -m rt --rt-type 0 -j DROP
-A FORWARD -m rt --rt-type 0 -j DROP

-A INPUT -p tcp ! --syn -m state --state NEW -j DROP

-A INPUT -m state --state INVALID -j DROP

-A INPUT -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE -j DROP
-A INPUT -p tcp -m tcp --tcp-flags SYN,FIN SYN,FIN          -j DROP
-A INPUT -p tcp -m tcp --tcp-flags SYN,RST SYN,RST          -j DROP
-A INPUT -p tcp -m tcp --tcp-flags FIN,RST FIN,RST          -j DROP
-A INPUT -p tcp -m tcp --tcp-flags ACK,FIN FIN              -j DROP
-A INPUT -p tcp -m tcp --tcp-flags ACK,URG URG              -j DROP

-A INPUT -d ff02::1 -j REJECT

-A INPUT  -p tcp -m state --state ESTABLISHED  -j ACCEPT
-A OUTPUT -p tcp -m state --state NEW,ESTABLISHED -j ACCEPT
-A INPUT  -p udp -m state --state ESTABLISHED  -j ACCEPT
-A OUTPUT -p udp -m state --state NEW,ESTABLISHED -j ACCEPT

-A INPUT    -p IPv6-icmp -j ACCEPT
-I OUTPUT   -p IPv6-icmp -j ACCEPT
-I FORWARD -p IPv6-icmp -j ACCEPT

-A INPUT -p tcp -m tcp --dport 80 --tcp-flags SYN,RST,ACK SYN -m state --state NEW -j ACCEPT
-A INPUT    -j LOG --log-level 4 --log-prefix "IPT_INPUT: "

-A FORWARD -j LOG --log-level 4 --log-prefix "IPT_FORWARD: "
-A OUTPUT   -j LOG --log-level 4 --log-prefix "IPT_OUTPUT: "


I found it somewhere on the inernet and changed it a little bit, but when I try to retore it it gives the following error:

sudo ip6tables-restore < /etc/ip6tables.firewall.rules
ip6tables-restore: line 47 failed

Any idea how to setup my ip6tables so it will work?

Thank you.

My answer:

I don’t know where you got that abomination, but the best thing you can do is delete it and start over from scratch. Its primary problem is that it’s needlessly complicated and difficult to follow, even if it might work (and I can’t be sure from reading it, so I’m certainly not going to test it).

Firewalls should be as simple as possible: Accept only what you need and reject everything else. Follow this and you won’t need any complicated and difficult to understand rules.

So let’s take a look at a live, working IPv6 iptables firewall. I just pulled this off one of my live servers:

# Firewall configuration written by system-config-firewall
# Manual customization of this file is not recommended.

We set default policies for the tables to ACCEPT; the traffic will actually be dropped by rules within each table. This gives us more flexibility. In particular, the OUTPUT table should always be set to a default policy of ACCEPT unless you intend to block outgoing connections.

-A INPUT -m rt --rt-type 0 --rt-segsleft 0 -j DROP
-A FORWARD -m rt --rt-type 0 --rt-segsleft 0 -j DROP
-A OUTPUT -m rt --rt-type 0 --rt-segsleft 0 -j DROP

This fixes the IPv6 Routing Header Type 0 security issue. It should appear before any other rules. (Note that modern kernels since automatically drop this traffic and do not need these rules. If you have a previous kernel, contact your distribution vendor for a patch for CVE-2007-2242.)


This accepts ongoing traffic for any existing connections that we’ve already accepted through other rules.

-A INPUT -p ipv6-icmp -j ACCEPT

We accept all ICMP packets. Unlike with IPv4, it’s not a good idea to block ICMPv6 traffic as IPv6 is much more heavily dependent on it.

-A INPUT -i lo -j ACCEPT

We accept all traffic from/to the local interface.

-A INPUT -m state --state NEW -m udp -p udp --dport 546 -d fe80::/64 -j ACCEPT

We accept DHCPv6 traffic. If you use stateless autoconfiguration, or statically configure your machines, this is not necessary.

-A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT

These accept new connections for ssh and http.

-A INPUT -j REJECT --reject-with icmp6-port-unreachable
-A FORWARD -j REJECT --reject-with icmp6-port-unreachable

At the end of our rules, we reject all traffic that didn’t match a rule, using “port unreachable”. This results in the standard “Connection refused” message at the other end, and effectively hides the fact that we have a firewall. Tools such as nmap will report that all our ports are “closed” rather than “filtered” and have a much more difficult time determining that we even have a firewall.


This commits all the table entries.

View the full question and answer on Server Fault.

Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.