Suppose I have this configuration on IPv4 right now:

My router (a Linux box) is connected to the Internet on eth0 and my LAN on eth1. I want to forward port 80 to Here's how I'd currently do that:

iptables -t nat -A PREROUTING -i eth0 -p tcp -m tcp --dport 80 -j DNAT --to iptables -A FORWARD -m conntrack --ctstate DNAT -j ACCEPT

Now I want to do the equivalent on IPv6. Suppose I have the same configuration as before, with these changes:

My ISP gives my router the range 2001:db8:aaaa::/64 via prefix delegation. My router takes 2001:db8:aaaa::1 for itself on eth1 and gives 2001:db8:aaaa::123 to the host that I want port 80 open on.

NAT is no longer necessary in the IPv6 case, so all I need is a firewall rule to allow the traffic. Here's the rule I can think of to do that:

ip6tables -A FORWARD -i eth0 -d 2001:db8:aaaa::123 -p tcp -m tcp --dport 80 -j ACCEPT

The problem I have with this is that I had to hardcode 2001:db8:aaaa::123 into my firewall rule, and the 2001:db8:aaaa:: prefix is subject to change at my ISP's whim. In the IPv4 world, the only IP that I had to hardcode was an internal one, so I knew it would never get changed out from under me. Is there any way I can allow traffic like this without having to modify a rule every time my ISP changes my delegated prefix? (If pf can do what I want but ip6tables can't, I'd be willing to switch to BSD for it.)

  • Downvote because unless you start out with an IPv6 address in the first place there is a protocol disconnect.
    – SDsolar
    Feb 22 '17 at 3:07
  • 3
    @SDsolar I'm not sure what you mean. Feb 22 '17 at 4:48

While there's no dedicated option, you can use the generic u32 iptables module (see iptables-extensions) to match just the interface ID part (which always starts at byte 32 of IP header):

-A FORWARD -m u32 --u32 "32 = 0x11223344 && 36 = 0xAABBCCDD" -j ACCEPT

This would match any destination address ending with :1122:3344:aabb:ccdd.

In IPv6 headers, the source address starts at byte 8 (network at 8, interface at 16); the destination address is at 24 (network at 24, interface at 32). You can use bitwise operations to implement things like CIDR mask matching in u32 as well.

  • This, in concert with DHCPv6 to get predictable local addresses. SLAAC can do whatever it want, after all.
    – Daniel B
    Feb 22 '17 at 7:51
  • 1
    So can DHCPv6. There's no rule saying that the DHCP server can't issue 15-minute leases and promptly forget about them the next day.
    – user1686
    Feb 22 '17 at 8:21
  • Yes of course. However, it’s the DHCP server that decides, not the client. In that regard, it is “predictable”.
    – Daniel B
    Feb 22 '17 at 10:55
  • 4
    Couldn't I just use the syntax ”-A FORWARD -d ::1122:3344:aabb:ccdd/::ffff:ffff:ffff:ffff -j ACCEPT" for that? I did a quick test and it seems to do the same as your solution. Also, this solution means I'm ignoring the network part altogether now. Couldn't this become a problem if it ends up matching something like a multicast or a private address that happens to have the same ending? Feb 22 '17 at 17:04
  • 3
    @JosephSible: You could still post it as an answer so it stands out, and list any shortcomings there - answers don't need to be perfect, that's why there's room for more than one answer! I think for the most common situations (e.g. home networks) your solution will work just fine, because sure you might forward more traffic than you expect, but there likely won't be any hosts listening on those extra IPs. If there are issues with this solution, an answer is a great place to list them all for everyone's benefit!
    – Malvineous
    Nov 6 '17 at 7:07

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.