Before we relied on the IP being first in the interfaces file, which is less than optimal. Now we use nftables to ensure the correct source IP is set only for the (fwmarked) wireguard traffic. Also remove iface hints from interfaces configuration as they are not needed with ifupdown-ng.
187 lines
5.8 KiB
Django/Jinja
187 lines
5.8 KiB
Django/Jinja
#!/usr/sbin/nft -f
|
|
{% set ifaces_fabric = interfaces | selectattr('name', 'match', '^lan') | map(attribute='name') %}
|
|
|
|
flush ruleset
|
|
|
|
table inet filter {
|
|
include "/etc/nftables.d/interfaces.nft"
|
|
include "/etc/nftables.d/networks.nft"
|
|
include "/etc/nftables.d/sets.nft*"
|
|
|
|
set link {
|
|
type iface_index
|
|
elements = { {{ ifaces_fabric | product(['2', '4']) | map('join', '.') | join(', ') }} }
|
|
}
|
|
|
|
# convenience port set definitions
|
|
set ad-ports { # https://learn.microsoft.com/en-us/troubleshoot/windows-server/active-directory/config-firewall-for-ad-domains-and-trusts
|
|
type inet_proto . inet_service
|
|
flags interval
|
|
elements = {
|
|
tcp . 53,
|
|
tcp . 88,
|
|
tcp . 135,
|
|
tcp . 139,
|
|
tcp . 389,
|
|
tcp . 445,
|
|
tcp . 464,
|
|
tcp . 636,
|
|
tcp . 3268-3269,
|
|
#tcp . 3389, # RDP
|
|
tcp . 5000-5100,
|
|
tcp . 5985,
|
|
tcp . 5986,
|
|
tcp . 9389,
|
|
tcp . 22222-22224,
|
|
tcp . 49152-65535,
|
|
udp . 53,
|
|
udp . 88,
|
|
udp . 135,
|
|
udp . 137, # netbios, maybe can do without
|
|
udp . 138, # netbios, maybe can do without
|
|
udp . 389,
|
|
udp . 464,
|
|
udp . 3269
|
|
}
|
|
}
|
|
|
|
set ldap-ports {
|
|
type inet_proto . inet_service
|
|
flags interval
|
|
elements = {
|
|
tcp . 88,
|
|
tcp . 389,
|
|
tcp . 636,
|
|
tcp . 3268,
|
|
tcp . 3269,
|
|
udp . 88,
|
|
udp . 389
|
|
}
|
|
}
|
|
|
|
chain input {
|
|
type filter hook input priority 0; policy drop
|
|
|
|
ct state vmap { established : accept, related : accept, invalid : drop } \
|
|
comment "Accept established streams and drop invalid connections"
|
|
|
|
iif lo accept \
|
|
comment "Accept any localhost traffic"
|
|
|
|
iif mgmt tcp dport ssh accept \
|
|
comment "Accept SSH from management VRF"
|
|
|
|
# allow SSH connections from firewall master’s IPs
|
|
{% for iface in hostvars[master].interfaces %}
|
|
{% for address in iface.ip_addresses %}
|
|
tcp dport ssh {{ 'ip' if address.family.value == 4 else 'ip6' }} saddr {{ address.address | ipaddr('address') }} accept
|
|
{% for nat_address in address.nat_outside %}
|
|
tcp dport ssh ip saddr {{ nat_address.address | ipaddr('address') }} accept
|
|
{% endfor %}
|
|
{% endfor %}
|
|
{% endfor %}
|
|
|
|
iif @link tcp dport bgp ip6 saddr fe80::/10 accept \
|
|
comment "Accept link-local BGP on fabric links"
|
|
|
|
iif @link udp dport 3784 ip6 saddr fe80::/10 accept \
|
|
comment "Accept link-local BFD on fabric links"
|
|
|
|
udp dport 51820 accept \
|
|
comment "Accept WireGuard from anywhere"
|
|
|
|
iif {{ iface_sync }} ip6 saddr fe80::/10 udp dport 3780 accept \
|
|
comment "Accept connection tracking sync data"
|
|
|
|
tcp dport auth reject with icmpx type port-unreachable \
|
|
comment "Reject AUTH to make it fail fast"
|
|
|
|
# ICMPv4
|
|
ip protocol icmp icmp type {
|
|
echo-request, echo-reply, destination-unreachable,
|
|
parameter-problem, time-exceeded,
|
|
} accept \
|
|
comment "Accept ICMP"
|
|
|
|
# ICMPv6
|
|
ip6 nexthdr icmpv6 icmpv6 type {
|
|
echo-request, echo-reply, destination-unreachable,
|
|
packet-too-big, parameter-problem, time-exceeded,
|
|
} accept \
|
|
comment "Accept basic IPv6 functionality"
|
|
|
|
ip6 nexthdr icmpv6 icmpv6 type {
|
|
nd-neighbor-solicit, nd-neighbor-advert,
|
|
nd-router-solicit, nd-router-advert,
|
|
} ip6 hoplimit 255 accept \
|
|
comment "Allow IPv6 neighbor discovery"
|
|
}
|
|
|
|
chain forward {
|
|
type filter hook forward priority filter; policy drop
|
|
|
|
ct state { established, related } accept \
|
|
comment "Forward all established and related traffic"
|
|
|
|
ct status dnat accept \
|
|
comment "Forward DNAT traffic for servers and suchlike"
|
|
|
|
ip protocol icmp icmp type {
|
|
echo-request, echo-reply, destination-unreachable,
|
|
parameter-problem, time-exceeded,
|
|
} accept \
|
|
comment "Accept ICMPv4"
|
|
|
|
ip6 nexthdr icmpv6 icmpv6 type {
|
|
echo-request, echo-reply, destination-unreachable,
|
|
packet-too-big, parameter-problem, time-exceeded,
|
|
} accept \
|
|
comment "Accept ICMPv6"
|
|
|
|
include "/etc/nftables.d/forward.nft*"
|
|
}
|
|
|
|
chain output {
|
|
type filter hook output priority 0; policy accept
|
|
}
|
|
}
|
|
|
|
table inet wireguard {
|
|
chain input {
|
|
type filter hook prerouting priority raw; policy accept
|
|
udp dport 51820 notrack \
|
|
comment "Disable connection tracking for wireguard"
|
|
}
|
|
chain output {
|
|
type route hook output priority raw; policy accept
|
|
meta mark 51820 meta nfproto ipv4 ip saddr set {{ wg_ip | ipaddr('address') }} notrack \
|
|
comment "Disable connection tracking and set anycast source IP for wireguard"
|
|
}
|
|
}
|
|
|
|
table ip nat {
|
|
include "/etc/nftables.d/interfaces.nft"
|
|
include "/etc/nftables.d/networks.nft"
|
|
include "/etc/nftables.d/sets.nft*"
|
|
include "/etc/nftables.d/netmap.nft*"
|
|
|
|
# Ensure these maps exist even if empty.
|
|
map netmap-in { type ipv4_addr : interval ipv4_addr; flags interval; }
|
|
map netmap-out { type ipv4_addr : interval ipv4_addr; flags interval; }
|
|
|
|
chain postrouting {
|
|
type nat hook postrouting priority srcnat
|
|
|
|
iif @inside oif @outside snat ip prefix to ip saddr map @netmap-out \
|
|
comment "Static source NAT for 1:1 mapped addresses"
|
|
|
|
include "/etc/nftables.d/nat.nft*"
|
|
}
|
|
|
|
chain prerouting {
|
|
type nat hook prerouting priority dstnat
|
|
|
|
dnat ip prefix to ip daddr map @netmap-in \
|
|
comment "Static destination NAT for 1:1 mapped addresses"
|
|
}
|
|
}
|