LowEndBox - Cheap VPS, Hosting and Dedicated Server Deals

IPtables: IPv6 and more rules


This is the last tutorial in a series of iptables tutorials. Last week I’ve shown you how to persist iptables. The week before that I gave a short introduction. I now want to finish that series with talking about IPv6 and adding more (advanced) rules.


iptables is not compatible with IPv6 because of the vastly different packets IPv6 has compared to IPv4. ip6tables, on the other hand, is compatible and handles the job just as fine as iptables. But having a seperate program for IPv6 means having seperate rules. And having different packets compared to IPv4 means having different rule options (for example ICMP vs ICMPv6).

Basically, you can close your server down with IPtables and then have it completely exposed with IPv6 because your ip6tables are not in order. To prevent this, you should add the rules you add to iptables to ip6tables as well, as far as they are compatible. Luckily, this is the case for most rules (except for source and destination addresses, naturally).

Working with ip6tables

To check your current ip6tables, run:

sudo ip6tables -L

Just as with IPtables, this should output:

mpkossen@host:~$ sudo ip6tables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Now, if we just add a rule to it like we did last times with iptables, it changes in exactly the same way. The difference between iptables and ip6tables is going to show when you add an ACCEPT or DROP rule with an IPv6 address in it.

So, let’s add a rule which does show that difference:

sudo ip6tables -A INPUT -s 2001:db8:1f0a:3ec::2 -j DROP

No worries, you’ve just blocked an IP address reserved for documentation purposes. If you list your ip6tables now, it should show you this:

mpkossen@host:~$ sudo ip6tables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination
DROP       all      2001:db8:1f0a:3ec::2/128  anywhere

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

As you see, not much difference between iptables and ip6tables. Basically just the addresses. The difference will show a bit more if you want to allow or block ICMP traffic, as there are some different protocols for IPv6. The rule of thumb, however, is to just add a ‘6’ after the ‘ip’ part in iptables commands and you should be good.


So, where do we persist these rules? The infrastructure is already in place if you have followed my previous guide.

For CentOS, ip6tables rules are stored in /etc/sysconfig/ip6tables or saved with the following command:

sudo /etc/init.d/ip6tables save

On Ubuntu, with the persistent-iptables package, the ip6tables rules are saved in /etc/iptables/rules.v6. The save command is the same for iptables and ip6tables:

sudo /etc/init.d/iptables-persistent save

So, that’s it! Persisting ip6tables is just as easy as persisting iptables.

More rules

Allowing traffic to port 80 and 443 in a closed firewall (policy DROP) is quite straight-forward. The same applies to port 22 (SSH). Allowing ping, however, is something different. It doesn’t go to a certain port, so allowing it through the firewall requires more advances iptables rules.

To allow IPv4 ping through your firewall, run the following commands (or add them as rules to your persistence file):

sudo iptables -A INPUT -p icmp –icmp-type 8 -m state –state NEW -j ACCEPT
sudo iptables -A OUTPUT -p icmp –icmp-type 0 -m state –state ESTABLISHED,RELATED -j ACCEPT

There’s a couple of new things here. Let’s start at the beginning, with the first command:

sudo iptables -A INPUT -p icmp –icmp-type 8 -m state –state NEW -j ACCEPT

We add a rule to the INPUT chain for the ‘icmp’ protocol (-p). We then pass a protocol-related option (–icmp-type) which indicates which type of ICMP to allow. In this case it’s 8, which is an ‘echo’ packet, which is used for ping. Next is the ‘state’ extension, which is loaded with -m. This extension allows to require the connection to have a certain state (–state). In this case we allow NEW incoming connections.

So, summarized, we narrowed it down to allow packets that meets the following requirements:

  • Protocol: ICMP
  • ICMP type: 8
  • Connection type: NEW

Which boils down to ping being allow to come in.

Next, we add the role to allow the response to go out, otherwise your server would seem down when you ping it from the outside:

sudo iptables -A OUTPUT -p icmp –icmp-type 0 -m state –state ESTABLISHED,RELATED -j ACCEPT

This rule is basically the same as the rule above, except for three things:

  • It is added to the OUTPUT chain
  • It allows ICMP type 0 (echo reply)
  • It only allows ESTABLISHED or RELATED connections

An ‘echo reply’ packet is always sent in response to an ‘echo’ packet, so there should always be an established or related connection.

So, now you know how to allow incoming PING requests but also how to work with different protocols, options and connection states. If you use the iptables man-pages, you can allow virtually any type of packet through without allowing too much packets through. A nice challenge is allowing outgoing PING from a server with a closed firewall. Give it a shot! I’ll give you one hint: it’s easy.

As one commenter correctly noted (thanks, Olipro), the ‘state’ extension contains a subset of connection states from the ‘conntrack’ extension and has been marked as ‘obsolete’ from iptables 1.4.17 and up. While not many distributions have that version of iptables yet, it is worth to note how the ‘conntrack’ extension works compared to the ‘state’ extension. The following is an example of the above commands using the ‘conntrack’ extension:

sudo iptables -A INPUT -p icmp –icmp-type 8 -m conntrack –ctstate NEW -j ACCEPT
sudo iptables -A OUTPUT -p icmp –icmp-type 0 -m conntrack –ctstate ESTABLISHED,RELATED -j ACCEPT

The ‘conntrack’ extension is available for use in most versions of iptables and it is probably wise to start using it straight away. However, a lot of the available documentation online (including some of Netfilter’s official HOWTOs) still use the ‘state’ extension. Now you know both, but should keep in mind to use ‘conntrack’ rather than ‘state’ for compatibility with future iptables versions!

