222 lines
7.4 KiB
Nix
222 lines
7.4 KiB
Nix
{ config, lib, pkgs, ... }:
|
|
let
|
|
vars = import ./vars.nix config;
|
|
links = vars.links;
|
|
ifs = vars.ifs;
|
|
pdFromWan = vars.pdFromWan;
|
|
nftIdentifiers = ''
|
|
define ZONE_WAN_IFS = { ${ifs.wan.name} }
|
|
define ZONE_LAN_IFS = {
|
|
${ifs.lan.name},
|
|
${ifs.lan10.name},
|
|
${ifs.lan20.name},
|
|
${ifs.lan30.name},
|
|
${ifs.lan40.name},
|
|
${ifs.lan50.name},
|
|
${ifs.wg0.name},
|
|
}
|
|
define OPNSENSE_NET6 = ${vars.extra.opnsense.net6}
|
|
define ZONE_LAN_EXTRA_NET6 = {
|
|
# TODO: reevaluate this statement
|
|
${ifs.lan20.net6}, # needed since packets can come in from wan on these addrs
|
|
$OPNSENSE_NET6,
|
|
}
|
|
define RFC1918 = { 10.0.0.0/8, 172.12.0.0/12, 192.168.0.0/16 }
|
|
define CLOUDFLARE_NET6 = {
|
|
# https://www.cloudflare.com/ips-v6
|
|
# TODO: figure out a better way to get addrs dynamically from url
|
|
# perhaps building a nixos module/package that fetches the ips?
|
|
2400:cb00::/32,
|
|
2606:4700::/32,
|
|
2803:f800::/32,
|
|
2405:b500::/32,
|
|
2405:8100::/32,
|
|
2a06:98c0::/29,
|
|
2c0f:f248::/32,
|
|
}
|
|
'';
|
|
in
|
|
{
|
|
networking.firewall.enable = false;
|
|
networking.nftables.enable = true;
|
|
# networking.nftables.ruleset = nftIdentifiers; #doesn't work because it's appended to the end
|
|
networking.nftables.tables.nat4 = {
|
|
family = "ip";
|
|
content = ''
|
|
${nftIdentifiers}
|
|
map port_forward {
|
|
type inet_proto . inet_service : ipv4_addr . inet_service
|
|
elements = {
|
|
tcp . 8006 : ${ifs.lan50.p4}.10 . 8006,
|
|
# opnsense vpn endpoints
|
|
# the plan is to maybe eventually move these to nixos
|
|
udp . 18596 : ${vars.extra.opnsense.addr4} . 18596,
|
|
udp . 48512 : ${vars.extra.opnsense.addr4} . 48512,
|
|
udp . 40993 : ${vars.extra.opnsense.addr4} . 40993,
|
|
udp . 45608 : ${vars.extra.opnsense.addr4} . 45608,
|
|
udp . 35848 : ${vars.extra.opnsense.addr4} . 35848,
|
|
udp . 48425 : ${vars.extra.opnsense.addr4} . 48425,
|
|
}
|
|
}
|
|
|
|
chain prerouting {
|
|
# Initial step, accept by default
|
|
type nat hook prerouting priority dstnat; policy accept;
|
|
|
|
# Port forwarding
|
|
fib daddr type local dnat ip to meta l4proto . th dport map @port_forward
|
|
}
|
|
|
|
chain postrouting {
|
|
# Last step, accept by default
|
|
type nat hook postrouting priority srcnat; policy accept;
|
|
|
|
# Masquerade LAN addrs
|
|
oifname $ZONE_WAN_IFS ip saddr $RFC1918 masquerade
|
|
}
|
|
'';
|
|
};
|
|
|
|
# Optional IPv6 masquerading (big L if enabled, don't forget to allow forwarding)
|
|
networking.nftables.tables.nat6 = {
|
|
family = "ip6";
|
|
enable = false;
|
|
content = ''
|
|
${nftIdentifiers}
|
|
chain postrouting {
|
|
type nat hook postrouting priority srcnat; policy accept;
|
|
oifname $ZONE_WAN_IFS ip6 saddr fd00::/8 masquerade
|
|
}
|
|
'';
|
|
};
|
|
|
|
networking.nftables.tables.firewall = {
|
|
family = "inet";
|
|
content = ''
|
|
${nftIdentifiers}
|
|
define ALLOWED_TCP_PORTS = { ssh }
|
|
define ALLOWED_UDP_PORTS = { ${toString vars.ifs.wg0.listenPort} }
|
|
define ALLOWED_TCP_LAN_PORTS = { ssh, https }
|
|
define ALLOWED_UDP_LAN_PORTS = { bootps, dhcpv6-server, domain, https }
|
|
set port_forward_v6 {
|
|
type inet_proto . ipv6_addr . inet_service
|
|
elements = {
|
|
# syncthing on alpina
|
|
tcp . ${ifs.lan.p6}::11:1 . 22000 ,
|
|
udp . ${ifs.lan.p6}::11:1 . 22000 ,
|
|
}
|
|
}
|
|
set cloudflare_forward_v6 {
|
|
type ipv6_addr
|
|
elements = {
|
|
${ifs.lan.p6}::11:1,
|
|
}
|
|
}
|
|
|
|
chain input {
|
|
type filter hook input priority filter; policy drop;
|
|
|
|
# Drop router adverts from self
|
|
# peculiarity due to wan and lan20 being bridged
|
|
# TODO: figure out a less jank way to do this
|
|
iifname $ZONE_WAN_IFS ip6 saddr ${links.lanLL} icmpv6 type nd-router-advert log prefix "self radvt: " drop
|
|
# iifname $ZONE_WAN_IFS ip6 saddr ${links.lanLL} ip6 nexthdr icmpv6 log prefix "self icmpv6: " drop
|
|
# iifname $ZONE_WAN_IFS ip6 saddr ${links.lanLL} log prefix "self llv6: " drop
|
|
# iifname $ZONE_WAN_IFS ip6 saddr ${links.lanLL} log drop
|
|
# iifname $ZONE_LAN_IFS ip6 saddr ${links.wanLL} log drop
|
|
|
|
# Allow established and related connections
|
|
# All icmp stuff should (theoretically) be handled by ct related
|
|
# https://serverfault.com/a/632363
|
|
ct state established,related accept
|
|
|
|
# However, that doesn't happen for router advertisements from what I can tell
|
|
# TODO: more testing
|
|
# Allow ICMPv6 on local addrs
|
|
ip6 nexthdr icmpv6 ip6 saddr { fe80::/10, ${pdFromWan}0::/60 } accept
|
|
ip6 nexthdr icmpv6 ip6 daddr fe80::/10 accept # TODO: not sure if necessary
|
|
|
|
# Allow all traffic from loopback interface
|
|
iif lo accept
|
|
|
|
# Allow DHCPv6 traffic
|
|
# I thought dhcpv6-client traffic would be accepted by established/related,
|
|
# but apparently not.
|
|
ip6 daddr { fe80::/10, ff02::/16 } th dport { dhcpv6-client, dhcpv6-server } accept
|
|
|
|
# Global input rules
|
|
tcp dport $ALLOWED_TCP_PORTS accept
|
|
udp dport $ALLOWED_UDP_PORTS accept
|
|
|
|
# WAN zone input rules
|
|
iifname $ZONE_WAN_IFS jump zone_wan_input
|
|
# LAN zone input rules
|
|
# iifname $ZONE_LAN_IFS accept
|
|
iifname $ZONE_LAN_IFS jump zone_lan_input
|
|
ip6 saddr $ZONE_LAN_EXTRA_NET6 jump zone_lan_input
|
|
|
|
# log
|
|
}
|
|
|
|
chain forward {
|
|
type filter hook forward priority filter; policy drop;
|
|
|
|
# Allow established and related connections
|
|
ct state established,related accept
|
|
|
|
# WAN zone forward rules
|
|
iifname $ZONE_WAN_IFS jump zone_wan_forward
|
|
# LAN zone forward rules
|
|
iifname $ZONE_LAN_IFS jump zone_lan_forward
|
|
ip6 saddr $ZONE_LAN_EXTRA_NET6 jump zone_lan_forward
|
|
}
|
|
|
|
chain zone_wan_input {
|
|
# Allow specific stuff from WAN
|
|
}
|
|
|
|
chain zone_wan_forward {
|
|
# Port forwarding
|
|
ct status dnat accept
|
|
|
|
# Allowed IPv6 ports
|
|
meta l4proto . ip6 daddr . th dport @port_forward_v6 accept
|
|
|
|
# Allowed IPv6 from cloudflare
|
|
ip6 saddr $CLOUDFLARE_NET6 ip6 daddr @cloudflare_forward_v6 th dport https accept
|
|
}
|
|
|
|
chain zone_lan_input {
|
|
# Allow all ICMPv6 from LAN
|
|
ip6 nexthdr icmpv6 accept
|
|
|
|
# Allow all ICMP from LAN
|
|
ip protocol icmp accept
|
|
|
|
# Allow specific services from LAN
|
|
tcp dport $ALLOWED_TCP_LAN_PORTS accept
|
|
udp dport $ALLOWED_UDP_LAN_PORTS accept
|
|
}
|
|
|
|
chain zone_lan_forward {
|
|
# Allow port forwarded targets
|
|
# ct status dnat accept
|
|
|
|
# Allow all traffic from LAN to WAN, except ULAs
|
|
oifname $ZONE_WAN_IFS ip6 saddr fd00::/8 drop # Not sure if needed
|
|
oifname $ZONE_WAN_IFS accept;
|
|
|
|
# Allow traffic between LANs
|
|
oifname $ZONE_LAN_IFS accept
|
|
}
|
|
|
|
chain output {
|
|
# Accept anything out of self by default
|
|
type filter hook output priority filter; policy accept;
|
|
# NAT reflection
|
|
# oif lo ip daddr != 127.0.0.0/8 dnat ip to meta l4proto . th dport map @port_forward_v4
|
|
}
|
|
'';
|
|
};
|
|
}
|