ip6t-firewall-server,ipt-firewall-server: HTTP limits only for local webserver; fix several bugs.

- HTTP(S) connection limits are only created if 'http_server_ips' is set.
  The global SYN rate limit no longer ACCEPTs packets (which opened ports
  80/443 on every host) - it now only drops packets above the limit
  (hashlimit without '--hashlimit-mode'). Ports are opened exclusively by
  the rules for 'http_server_ips'.
- Use '$http_ports' instead of hard coded '80,443' for the limits.
- ipt-firewall-server: use '--connlimit-mask 32' instead of 128. With the
  nf_tables backend mask 128 ended up as mask 0, so the limit applied to
  all clients together instead of per IP. Rename hashlimit 'http_v6' -> 'http_v4'.
- Log rules use their own hashlimit tables ('*_log'), otherwise each packet
  is counted twice when logging is enabled.
- SYN-Overflow log rule now logs packets above (not below) the limit.
- ip6t-firewall-server: clamp TCP MSS for HTTPS on all external interfaces
  instead of hard coded 'eth0'.
- Quote test for 'mm_tcp_ports_in' ('[ -n ${mm_tcp_ports_in} ]' was always true).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-02 21:51:16 +01:00
co-authored by Claude Opus 5.5
parent 9de4e742cd
commit 93d9af854b
2 changed files with 81 additions and 59 deletions
+37 -26
View File
@@ -736,10 +736,12 @@ if $throttle_tcp6_mss_for_https ; then
tcp6_mss_for_https_val=$min_tcp6_mss_for_https_val
fi
$ip6t -t mangle -A PREROUTING -i eth0 \
for _dev in ${ext_if_arr[@]} ; do
$ip6t -t mangle -A PREROUTING -i $_dev \
-p tcp --dport 443 \
--tcp-flags SYN,RST SYN \
-j TCPMSS --set-mss $tcp6_mss_for_https_val
done
echo_done
@@ -2169,9 +2171,15 @@ echo_done
# ---
echo ""
# Note:
# The following rules only DROP/REJECT excess connections - they never ACCEPT.
# Ports are opened exclusively by the rules for 'http_server_ips' below.
# Without local webserver (empty 'http_server_ips') no rules are created.
#
echononl "\t\tA maximum number new connections per second per IP"
if $set_max_new_http_conn_per_ip_per_second ; then
if [[ ${#http_server_ip_arr[@]} -gt 0 ]] && $set_max_new_http_conn_per_ip_per_second ; then
if [[ -z "$max_http_new_conn_per_ip_per_second" || ! "$max_http_new_conn_per_ip_per_second" =~ ^[0-9]+$ ]]; then
@@ -2182,8 +2190,8 @@ if $set_max_new_http_conn_per_ip_per_second ; then
burst_http_new_conn_per_ip_per_second=$((max_http_new_conn_per_ip_per_second * 2))
if $log_rejected || $log_all ; then
$ip6t -A INPUT -p tcp -m multiport --dports 80,443 -m conntrack --ctstate NEW \
-m hashlimit --hashlimit-name http_v6 --hashlimit-mode srcip \
$ip6t -A INPUT -p tcp -m multiport --dports $http_ports -m conntrack --ctstate NEW \
-m hashlimit --hashlimit-name http_v6_log --hashlimit-mode srcip \
--hashlimit-above ${max_http_new_conn_per_ip_per_second}/second \
--hashlimit-burst $burst_http_new_conn_per_ip_per_second \
--hashlimit-htable-expire 600000 \
@@ -2192,9 +2200,9 @@ if $set_max_new_http_conn_per_ip_per_second ; then
fi
# HTTP/HTTPS: neue Verbindungen pro Quell-IP begrenzen
# Über 30 neue Verbindungen/s pro IP werden gedroppt
# Über 'max_http_new_conn_per_ip_per_second' neue Verbindungen/s pro IP werden gedroppt
# Eintrag wird nach 600000 ms = 10 Minuten gelöscht (--hashlimit-htable-expire 600000).
$ip6t -A INPUT -p tcp -m multiport --dports 80,443 -m conntrack --ctstate NEW \
$ip6t -A INPUT -p tcp -m multiport --dports $http_ports -m conntrack --ctstate NEW \
-m hashlimit --hashlimit-name http_v6 --hashlimit-mode srcip \
--hashlimit-above ${max_http_new_conn_per_ip_per_second}/second \
--hashlimit-burst $burst_http_new_conn_per_ip_per_second \
@@ -2211,8 +2219,7 @@ fi
echononl "\t\tA maximum number of concurrent TCP connections per IP"
if $set_max_concurrent_http_conn_per_ip ; then
if [[ ${#http_server_ip_arr[@]} -gt 0 ]] && $set_max_concurrent_http_conn_per_ip ; then
if [[ -z "$max_concurrent_http_conn_per_ip" || ! "$max_concurrent_http_conn_per_ip" =~ ^[0-9]+$ ]]; then
@@ -2221,17 +2228,17 @@ if $set_max_concurrent_http_conn_per_ip ; then
fi
if $log_rejected || $log_all ; then
$ip6t -A INPUT -p tcp -m multiport --dports 80,443 --syn \
$ip6t -A INPUT -p tcp -m multiport --dports $http_ports --syn \
-m connlimit --connlimit-above $max_concurrent_http_conn_per_ip --connlimit-mask 128 \
-m limit --limit 10/second --limit-burst 20 \
-j $LOG_TARGET $tag_log_prefix "$log_prefix more then $max_concurrent_http_conn_per_ip concurrent connections per IP."
fi
# HTTP/HTTPS: gleichzeitige Verbindungen pro IP begrenzen
# Mehr als 50 parallele TCP-Verbindungen pro IP ablehnen
# Mehr als 'max_concurrent_http_conn_per_ip' parallele TCP-Verbindungen pro IP ablehnen
#
# Limit gilt pro einzelner IPv4-Adresse (--connlimit-mask 128) (z.bsp. 2a01:599:108:40b0:e1a9:170b:ba18:fd58/128)
$ip6t -A INPUT -p tcp -m multiport --dports 80,443 --syn \
# Limit gilt pro einzelner IPv6-Adresse (--connlimit-mask 128) (z.bsp. 2a01:599:108:40b0:e1a9:170b:ba18:fd58/128)
$ip6t -A INPUT -p tcp -m multiport --dports $http_ports --syn \
-m connlimit --connlimit-above $max_concurrent_http_conn_per_ip --connlimit-mask 128 \
-j REJECT --reject-with tcp-reset
@@ -2244,10 +2251,9 @@ else
fi
echononl "\t\tA maximum number of new TCP handshakes per second."
if $set_max_new_http_conn_per_second ; then
if [[ ${#http_server_ip_arr[@]} -gt 0 ]] && $set_max_new_http_conn_per_second ; then
if [[ -z "$max_new_http_conn_per_second" || ! "$max_new_http_conn_per_second" =~ ^[0-9]+$ ]]; then
@@ -2257,23 +2263,28 @@ if $set_max_new_http_conn_per_second ; then
burst_max_new_http_conn_per_second=$((2 * max_new_http_conn_per_second))
# SYN-Rate begrenzen
# SYN-Rate begrenzen (global, alle Quell-IPs zusammen)
#
# Kurzfristig auch bis zu 400 syn pakete erlaubt. --limit-burst 400 - Danach greift das Limit."
$ip6t -A INPUT -p tcp -m multiport --dports 80,443 \
--syn \
-m limit --limit ${max_new_http_conn_per_second}/second --limit-burst $burst_max_new_http_conn_per_second \
-j ACCEPT
# hashlimit ohne '--hashlimit-mode' verwendet einen einzigen Bucket für alle
# Pakete. SYN-Pakete oberhalb des Limits werden gedroppt; alles darunter
# läuft weiter zu den Regeln für 'http_server_ips' (kein ACCEPT hier!).
#
# Kurzfristig auch bis zu 'burst_max_new_http_conn_per_second' SYN-Pakete erlaubt.
if $log_rejected || $log_all ; then
$ip6t -A INPUT -p tcp -m multiport --dports 80,443 \
$ip6t -A INPUT -p tcp -m multiport --dports $http_ports \
--syn \
-m limit --limit ${max_new_http_conn_per_second}/second --limit-burst $burst_max_new_http_conn_per_second \
-m hashlimit --hashlimit-name http_v6_syn_log \
--hashlimit-above ${max_new_http_conn_per_second}/second \
--hashlimit-burst $burst_max_new_http_conn_per_second \
-m limit --limit 10/second --limit-burst 20 \
-j $LOG_TARGET $tag_log_prefix "$log_prefix SYN-Overflow."
fi
$ip6t -A INPUT -p tcp -m multiport --dports 80,443 \
$ip6t -A INPUT -p tcp -m multiport --dports $http_ports \
--syn \
-m hashlimit --hashlimit-name http_v6_syn \
--hashlimit-above ${max_new_http_conn_per_second}/second \
--hashlimit-burst $burst_max_new_http_conn_per_second \
-j DROP
echo_done
@@ -2319,7 +2330,7 @@ if [[ ${#mm_server_ip_arr[@]} -gt 0 ]] || [[ ${#forward_mm_server_ip_arr[@]} -gt
if [[ ${#mm_server_ip_arr[@]} -gt 0 ]] ; then
for _ip in ${mm_server_ip_arr[@]} ; do
$ip6t -A INPUT -p udp -d $_ip -m multiport --dports $mm_udp_ports_in -m conntrack --ctstate NEW -j ACCEPT
if [ -n ${mm_tcp_ports_in} ] ; then
if [[ -n "$mm_tcp_ports_in" ]] ; then
$ip6t -A INPUT -p tcp -d $_ip -m multiport --dports $mm_tcp_ports_in -m conntrack --ctstate NEW -j ACCEPT
else
$ip6t -A INPUT -p tcp -d $_ip -m multiport --dports $mm_udp_ports_in -m conntrack --ctstate NEW -j ACCEPT
@@ -2330,7 +2341,7 @@ if [[ ${#mm_server_ip_arr[@]} -gt 0 ]] || [[ ${#forward_mm_server_ip_arr[@]} -gt
if [[ ${#forward_mm_server_ip_arr[@]} -gt 0 ]] && $kernel_forward_between_interfaces ; then
for _ip in ${forward_mm_server_ip_arr[@]} ; do
$ip6t -A FORWARD -p udp -d $_ip -m multiport --dports $mm_udp_ports_in -m conntrack --ctstate NEW -j ACCEPT
if [ -n ${mm_tcp_ports_in} ] ; then
if [[ -n "$mm_tcp_ports_in" ]] ; then
$ip6t -A FORWARD -p tcp -d $_ip -m multiport --dports $mm_tcp_ports_in -m conntrack --ctstate NEW -j ACCEPT
else
$ip6t -A FORWARD -p tcp -d $_ip -m multiport --dports $mm_udp_ports_in -m conntrack --ctstate NEW -j ACCEPT
+37 -26
View File
@@ -2247,9 +2247,15 @@ echo_done
# ---
echo ""
# Note:
# The following rules only DROP/REJECT excess connections - they never ACCEPT.
# Ports are opened exclusively by the rules for 'http_server_ips' below.
# Without local webserver (empty 'http_server_ips') no rules are created.
#
echononl "\t\tA maximum number new connections per second per IP"
if $set_max_new_http_conn_per_ip_per_second ; then
if [[ ${#http_server_ip_arr[@]} -gt 0 ]] && $set_max_new_http_conn_per_ip_per_second ; then
if [[ -z "$max_http_new_conn_per_ip_per_second" || ! "$max_http_new_conn_per_ip_per_second" =~ ^[0-9]+$ ]]; then
@@ -2260,8 +2266,8 @@ if $set_max_new_http_conn_per_ip_per_second ; then
burst_http_new_conn_per_ip_per_second=$((max_http_new_conn_per_ip_per_second * 2))
if $log_rejected || $log_all ; then
$ipt -A INPUT -p tcp -m multiport --dports 80,443 -m conntrack --ctstate NEW \
-m hashlimit --hashlimit-name http_v6 --hashlimit-mode srcip \
$ipt -A INPUT -p tcp -m multiport --dports $http_ports -m conntrack --ctstate NEW \
-m hashlimit --hashlimit-name http_v4_log --hashlimit-mode srcip \
--hashlimit-above ${max_http_new_conn_per_ip_per_second}/second \
--hashlimit-burst $burst_http_new_conn_per_ip_per_second \
--hashlimit-htable-expire 600000 \
@@ -2270,10 +2276,10 @@ if $set_max_new_http_conn_per_ip_per_second ; then
fi
# HTTP/HTTPS: neue Verbindungen pro Quell-IP begrenzen
# Über 30 neue Verbindungen/s pro IP werden gedroppt
# Über 'max_http_new_conn_per_ip_per_second' neue Verbindungen/s pro IP werden gedroppt
# Eintrag wird nach 600000 ms = 10 Minuten gelöscht (--hashlimit-htable-expire 600000).
$ipt -A INPUT -p tcp -m multiport --dports 80,443 -m conntrack --ctstate NEW \
-m hashlimit --hashlimit-name http_v6 --hashlimit-mode srcip \
$ipt -A INPUT -p tcp -m multiport --dports $http_ports -m conntrack --ctstate NEW \
-m hashlimit --hashlimit-name http_v4 --hashlimit-mode srcip \
--hashlimit-above ${max_http_new_conn_per_ip_per_second}/second \
--hashlimit-burst $burst_http_new_conn_per_ip_per_second \
--hashlimit-htable-expire 600000 -j DROP
@@ -2289,7 +2295,7 @@ fi
echononl "\t\tA maximum number of concurrent TCP connections per IP"
if $set_max_concurrent_http_conn_per_ip ; then
if [[ ${#http_server_ip_arr[@]} -gt 0 ]] && $set_max_concurrent_http_conn_per_ip ; then
if [[ -z "$max_concurrent_http_conn_per_ip" || ! "$max_concurrent_http_conn_per_ip" =~ ^[0-9]+$ ]]; then
@@ -2298,18 +2304,18 @@ if $set_max_concurrent_http_conn_per_ip ; then
fi
if $log_rejected || $log_all ; then
$ipt -A INPUT -p tcp -m multiport --dports 80,443 --syn \
-m connlimit --connlimit-above $max_concurrent_http_conn_per_ip --connlimit-mask 128 \
$ipt -A INPUT -p tcp -m multiport --dports $http_ports --syn \
-m connlimit --connlimit-above $max_concurrent_http_conn_per_ip --connlimit-mask 32 \
-m limit --limit 10/second --limit-burst 20 \
-j $LOG_TARGET $tag_log_prefix "$log_prefix more then $max_concurrent_http_conn_per_ip concurrent connections per IP."
fi
# HTTP/HTTPS: gleichzeitige Verbindungen pro IP begrenzen
# Mehr als 50 parallele TCP-Verbindungen pro IP ablehnen
# Mehr als 'max_concurrent_http_conn_per_ip' parallele TCP-Verbindungen pro IP ablehnen
#
# Limit gilt pro einzelner IPv4-Adresse (--connlimit-mask 128) (z.bsp. 2a01:599:108:40b0:e1a9:170b:ba18:fd58/128)
$ipt -A INPUT -p tcp -m multiport --dports 80,443 --syn \
-m connlimit --connlimit-above $max_concurrent_http_conn_per_ip --connlimit-mask 128 \
# Limit gilt pro einzelner IPv4-Adresse (--connlimit-mask 32)
$ipt -A INPUT -p tcp -m multiport --dports $http_ports --syn \
-m connlimit --connlimit-above $max_concurrent_http_conn_per_ip --connlimit-mask 32 \
-j REJECT --reject-with tcp-reset
echo_done
@@ -2323,7 +2329,7 @@ fi
echononl "\t\tA maximum number of new TCP handshakes per second."
if $set_max_new_http_conn_per_second ; then
if [[ ${#http_server_ip_arr[@]} -gt 0 ]] && $set_max_new_http_conn_per_second ; then
if [[ -z "$max_new_http_conn_per_second" || ! "$max_new_http_conn_per_second" =~ ^[0-9]+$ ]]; then
@@ -2333,23 +2339,28 @@ if $set_max_new_http_conn_per_second ; then
burst_max_new_http_conn_per_second=$((2 * max_new_http_conn_per_second))
# SYN-Rate begrenzen
# SYN-Rate begrenzen (global, alle Quell-IPs zusammen)
#
# Kurzfristig auch bis zu 400 syn pakete erlaubt. --limit-burst 400 - Danach greift das Limit."
$ipt -A INPUT -p tcp -m multiport --dports 80,443 \
--syn \
-m limit --limit ${max_new_http_conn_per_second}/second --limit-burst $burst_max_new_http_conn_per_second \
-j ACCEPT
# hashlimit ohne '--hashlimit-mode' verwendet einen einzigen Bucket für alle
# Pakete. SYN-Pakete oberhalb des Limits werden gedroppt; alles darunter
# läuft weiter zu den Regeln für 'http_server_ips' (kein ACCEPT hier!).
#
# Kurzfristig auch bis zu 'burst_max_new_http_conn_per_second' SYN-Pakete erlaubt.
if $log_rejected || $log_all ; then
$ipt -A INPUT -p tcp -m multiport --dports 80,443 \
$ipt -A INPUT -p tcp -m multiport --dports $http_ports \
--syn \
-m limit --limit ${max_new_http_conn_per_second}/second --limit-burst $burst_max_new_http_conn_per_second \
-m hashlimit --hashlimit-name http_v4_syn_log \
--hashlimit-above ${max_new_http_conn_per_second}/second \
--hashlimit-burst $burst_max_new_http_conn_per_second \
-m limit --limit 10/second --limit-burst 20 \
-j $LOG_TARGET $tag_log_prefix "$log_prefix SYN-Overflow."
fi
$ipt -A INPUT -p tcp -m multiport --dports 80,443 \
$ipt -A INPUT -p tcp -m multiport --dports $http_ports \
--syn \
-m hashlimit --hashlimit-name http_v4_syn \
--hashlimit-above ${max_new_http_conn_per_second}/second \
--hashlimit-burst $burst_max_new_http_conn_per_second \
-j DROP
echo_done
@@ -2395,7 +2406,7 @@ if [[ ${#mm_server_ip_arr[@]} -gt 0 ]] || [[ ${#forward_mm_server_ip_arr[@]} -gt
if [[ ${#mm_server_ip_arr[@]} -gt 0 ]] ; then
for _ip in ${mm_server_ip_arr[@]} ; do
$ipt -A INPUT -p udp -d $_ip -m multiport --dports $mm_udp_ports_in -m conntrack --ctstate NEW -j ACCEPT
if [ -n ${mm_tcp_ports_in} ] ; then
if [[ -n "$mm_tcp_ports_in" ]] ; then
$ipt -A INPUT -p tcp -d $_ip -m multiport --dports $mm_tcp_ports_in -m conntrack --ctstate NEW -j ACCEPT
else
$ipt -A INPUT -p tcp -d $_ip -m multiport --dports $mm_udp_ports_in -m conntrack --ctstate NEW -j ACCEPT
@@ -2406,7 +2417,7 @@ if [[ ${#mm_server_ip_arr[@]} -gt 0 ]] || [[ ${#forward_mm_server_ip_arr[@]} -gt
if [[ ${#forward_mm_server_ip_arr[@]} -gt 0 ]] && $kernel_activate_forwarding ; then
for _ip in ${forward_mm_server_ip_arr[@]} ; do
$ipt -A FORWARD -p udp -d $_ip -m multiport --dports $mm_udp_ports_in -m conntrack --ctstate NEW -j ACCEPT
if [ -n ${mm_tcp_ports_in} ] ; then
if [[ -n "$mm_tcp_ports_in" ]] ; then
$ipt -A FORWARD -p tcp -d $_ip -m multiport --dports $mm_tcp_ports_in -m conntrack --ctstate NEW -j ACCEPT
else
$ipt -A FORWARD -p tcp -d $_ip -m multiport --dports $mm_udp_ports_in -m conntrack --ctstate NEW -j ACCEPT