Final notes

There’s (still) a lot more to learn about iptables, so I suggest you read the man-pages for more information, as they are a good source of information. Also, in this case, Google is your friend. iptables is established software so there’s plenty to be found about it.

This concludes my series of iptables-related tutorials, which are part of a bigger series of security-related tutorials. I’ll be picking up on that later.

Up next week: how to create your own mail server with Virtualmin!



  1. Expecting the mail server tutorial!!!

    August 17, 2013 @ 12:13 pm | Reply
    • Maarten Kossen:

      It’ll be a GUI tutorial with lots of images, but it will hopefully help a lot of people set up their own mail server. It may seem hard to many, but with Virtualmin it’s quite easy and the setup is proper. It’s non-invasive, like something like cPanel.

      I’ve got a full CLI mail server on my TODO list but it is going to be several weeks of articles due to the amount of work involved. It’ll probably be in November/December.

      August 19, 2013 @ 4:50 am | Reply
  2. Nice tutorial and bookmarked it, thanks!

    August 17, 2013 @ 1:30 pm | Reply
  3. This is the article good article, learn about. Thank you.

    August 17, 2013 @ 5:29 pm | Reply
  4. W1V_Lee:

    Nice job Maarten, easy to follow and very informative.

    August 17, 2013 @ 10:55 pm | Reply
    • Maarten Kossen:

      Thanks, Lee!

      August 19, 2013 @ 4:50 am | Reply
  5. Tianyi:


    I need a rule that specify an ipv6 IP for one user. How Can I do that. I used VPS as proxy for my colleagues because it dificult to use google service in China mainland.

    However it always come out the info and verify codes requested. The reason seems to be too much device use one IPV6 IP on the same time.

    August 18, 2013 @ 3:35 am | Reply
  6. The Toastcutter:

    Really enjoying these articles Maarten. Please keep them coming!

    August 19, 2013 @ 12:13 am | Reply
  7. Olipro:

    This is a bad tutorial, firstly, an ICMP echo-request can never have a state of RELATED or ESTABLISHED because, by definition, it is the initiation packet, it will either be NEW, INVALID (if malformed) or UNTRACKED (if you notrack’ed it in the raw table).

    Secondly, don’t use -m state, it’s old, deprecated and pointless. Use -m conntrack.

    Conntrack does all the hard-work so you don’t have to – your first rule in filter chains should almost *always* solely match on –ctstate ESTABLISHED,RELATED and ACCEPT it.

    For a *good* guide on what makes for an efficient setup, read “towards the perfect ruleset” http://inai.de/documents/Perfect_Ruleset.pdf [PDF]

    August 19, 2013 @ 3:49 pm | Reply
    • Dave:

      Well Said.

      August 19, 2013 @ 4:18 pm | Reply
    • Maarten Kossen:

      Thanks for your feedback and taking the time to read my article!

      In my enthusiasm of wanting to combine two things (allowing ICMP traffic and showing different connection states), I realize I may have unjustly combined the two. I still need to edit the tutorial accordingly, but did not get around to it due to time constraints. I will do so tomorrow.

      The state extension is _not_ deprecated. The documentation of iptables states it is obsolete compared to conntrack because it only allows a subset of conntrack’s connection states. For the purposes I used it for, it is sufficient. Netfilter itself frequently relies on this module for state tracking, as it’s the clearest approach to do this. Even more so, it’s most commonly and widely used, which is why I am using it as an example. People are going to see this quite often when looking up more information in iptables.

      August 20, 2013 @ 4:33 am | Reply
      • Olipro:

        Deprecated, Obsolete… Tomayto, Tomahto.

        It remains in existence purely to avoid breakage, it is simply a subset of -m conntrack – unless you’re running a kernel that’s so old it doesn’t have it, it’s good practice to make use of -m conntrack rather than -m state. If you look at the manpage for iptables (or iptables-extensions in more recent iterations) you’ll see that the functionality offered by -m conntrack is far superior.

        To put it simply, whilst you *can* use it, and there is nothing technically wrong with doing so, it’s better not to introduce people to it, if not simply for the fact that they may never read about -m conntrack and discover its wonderful functionality then at least because doing so is best-practice.

        August 20, 2013 @ 7:18 am | Reply
        • Maarten Kossen:

          Guide amended, thanks for your feedback!

          August 21, 2013 @ 5:53 am | Reply
  8. Kishor Pawar:

    Hey Maarten, this is really a great article. I am learning iptables by finding information online, in order to write a program that will check if the system is secured. I have one rule that says “The operating system must prevent public IPv6 access into an organizations internal networks, except as appropriately mediated by managed interfaces employing boundary protection devices.”. But I am not sure if I understand it correctly. Request you to please simplify this statement for me. Lots of Thanks in advanced.

    July 12, 2016 @ 12:46 pm | Reply
  9. Is iptable can deal with ipv6 IP address? Should I install both iptable and ip6table to handle all of that? Anyway, thank you very much for your article, it helps a lot.

    October 26, 2019 @ 10:54 am | Reply

Leave a Reply

Some notes on commenting on LowEndBox:

  • Do not use LowEndBox for support issues. Go to your hosting provider and issue a ticket there. Coming here saying "my VPS is down, what do I do?!" will only have your comments removed.
  • Akismet is used for spam detection. Some comments may be held temporarily for manual approval.
  • Use <pre>...</pre> to quote the output from your terminal/console, or consider using a pastebin service.

Your email address will not be published. Required fields are marked *