www.nico.schottelius.org/blog/my-notebook-firewall-36c3.mdwn

171 lines
5.4 KiB
Markdown

[[!meta title="My notebook firewall for the 36c3"]]
It's time for the
[36c3](https://events.ccc.de/congress/2019/wiki/index.php/Main_Page)
and to verify that some things are in place where they should be.
As some of you might know, I am using
[IPv6 extensively](https://ipv6onlyhosting.com) 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](https://ungleich.ch/en-us/cms/blog/2018/09/11/introduction-to-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](https://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](http://chat.with.ungleich.ch),
[twitter](https://twitter.com/NicoSchottelius) or IRC (telmich).
## Update 2019-12-24
I forgot to allow loopback traffic in the original version, which
breaks some local networking.
[[!tag ccc firewall nftables ipv6]]