From b29daa0ea10ea3d22ab1f5eac79a17040017a30c Mon Sep 17 00:00:00 2001 From: Brendan Golden Date: Sat, 28 Jan 2023 15:31:46 +0000 Subject: [PATCH] feat: I think this is a better firewall setup, still need to properly test it --- applications/firewall.nix | 94 +++++++++++++++++++++++++++------------ 1 file changed, 66 insertions(+), 28 deletions(-) diff --git a/applications/firewall.nix b/applications/firewall.nix index cfe50d2..1faef0e 100644 --- a/applications/firewall.nix +++ b/applications/firewall.nix @@ -58,8 +58,23 @@ # beware of EOL conversion. networking.nftables.ruleset = '' - # Check out https://wiki.nftables.org/ for better documentation. - # Table for both IPv4 and IPv6. + # using https://oxcrag.net/2021/12/25/build-your-own-router-with-nftables-part-1/ as a guide + + # Clear out any existing rules + flush ruleset + + # Our future selves will thank us for noting what cable goes where and labeling the relevant network interfaces if it isn't already done out-of-the-box. + # red cabled + define WANLINK = eno1 + # yellow cable + define LANLINK = eno2 + + + # We never expect to see the following address ranges on the Internet + define BOGONS4 = { 0.0.0.0/8, 10.0.0.0/8, 10.64.0.0/10, 127.0.0.0/8, 127.0.53.53, 169.254.0.0/16, 172.16.0.0/12, 192.0.0.0/24, 192.0.2.0/24, 192.168.0.0/16, 198.18.0.0/15, 198.51.100.0/24, 203.0.113.0/24, 224.0.0.0/4, 240.0.0.0/4, 255.255.255.255/32 } + + + # Network address translation: What allows us to glue together a private network with the Internet even though we only have one routable address, as per IPv4 limitations table ip nat { chain prerouting { type nat hook prerouting priority dstnat; policy accept; @@ -84,46 +99,69 @@ } } - table ip filter { - chain input { - type filter hook input priority filter; policy accept; + # The actual firewall starts here + table inet filter { + # Additional rules for traffic from the Internet + chain inbound_world { + # this is actually a good idea + # Drop obviously spoofed inbound traffic + ip saddr { $BOGONS4 } drop + } + + # Additional rules for traffic from our private network + chain inbound_private { + # We want to allow remote access over ssh, incoming DNS traffic, and incoming DHCP traffic # for the host machiene + # hardcoded in so that we can always have access + tcp dport 22 counter packets 0 bytes 0 accept + # TCP ${lib.strings.concatMapStrings (x: x + "\n") (map (port: "tcp dport ${toString port} counter packets 0 bytes 0 accept") config.skynet_firewall.own.ports.tcp)} # UDP ${lib.strings.concatMapStrings (x: x + "\n") (map (port: "udp dport ${toString port} counter packets 0 bytes 0 accept") config.skynet_firewall.own.ports.udp)} + } - chain forward { - type filter hook forward priority filter; policy drop; - counter packets 0 bytes 0 jump rejects + # Our funnel for inbound traffic from any network + chain inbound { + # Default Deny + type filter hook input priority 0; policy drop; - # accept these ip/ports - # ip saddr 193.1.99.123 tcp dport 443 counter packets 0 bytes 0 accept + # Allow established and related connections: Allows Internet servers to respond to requests from our Internal network + ct state vmap { established : accept, related : accept, invalid : drop} counter + + # ICMP is - mostly - our friend. Limit incoming pings somewhat but allow necessary information. + ip protocol icmp icmp type { + destination-unreachable, echo-reply, echo-request, source-quench, time-exceeded + } limit rate 5/second accept + + # guy must have had a lot of trouble with spoofed ips + # Drop obviously spoofed loopback traffic + iifname "lo" ip daddr != 127.0.0.0/8 drop + + # Separate rules for traffic from Internet and from the internal network + iifname vmap { lo: accept, $WANLINK : jump inbound_world, $LANLINK : jump inbound_private } + } + + # Rules for sending traffic from one network interface to another + chain forward { + # Default deny, again + type filter hook forward priority 0; policy drop; + + # Accept established and related traffic + ct state vmap { established : accept, related : accept, invalid : drop } + + # Let traffic from this router and from the Internal network get out onto the Internet + iifname { lo, $LANLINK } accept + + # Only allow specific inbound traffic from the Internet (only relevant if we present services to the Internet). + # tcp dport { $PORTFORWARDS } counter # can basically make each machiene responsibile for their own forwarding (in config at least) ${lib.strings.concatMapStrings (x: x + "\n") config.skynet_firewall.forward} - counter packets 0 bytes 0 reject with icmp type admin-prohibited - } - - chain output { - type filter hook output priority filter; policy accept; - - # no outgoing limits (for now) - } - - chain fail2ban-ssh { - # ban these - # ip saddr 104.236.151.120 counter packets 0 bytes 0 drop - counter packets 0 bytes 0 return - } - - chain rejects { - # Reject all these - # ip saddr 220.119.33.251 counter packets 0 bytes 0 reject with icmp type admin-prohibited } } '';