# IPv6 persistent firewall base prepared for publication on 2026-08-16. # Its non-comment lines exactly match the deployed /etc/iptables/rules.v6. # All packet and byte counters are deliberately reset to [0:0]. # This is a server-specific reference, not a turnkey template: verify eno1, # the OVH IPv6 routing model, Docker listeners and CrowdSec sets first. # Restore this family with ip6tables-restore only. # The current Fail2ban SSH action inserts f2b-sshd in IPv4 only; no Fail2ban # chain or INPUT jump is expected in this IPv6 base or in the live IPv6 policy. # AbuseIPDB set matches are intentionally absent: the # abuseipdb-blocklist-rules.service unit creates the ipsets first, then inserts # the INPUT and DOCKER-USER DROP lookups. # Docker-owned chains reflect the validated Proxy_net topology at capture time. # SECURITY BLOCK: malformed TCP flag combinations # Drop impossible or scan-associated flag patterns before normal stateful # filtering. This is protocol sanitization, not a replacement for conntrack. *mangle :PREROUTING ACCEPT [0:0] :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] -A PREROUTING -p tcp -m tcp --tcp-flags FIN,SYN FIN,SYN -j DROP -A PREROUTING -p tcp -m tcp --tcp-flags SYN,RST SYN,RST -j DROP -A PREROUTING -p tcp -m tcp --tcp-flags FIN,RST FIN,RST -j DROP -A PREROUTING -p tcp -m tcp --tcp-flags FIN,ACK FIN -j DROP -A PREROUTING -p tcp -m tcp --tcp-flags ACK,URG URG -j DROP -A PREROUTING -p tcp -m tcp --tcp-flags PSH,ACK PSH -j DROP -A PREROUTING -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,SYN,RST,PSH,ACK,URG -j DROP -A PREROUTING -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE -j DROP -A PREROUTING -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,PSH,URG -j DROP -A PREROUTING -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,SYN,PSH,URG -j DROP -A PREROUTING -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,SYN,RST,ACK,URG -j DROP COMMIT # The raw table contains controls that must run before ordinary conntrack and # filter processing. Each security block below documents its own scope. *raw :PREROUTING ACCEPT [0:0] :OUTPUT ACCEPT [0:0] # SECURITY BLOCK: public-ingress source anti-spoofing # Reject selected special-use sources that must not arrive from the Internet: # loopback, unique-local, documentation and multicast source addresses. The # OVH design requires link-local traffic on eno1, so fe80::/10 remains allowed. -A PREROUTING -i eno1 -s ::1/128 -j DROP -A PREROUTING -i eno1 -s fc00::/7 -j DROP -A PREROUTING -i eno1 -s 2001:db8::/32 -j DROP -A PREROUTING -i eno1 -s ff00::/8 -j DROP # SECURITY BLOCK: bounded SYN flood control for exposed services # Drop only above 200 SYN/s with burst 1000, grouped by IPv4 /24 or IPv6 /64, # for ports 22, 80 and 443. This is deliberately permissive for web traffic. -A PREROUTING -i eno1 -p tcp --syn -m multiport --dports 22,80,443 -m hashlimit --hashlimit-above 200/sec --hashlimit-burst 1000 --hashlimit-mode srcip --hashlimit-name syn6 --hashlimit-htable-size 1048576 --hashlimit-srcmask 64 -j DROP COMMIT # Default INPUT/FORWARD policy is DROP. Explicit blocks below establish the # accepted host traffic and delegate Docker forwarding to Docker-owned chains. *filter :INPUT DROP [0:0] :FORWARD DROP [0:0] :OUTPUT ACCEPT [0:0] :CROWDSEC_CHAIN - [0:0] :DOCKER - [0:0] :DOCKER-BRIDGE - [0:0] :DOCKER-CT - [0:0] :DOCKER-FORWARD - [0:0] :DOCKER-INTERNAL - [0:0] :DOCKER-USER - [0:0] :LOG_N_IPS-ACCEPT - [0:0] # SECURITY BLOCK: reputation and behavioral deny lists # This persistent base owns the CrowdSec jump. AbuseIPDB dynamically inserts # its IPv6 set lookup immediately after it. The current Fail2ban SSH action is # IPv4-only, so no f2b-sshd jump is expected here. -A INPUT -j CROWDSEC_CHAIN # SECURITY BLOCK: per-source SSH connection ceiling # Reject only a new SSH SYN when that source already owns more than 100 tracked # connections. Established packets never re-enter this test. Fail2ban and # CrowdSec remain the brute-force controls. -A INPUT -i eno1 -p tcp --syn --dport 22 -m connlimit --connlimit-above 100 --connlimit-mask 128 --connlimit-saddr -j REJECT --reject-with icmp6-port-unreachable # TRUST BLOCK: local loopback # Permit host-local IPC on lo; this does not trust Docker bridge interfaces. -A INPUT -i lo -j ACCEPT # AVAILABILITY BLOCK: IPv6 neighbor and router discovery # Permit essential link-local discovery only on eno1 with hop-limit 255 so the # OVH on-link /128 gateway design remains reachable. -A INPUT -i eno1 -p ipv6-icmp --icmpv6-type router-solicitation -m hl --hl-eq 255 -j ACCEPT -A INPUT -i eno1 -p ipv6-icmp --icmpv6-type router-advertisement -m hl --hl-eq 255 -j ACCEPT -A INPUT -i eno1 -p ipv6-icmp --icmpv6-type neighbour-solicitation -m hl --hl-eq 255 -j ACCEPT -A INPUT -i eno1 -p ipv6-icmp --icmpv6-type neighbour-advertisement -m hl --hl-eq 255 -j ACCEPT # AVAILABILITY BLOCK: operational ICMP control traffic # Permit required errors for reachability and Path MTU Discovery; echo requests # are allowed at 5/s with burst 10 instead of using a blanket ICMP drop. -A INPUT -p ipv6-icmp --icmpv6-type destination-unreachable -j ACCEPT -A INPUT -p ipv6-icmp --icmpv6-type packet-too-big -j ACCEPT -A INPUT -p ipv6-icmp --icmpv6-type time-exceeded -j ACCEPT -A INPUT -p ipv6-icmp --icmpv6-type parameter-problem -j ACCEPT -A INPUT -p ipv6-icmp --icmpv6-type echo-request -m limit --limit 5/second --limit-burst 10 -j ACCEPT # STATE BLOCK: established and related host traffic # Preserve active SSH/web sessions before the scanner quarantine. A source # trapped later can keep its current web session but cannot open a new one. -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT # SECURITY BLOCK: retained 24-hour scanner quarantine # Sources probing selected high-risk closed ports are remembered for 24 hours. # Existing tracked sessions were accepted earlier; new probes and connection # attempts disappear here. The next rule removes an expired list entry. Source # spoofing can abuse this as a targeted DoS; that risk is explicitly accepted. -A INPUT -m recent --rcheck --seconds 86400 --name portscan6 --rsource -j DROP -A INPUT -m recent --remove --name portscan6 --rsource -A INPUT -p tcp -m multiport --dports 23,25,445,1433,5432,3389 -m recent --set --name portscan6 --rsource -j DROP # SECURITY BLOCK: invalid conntrack state # Drop packets that cannot belong to a valid normally tracked flow. # SYNPROXY/NOTRACK are intentionally absent; conntrack loose pickup is enabled. -A INPUT -m conntrack --ctstate INVALID -j DROP # SERVICE BLOCK: explicitly Internet-exposed TCP services # Permit SSH 22 and web 80/443. No legacy Portainer 9443 host exposure exists. -A INPUT -p tcp -m multiport --dports 22,80,443 -j ACCEPT # FORWARDING BLOCK: Docker administrator and engine policy # Evaluate DOCKER-USER first (including dynamic AbuseIPDB), then delegate to # Docker's connection tracking, bridge isolation and published-port chains. -A FORWARD -j DOCKER-USER -A FORWARD -j DOCKER-FORWARD # DYNAMIC DATA BLOCK: CrowdSec-managed ipsets # These DROP lookups reference sets maintained independently by CrowdSec. -A CROWDSEC_CHAIN -m set --match-set crowdsec6-blacklists-0 src -m comment --comment "CrowdSec: CAPI" -j DROP # DOCKER-OWNED BLOCK: current IPv6 forwarding scaffolding # Docker keeps its forwarding dispatcher jumps, but currently installs no # per-container IPv6 filter rules here. NPM 80/443 use local docker-proxy # listeners. DOCKER-USER intentionally has no general fail-closed port policy. -A DOCKER-FORWARD -j DOCKER-CT -A DOCKER-FORWARD -j DOCKER-INTERNAL -A DOCKER-FORWARD -j DOCKER-BRIDGE # RESERVED BLOCK: LOG_N_IPS-ACCEPT # Preserve the future NFQUEUE integration chain exactly as requested. -A LOG_N_IPS-ACCEPT -j NFQUEUE --queue-num 0 -A LOG_N_IPS-ACCEPT -j ACCEPT COMMIT # Docker-created IPv6 NAT scaffolding for locally published services. *nat :PREROUTING ACCEPT [0:0] :INPUT ACCEPT [0:0] :OUTPUT ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] :DOCKER - [0:0] # DOCKER-OWNED BLOCK: local dispatch without IPv6 DNAT # NPM ports 80/443 use local docker-proxy listeners, so the DOCKER chain has no # IPv6 DNAT or masquerade entry in this captured topology. -A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER -A OUTPUT ! -d ::1/128 -m addrtype --dst-type LOCAL -j DOCKER COMMIT