I am facing an IPv6 accessibility problem with my server.

  • The server is IPv6-capable and is capable of contacting/being contacted by third-parties on IPv6 (ping6 and traceroute6 tested on my Debian stable Wheezy, up-to-date)
  • The DNS IPv6 AAAA entry for the website is existing and functioning properly
  • The webserver (nginx) is listening on the IPv6 link and is ready to handle the requests the same way as it is for IPv4
  • ip6tables INPUT table is configured to allow HTTP requests just like iptables (default policy DROP + TCP 80 ACCEPT rule):

    Chain INPUT (policy DROP 648 packets, 46788 bytes)
    pkts bytes target     prot opt in     out     source               destination
    6   480 ACCEPT     tcp      *      *       ::/0                 ::/0                 tcp dpt:80

I narrowed the problem down to the fact that if I set the default policy to ACCEPT, the HTTP connection works, otherwise not.

Thus, it seems than some other port redirections might be required? oO

Could that be related to some kernel configuration of the routing/IPv6 stack?

Here is the output of sudo ip6tables --line-numbers -nvL:

Chain INPUT (policy DROP 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination
1     8169  784K ACCEPT     all      *      *       ::/0                 ::/0                 state RELATED,ESTABLISHED
2        0     0 ACCEPT     tcp      *      *       ::/0                 ::/0                 tcp dpt:22
3        0     0 ACCEPT     tcp      *      *       ::/0                 ::/0                 tcp dpt:80
4        0     0 ACCEPT     tcp      *      *       ::/0                 ::/0                 tcp dpt:443

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination
  • Consider adding a logging line with e.g. ip6tables -A INPUT -j LOG --log-prefix "INPUT6 DENY: " --log-level 6 and looking in the appropriate system log for the packets that are being refused when the policy is not ACCEPT and you try telnet ipv6.address 80 from off-server. It would also be useful to know what you currently mean by "the HTTP connection doesn't work". – MadHatter Jul 22 '14 at 14:07
  • Your firewall looks fine. Are you sure the problem isn't elsewhere? What is your IPv6 address? – Michael Hampton Jul 22 '14 at 14:40
  • the HTTP connection doesn't work means that trying to access the webserver on standard TCP 80 fails when firewall is up (default policy DROP) but works when down (default policy ACCEPT). I will try the logging rule and come back to you with its results – Bernard Rosset Jul 22 '14 at 19:29
  • I think you have a bigger problem than port 80; I cannot ping6 that address at all. Those tests are not biased per se, but ipv6-test.com tests much more than just v6 connectivity; there's all sorts of DNS and service configuration stuff caught up in it as well. The chair6 tester seems to have similar problems. I would strongly advise you to chase possible firewall issues down with telnet from a known-v6-enabled client system, using just ipv6 addresses. – MadHatter Jul 23 '14 at 7:01
  • You could not ping this address since icmpv6 packets were not allowed (as the ip6tables configuration above show it). I just added a rule to allow them so you should now be able to ping it. – Bernard Rosset Jul 23 '14 at 17:13

Folks, you must not ignore ICMPv6 as you did for legacy IP - ICMPv6 and particularly the Neighbor Discovery Protocol (NDP) is vital for the proper functioning of IPv6. (The NDP, among other things, is a substitute for ARP.)

This means, you must allow at least for ICMPv6 types 133-136 from link local (i.e. fe80::/10). Moreover, you must allow certain error messages to arrive, as for instance routers don't fragment any more. You also don't want to drop link local multicast messages.

The full story is told in RFC 4890.

Below is an excerpt from one of my machines, a vm host that acts as a router:

#! /bin/sh

drop () {
    /sbin/ip6tables --jump DROP --append "$@";

accept () {
    /sbin/ip6tables --jump ACCEPT --append "$@";

chain () {
    /sbin/ip6tables --new-chain "$@"

ICMP_RATELIMIT="--match limit --limit 2/s"

# ...

#       Validate ingoing ICMPv6 messages
chain   ICMPv6_IN

# error messages

# allow error messages that are related to previously seen traffic
accept  ICMPv6_IN --protocol icmpv6 --icmpv6-type destination-unreachable --match conntrack --ctstate ESTABLISHED,RELATED $ICMP_RATELIMIT
accept  ICMPv6_IN --protocol icmpv6 --icmpv6-type packet-too-big --match conntrack --ctstate ESTABLISHED,RELATED $ICMP_RATELIMIT
accept  ICMPv6_IN --protocol icmpv6 --icmpv6-type ttl-exceeded --match conntrack --ctstate ESTABLISHED,RELATED $ICMP_RATELIMIT
accept  ICMPv6_IN --protocol icmpv6 --icmpv6-type parameter-problem --match conntrack --ctstate ESTABLISHED,RELATED $ICMP_RATELIMIT

# accept neighbor discovery
accept  ICMPv6_IN --protocol icmpv6 --icmpv6-type neighbor-solicitation $ICMP_RATELIMIT
accept  ICMPv6_IN --protocol icmpv6 --icmpv6-type neighbor-advertisement $ICMP_RATELIMIT

# accept router discovery
accept  ICMPv6_IN --protocol icmpv6 --icmpv6-type router-solicitation '!' --src ff00::/8 --in-interface cafe0 $ICMP_RATELIMIT
accept  ICMPv6_IN --protocol icmpv6 --icmpv6-type router-advertisement --src fe80::/10 --in-interface wlp3s0 $ICMP_RATELIMIT

# ping
# accept replies to my ping requests
accept  ICMPv6_IN --protocol icmpv6 --icmpv6-type echo-reply --match conntrack --ctstate ESTABLISHED,RELATED

# allow ping from my network(s)
accept  ICMPv6_IN --src $COUNTERMODE --protocol icmpv6 --icmpv6-type echo-request $ICMP_RATELIMIT

# allow link-local unicast ping
accept  ICMPv6_IN --dst fe80::/10 --protocol icmpv6 --icmpv6-type echo-request $ICMP_RATELIMIT

## allow multicast ping from local link
#accept  ICMPv6_IN --dst ff00::/8 --src fe80::/10 --protocol icmpv6 --icmpv6-type echo-request $ICMP_RATELIMIT

# multicast listener discovery v1
accept  ICMPv6_IN --protocol icmpv6 --icmpv6-type 130 --in-interface cafe0
accept  ICMPv6_IN --protocol icmpv6 --icmpv6-type 131 --in-interface cafe0
accept  ICMPv6_IN --protocol icmpv6 --icmpv6-type 132 --in-interface cafe0

# multicast listener discovery v2
accept  ICMPv6_IN --protocol icmpv6 --icmpv6-type 143 --in-interface cafe0

# drop everything else
drop ICMPv6_IN
| improve this answer | |
  • Thanks! That must have been the problem indeed. Reading RFC4890, it seems that attempting to filter ICMPv6 might be too cumbersome. Moreover, ip6tables has limited support for 'named types' for the ICMPv6 protocol which would force one wishing to filter in everything possible/necessary to rely on numbered types/codes which would be, in the end, hard to read. Furthermore, the RFC clearly advise not to filter ECHO requests/replies (though its 'IPv6-is-secure argument' seems edgy). At the end of the day, just accepting the all ICMPv6 packets is way simpler – Bernard Rosset Jul 30 '14 at 17:47
  • Well, that's not the way to go either. See my edited post for a sample ip6tables configuration. – countermode Jul 30 '14 at 17:51
  • According to RFC4890, section 4.3, there are way more stuff that MUST/SHOULD NOT be allowed, in the end, almost all known types/codes. You would need 10/15 lines in a dedicated table to handle them all... In the end, isn't it the same as the 'all-in' method? Btw, does 4.3 apply to 'outside' interfaces and 4.4 to 'link-local' ones? – Bernard Rosset Jul 30 '14 at 17:53
  • Well, the principle to drop everything that you don't need applies. And some stuff is valid only link-local and should be rejected otherwise. Better 10 to 15 lines of what to allow than allowing all 255 ICMPv6 types. Especially Types 138, 139 and 140 are security wise no-nos. In the end its not so difficult, you just need to get used to it. See the code sample. – countermode Jul 30 '14 at 18:07
  • Acknowledged. Your 'allow ping from my network(s)' rule seems to address networks outside the link-local scope. That is a non-standard feature for a sample configuration. If the ping is deactivated on the global scope, won't it prevent IPv6 connectivity? RFC states 'As discussed in Section 4.3.1, dropping connectivity checking messages will prevent the firewall being the destination of a Teredo tunnel and it is not considered necessary to disable connectivity checking in IPv6 networks because port scanning is less of a security risk.' – Bernard Rosset Jul 30 '14 at 18:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.