#!/usr/bin/env nft -f # The home-server project produces a multi-purpose setup using Ansible. # Copyright © 2018 Y. Gablin, under the GPL-3.0-or-later license. # Full licensing information in the LICENSE file, or gnu.org/licences/gpl-3.0.txt if the file is missing. flush ruleset {% for V in ['4', '6'] %} {% set v = V | replace('4', '') %} {% macro trust(list) %} {% for net in list.split(' ') %} {% if not net is match('127(?:\.\d{1,3}){3}(?:/\d+)?|::1|^$') %} {% if (net is match('\d{1,3}(?:\.\d{1,3}){3}(?:/\d+)?') and V == '4') or (net is search(':') and V == '6') %} {{caller(net)}} {% endif %} {% endif %} {% endfor %} {% endmacro %} table ip{{v}} Inet{{V}} { set https_ban { type ipv{{V}}_addr flags timeout } set mail_ban { type ipv{{V}}_addr flags timeout } set sshd_ban { type ipv{{V}}_addr flags timeout } {% set seq = fw_portknock_seq.split(' ') %} {% for port in seq %} set Knocked_{{loop.index}} { type ipv{{V}}_addr flags timeout {% if loop.last %} timeout {{fw_knock_timeout_min}}m {% else %} timeout 10s {% endif %} gc-interval 4s } {% endfor %} chain doBan { type filter hook prerouting priority -200; policy accept; ip{{v}} saddr @https_ban tcp dport {80, 443} drop ip{{v}} saddr @mail_ban tcp dport {25, 465, 587, 993} drop ip{{v}} saddr @sshd_ban tcp dport {22, 2222, 22000} drop } chain NAT_in { type nat hook prerouting priority -100 {% call(net) trust(SafeZone_IP) %} # Git SSH tcp dport 2222 log prefix "DNAT/git: " dnat to {{net}} {% endcall %} # Trusted hosts tcp dport 443 ip{{v}} saddr @Knocked_{{seq | length}} log prefix "DNAT/HTTPS after Port-Knock: " redirect to 444 {% call(net) trust(net_trusted_ranges) %} tcp dport 443 ip{{v}} saddr {{net}} redirect to 444 {% endcall %} tcp dport 22 ip{{v}} saddr @Knocked_{{seq | length}} log prefix "DNAT/SSH after Port-Knock: " redirect to 23 {% call(net) trust(net_trusted_ranges) %} tcp dport 22 ip{{v}} saddr {{net}} redirect to 23 {% endcall %} } chain NAT_out { type nat hook postrouting priority 100 ct status dnat masquerade } {% for port in seq %} chain Knock_{{loop.index}} { {% if not loop.first %} set update ip{{v}} saddr timeout 0s @Knocked_{{loop.index-1}} {% endif %} set add ip{{v}} saddr @Knocked_{{loop.index}}{% if loop.last %} log prefix "Port-Knock accepted: "{% endif %} } {% if not loop.last %} chain Unknock_{{loop.index}} { set update ip{{v}} saddr timeout 0s @Knocked_{{loop.index}} } {% endif %} {% endfor %} chain RefreshKnock { set update ip{{v}} saddr timeout {{fw_knock_timeout_min}}m @Knocked_{{seq | length}} } chain PortKnock { {% for port in seq | reverse %} {% if loop.first %} ct state new ip{{v}} saddr @Knocked_{{loop.revindex}} goto RefreshKnock {% else %} tcp dport {{seq[loop.revindex]}} ct state new ip{{v}} saddr @Knocked_{{loop.revindex}} goto Knock_{{loop.revindex+1}} tcp dport {{port}} ct state new ip{{v}} saddr @Knocked_{{loop.revindex}} return ip{{v}} saddr @Knocked_{{loop.revindex}} ct state new goto Unknock_{{loop.revindex}} {% endif %} {% if loop.last %} tcp dport {{port}} ct state new goto Knock_{{loop.revindex}} {% endif %} {% endfor %} } chain FilterIn { type filter hook input priority 0 policy drop # allow established/related connections ct state {established, related} accept # early drop of invalid connections ct state invalid drop # allow from loopback meta iif lo accept # allow icmp {% if V == '4' %} ip protocol icmp accept {% else %} ip6 nexthdr icmpv6 accept {% endif %} # allow iodine meta iifname dns0 accept # port-knocking jump PortKnock # trusted ssh and https ct status dnat accept # smtp tcp dport 25 accept # iodine tcp dport 53 accept udp dport 53 accept # http tcp dport 80 accept # https tcp dport 443 accept # smtps tcp dport 465 accept # submission (smtp) tcp dport 587 accept # ipp {% call(net) trust(net_trusted_ranges) %} tcp dport 631 ip{{v}} saddr {{net}} accept udp dport 631 ip{{v}} saddr {{net}} accept {% endcall %} # imaps tcp dport 993 accept # xmpp client tcp dport 5222 accept # xmpp server tcp dport 5269 accept # xmpp components tcp dport 5347 accept # zeroconf {% call(net) trust(net_trusted_ranges) %} udp dport 5353 ip{{v}} saddr {{net}} accept {% endcall %} # remote-help ssh tcp dport 22000 accept {% call(net) trust(net_trusted_ranges) %} tcp dport 22001-22009 ip{{v}} saddr {{net}} accept {% endcall %} # transmission tcp dport {{transmission_bt_port}} accept udp dport {{transmission_bt_port}} accept } chain FilterOut { type filter hook output priority 0 policy drop ct state {established, related} accept meta oif lo accept {% call(net) trust(SafeZone_IP + ' ' + dns_hosts + ' ' + allowed_domains_ip + ' ' + ntp_hosts) %} ip{{v}} daddr {{net}} accept {% endcall %} meta skuid {{aur_user}} accept meta skuid exim tcp dport 25 accept meta skuid prosody accept meta skgid spamd accept meta skuid transmission tcp dport 443 accept meta skuid transmission udp dport 443 accept meta skuid transmission tcp dport > 1024 accept meta skuid transmission udp dport > 1024 accept } } {% endfor %}