It's time for the 36c3 and to verify that some things are in place where they should be.

As some of you might know, I am using IPv6 extensively to provide services anywhere on anything, so you will see quite some IPv6 related rules in my configuration.

This post should serve two purpose:

  • Inspire others to verify their network settings prior to the congress
  • Get feedback from anyone spotting a huge mistake in my config :-)

The firewall rules

I am using nftables on my notebook and the full ruleset is shown below.

table ip6 filter {
        chain input {
                type filter hook input priority 0;
                policy drop;

                iif lo accept
                ct state established,related accept

                icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } accept

                tcp dport { 22, 80, 443 } accept

        }

        chain forward {
                type filter hook forward priority 0;
                policy drop;

                ct state established,related accept

                ip6 daddr 2a0a:e5c1:137:b00::/64  jump container
                ip6 daddr 2a0a:e5c1:137:cafe::/64 jump container
        }

        chain container {
        icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } accept

                tcp dport { 22, 80, 443 } accept
                drop

        }
        chain output {
                type filter hook output priority 0;
                policy accept;
        }
}

table ip filter {
        chain input {
                type filter hook input priority 0;
                policy drop;

                iif lo accept
                ct state established,related accept
                tcp dport { 22 } accept
                tcp dport { 51820 } accept
        }
        chain forward {
                type filter hook forward priority 0;
                policy drop;
        }
        chain output {
                type filter hook output priority 0;
                policy accept;
        }
}

The firewall explained: IPv6

Let's have a look at the IPv6 part first. In nftables we can freely define chains, what is important is is the hook that we use in it.

        chain input {
                type filter hook input priority 0;
                ...

The policy has the same meaning as in iptables and basically specifies what to do with unmatched packets.

IPv6 uses quite some ICMP6 messages to control and also to establish communication in the first place, so the list for accepting is quite long.

                icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } accept

As we are dealing with traffic that comes to my notebook ("hook input"), I want to allow any incoming packets that belong to one of the connections that I initiated:

                ct state established,related accept

And finally, I allow port 22, to be able to ssh into my notebook, port 80 to get letsencrypt certificates and port 443 for serving https. When I am online, my notebook is reachable at nico.plays.ipv6.games, so I need the web ports to be open.

As I run quite some test on my notebook with docker and lxc, I created a /64 IPv6 network for each of them. When matching on those specific networks, I jump into a chain that allows specific configurations for containers:

                ip6 daddr 2a0a:e5c1:137:b00::/64  jump container
                ip6 daddr 2a0a:e5c1:137:cafe::/64 jump container

The chain container consists at the moment of the same rule set as the input chain, however this changes occasionally when testing applications in containers.

And for the output chain, I trust that the traffic my notebook emits is what I wanted it to emit (but also allows malware to send out data, if I had some installed).

The firewall explained: IPv4

In the IPv4 irea ("table ip filter*) things are quite similar with some small differences:

  • I don't provides services on IPv4 besides ssh and wireguard (port 22 and 51820)
  • There is nothing to be forwarded for IPv4, all containers use IPv6
  • Same logic for the output as in IPv6

Safe or not safe?

Whether this ruleset is safe or not depends a bit on your degree of paranoia. I allow access to port 443 on which an nginx runs which then again proxies to a self written flask application, which might-or-might-not be safe.

Some people argue to limit outgoing traffic and while this is certainly possible (whitelist ports?), often this does is rendered useless, as any command and control server can be reached on port 80 and you probably don't want to block outgoing port 80 traffic.

If you have any comments about it, I'm interested in hearing your feedback on the ungleich chat, twitter or IRC (telmich).

Update 2019-12-24

I forgot to allow loopback traffic in the original version, which breaks some local networking.