#!/usr/sbin/nft -f
flush ruleset

define wan = eth0
define vpn = wg0
define vpn_net = 10.0.0.0/24
define lan_net = 192.168.2.0/24
define self = 192.168.2.2

# delegated prefix is 2a02:a45e:ce93::/48
define lan_net6 = 2a02:a45e:ce93:0::/64

define icmpv4_basic = {
  echo-reply, # type 0 / ping
  echo-request, # type 8 / ping
  destination-unreachable, # type 3
  time-exceeded, # type 11
  parameter-problem, # type 12
}

define icmpv6_basic = { 
  # Basic
  echo-reply, # type 129 / ping
  echo-request, # type 128 / ping
  destination-unreachable, # type 1
  packet-too-big, # type 2
  time-exceeded, # type 3
  parameter-problem # type 4
}

define icmpv6_slaac = {
  # SLAAC
  nd-router-solicit, # type 133
  nd-router-advert, # type 134
  nd-neighbor-solicit, # type 135
  nd-neighbor-advert # type 136
}

# Clients that are allowed to access the LAN network
define lan_clients = { 10.0.0.2 }

table inet firewall {
  chain postrouting {
    type nat hook postrouting priority 100;

    # Masquerade WireGuard VPN WAN traffic to LAN subnet
    oifname $wan ip saddr $vpn_net masquerade
  }

  chain incoming {
    # This line set what traffic the chain will handle, the priority and default policy.
    # The priority comes in when you in another table have a chain set to "hook input" and want to specify in what order they should run.
    type filter hook input priority 0; policy drop;

    ct state invalid drop                                 # early drop of invalid packets
    ct state { established, related } accept              # allow established/related connections

    iif lo accept                                         # allow traffic from loopback interface

    # Limit and accept ICMP packets
    ip protocol icmp icmp type $icmpv4_basic limit rate 1/second burst 5 packets accept
    ip6 nexthdr icmpv6 icmpv6 type $icmpv6_basic limit rate 1/second burst 5 packets accept
    icmpv6 type $icmpv6_slaac limit rate 1/second burst 5 packets ip6 hoplimit 255 accept

    # Rules for all interfaces
    tcp dport { 80, 443 } accept                          # Allow http and https for all interfaces
    udp dport 443 accept                                  # Allow quic (http/3) for all interfaces

    ip saddr $lan_net tcp dport 22 accept                 # Allow SSH from LAN network

    # AdGuard admin access (8888) accept for LAN and VPN
    ip saddr { $lan_net, $vpn_net } tcp dport 8888 accept
    ip6 saddr $lan_net6 tcp dport 8888 accept

    # Adguard DHCP, DoT, DoQ ports
    udp dport { 67, 68, 784 } accept
    tcp dport { 853 } accept

    # Allow DNS from LAN and VPN
    ip saddr { $lan_net, $vpn_net } udp dport 53 accept
    ip6 saddr $lan_net6 udp dport 53 accept
    ip saddr { $lan_net, $vpn_net } tcp dport 53 accept
    ip6 saddr $lan_net6 tcp dport 53 accept

    # Allow Minecraft server access from LAN and VPN
    ip saddr { $lan_net, $vpn_net } tcp dport 25565 accept
    ip saddr { $lan_net, $vpn_net } udp dport 25565 accept
    ip saddr { $lan_net, $vpn_net } tcp dport 19132 accept
    ip saddr { $lan_net, $vpn_net } udp dport 19132 accept

    # Rules for WAN interface only
    iifname $wan udp dport 51820 accept                   # Allow Wireguard incoming from WAN

    # iifname $wan tcp dport 22 limit rate 10/minute accept # Rate limit SSH (port 22) to 10 connections per minute from WAN

    # Rules for VPN interface only
    iifname $vpn tcp dport 22 accept                      # Allow SSH from VPN
  }

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

    ct state invalid drop                                 # early drop of invalid packets
    ct state {established, related} accept                # allow established/related connections

    iifname $vpn ip saddr $lan_clients ip daddr $lan_net accept # Allow specific clients to access the LAN network
    iifname $vpn ip daddr $lan_net drop                   # Block all other VPN clients from accessing the LAN network 
  
    iifname $vpn oifname $wan accept                      # Allow VPN traffic to access WAN
    
    iifname "podman*" accept                              # allow traffic from podman interfaces (podman0, podman1, ...)
    oifname "podman*" accept                              # allow traffic to podman interfaces (podman0, podman1, ...)
  }

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