diff --git a/extract-fw-host-vars.py b/extract-fw-host-vars.py index 475ae13..1704854 100755 --- a/extract-fw-host-vars.py +++ b/extract-fw-host-vars.py @@ -168,8 +168,9 @@ DEFAULTS = { "fw_protection_against_ssh_brute_force_attacks": True, "fw_limit_connections_per_source_IP": True, "fw_per_IP_connection_limit": "$default_per_IP_connection_limit", - "fw_limit_new_tcp_connections_per_seconds_per_source_IP": True, - "fw_limit_new_tcp_connections_per_seconds_ports": "", + "fw_limit_new_tcp_connections_per_seconds_per_source_IP": False, + "fw_limit_new_tcp_connections_per_seconds_ports": "80,110,143,443,465,995", + "fw_limit_new_tcp_connections_per_seconds_rate": "$default_limit_new_tcp_connections_per_seconds_rate", "fw_kernel_activate_forwarding": False, "fw_kernel_support_dynaddr": False, "fw_dynaddr_flag": "5", @@ -302,6 +303,7 @@ MAIN_SHARED = { "per_IP_connection_limit": "fw_per_IP_connection_limit", "limit_new_tcp_connections_per_seconds_per_source_IP": "fw_limit_new_tcp_connections_per_seconds_per_source_IP", "limit_new_tcp_connections_per_seconds_ports": "fw_limit_new_tcp_connections_per_seconds_ports", + "limit_new_tcp_connections_per_seconds_rate": "fw_limit_new_tcp_connections_per_seconds_rate", } # IPv4-only variables (from main_ipv4.conf) @@ -687,7 +689,8 @@ def render_yaml(hostname, host_vars, all_warnings): "fw_protection_against_ssh_brute_force_attacks", "fw_limit_connections_per_source_IP", "fw_per_IP_connection_limit", "fw_limit_new_tcp_connections_per_seconds_per_source_IP", - "fw_limit_new_tcp_connections_per_seconds_ports"]), + "fw_limit_new_tcp_connections_per_seconds_ports", + "fw_limit_new_tcp_connections_per_seconds_rate"]), ("Kernel IPv4", ["fw_kernel_support_dynaddr", "fw_dynaddr_flag", "fw_kernel_reduce_timeouts", "fw_kernel_tcp_syncookies", "fw_kernel_protect_against_icmp_bogus_messages", diff --git a/host_vars/oolm-shop.oopen.de/oolm-shop-ipt-server.yml b/host_vars/oolm-shop.oopen.de/oolm-shop-ipt-server.yml index 40b10a8..2cc03db 100644 --- a/host_vars/oolm-shop.oopen.de/oolm-shop-ipt-server.yml +++ b/host_vars/oolm-shop.oopen.de/oolm-shop-ipt-server.yml @@ -44,4 +44,3 @@ fw_limit_connections_per_source_IP_v6: true fw_per_IP_connection_limit: 2048 fw_per_IP_connection_limit_v6: 1024 fw_limit_new_tcp_connections_per_seconds_per_source_IP: false -fw_limit_new_tcp_connections_per_seconds_per_source_IP_v6: true diff --git a/host_vars/piwik.warenform.de/piwik-ipt-server.yml b/host_vars/piwik.warenform.de/piwik-ipt-server.yml index bb87519..bdc8e3d 100644 --- a/host_vars/piwik.warenform.de/piwik-ipt-server.yml +++ b/host_vars/piwik.warenform.de/piwik-ipt-server.yml @@ -3,7 +3,7 @@ # Generated by extract-fw-host-vars.py - review before committing! # Place in: host_vars//-ipt-server.yml -fw_manage_config: false +fw_manage_config: true # --- Network fw_ext_interfaces: @@ -22,3 +22,7 @@ fw_http_server_ips: $ext_1_ip # --- Block fw_blocked_ips_v4: 222.184.0.0/13 61.160.0.0/16 116.8.0.0/14 + +# --- Protection / limits +fw_per_IP_connection_limit: 501 +fw_limit_new_tcp_connections_per_seconds_per_source_IP: false diff --git a/roles/ipt-server/README.md b/roles/ipt-server/README.md index 9d59b8b..a8ecfb0 100644 --- a/roles/ipt-server/README.md +++ b/roles/ipt-server/README.md @@ -221,6 +221,11 @@ Neustart der Firewall aus. | `fw_max_concurrent_http_conn_per_ip` | `"$default_max_concurrent_http_conn_per_ip"` | Limit dazu | | `fw_set_max_new_http_conn_per_second` | `true` | SYN-Rate auf 80/443 insgesamt begrenzen | | `fw_max_new_http_conn_per_second` | `"$default_max_new_http_conn_per_second"` | Limit dazu | +| `fw_limit_connections_per_source_IP` | `true` | Gleichzeitige TCP-Verbindungen pro Quell-IP begrenzen | +| `fw_per_IP_connection_limit` | `"$default_per_IP_connection_limit"` | Limit dazu (Default 250) | +| `fw_limit_new_tcp_connections_per_seconds_per_source_IP` | `false` | Neue TCP-Verbindungen/s pro Quell-IP begrenzen | +| `fw_limit_new_tcp_connections_per_seconds_ports` | `"80,110,143,443,465,995"` | Ports dazu (kommagetrennt) | +| `fw_limit_new_tcp_connections_per_seconds_rate` | `"$default_limit_new_tcp_connections_per_seconds_rate"` | Neue Verbindungen/s pro Quell-IP (Default 30, Burst = doppelter Wert); darüber wird verworfen | | `fw_throttle_tcp6_mss_for_https` | `false` | Nur IPv6: MSS eingehender HTTPS-SYNs clampen | | `fw_tcp6_mss_for_https_val` | `"$min_tcp6_mss_for_https_val"` | Nur IPv6: MSS-Wert (z.B. `1360`) | | `fw_mm_tcp_ports_in` | `"$standard_mattermost_tcp_ports_in"` | Mattermost TCP-Fallback (STUN) | diff --git a/roles/ipt-server/defaults/main.yml b/roles/ipt-server/defaults/main.yml index 4f6a1ce..3356b44 100644 --- a/roles/ipt-server/defaults/main.yml +++ b/roles/ipt-server/defaults/main.yml @@ -364,8 +364,12 @@ fw_protection_against_ssh_brute_force_attacks: true fw_limit_connections_per_source_IP: true fw_per_IP_connection_limit: "$default_per_IP_connection_limit" -fw_limit_new_tcp_connections_per_seconds_per_source_IP: true -fw_limit_new_tcp_connections_per_seconds_ports: "" +# Rate limit for new TCP connections per source IP; only active if true +# and the port list (comma separated) is not empty. +fw_limit_new_tcp_connections_per_seconds_per_source_IP: false +fw_limit_new_tcp_connections_per_seconds_ports: "80,110,143,443,465,995" +# New connections per second per source IP; burst is twice this value. +fw_limit_new_tcp_connections_per_seconds_rate: "$default_limit_new_tcp_connections_per_seconds_rate" # --- diff --git a/roles/ipt-server/files/etc/ipt-firewall/default_settings.conf b/roles/ipt-server/files/etc/ipt-firewall/default_settings.conf index c6a0f24..d8f86bd 100644 --- a/roles/ipt-server/files/etc/ipt-firewall/default_settings.conf +++ b/roles/ipt-server/files/etc/ipt-firewall/default_settings.conf @@ -6,6 +6,13 @@ default_per_IP_connection_limit=250 +# ip6t-firewall-server,ipt-firewall-server: +# New (syn) TCP connections per second per source IP on the ports in +# 'limit_new_tcp_connections_per_seconds_ports'. The burst is twice +# this value. +# +default_limit_new_tcp_connections_per_seconds_rate=30 + # ------------- # --- Default Ports for Services out diff --git a/roles/ipt-server/files/usr/local/sbin/ip6t-firewall-server b/roles/ipt-server/files/usr/local/sbin/ip6t-firewall-server index 9ddd69d..15a0baa 100755 --- a/roles/ipt-server/files/usr/local/sbin/ip6t-firewall-server +++ b/roles/ipt-server/files/usr/local/sbin/ip6t-firewall-server @@ -1162,29 +1162,56 @@ echononl "\tLimit new (syn) TCP connections per second per source IP (multiport) if $limit_new_tcp_connections_per_seconds_per_source_IP \ && [[ ${#limit_new_tcp_connections_per_seconds_ports} -gt 0 ]]; then - #$ip6t -A INPUT -p tcp -m conntrack --ctstate NEW -m limit --limit 60/s --limit-burst 20 -j ACCEPT + if [[ -z "$limit_new_tcp_connections_per_seconds_rate" \ + || ! "$limit_new_tcp_connections_per_seconds_rate" =~ ^[0-9]+$ ]]; then + limit_new_tcp_connections_per_seconds_rate=$default_limit_new_tcp_connections_per_seconds_rate + fi + limit_new_tcp_connections_per_seconds_burst=$((limit_new_tcp_connections_per_seconds_rate * 2)) - # Rate-Limit für neue SYNs auf 443 pro IP - $ip6t -A INPUT -p tcp --syn \ - -m multiport --dports $limit_new_tcp_connections_per_seconds_ports \ - -m hashlimit --hashlimit-name syn_multi_v4 \ - --hashlimit 30/second --hashlimit-burst 60 \ - --hashlimit-mode srcip --hashlimit-srcmask 32 \ - -j ACCEPT + # Only (syn) packets above the limit are dropped here. Packets below the + # limit are not accepted but pass on to the rules of the services, so this + # does not open any port and does not bypass later limits. + if can_use_hashlimit ; then - if $log_rejected || $log_all ; then + if $log_rejected || $log_all ; then + $ip6t -A INPUT -p tcp --syn \ + -m multiport --dports $limit_new_tcp_connections_per_seconds_ports \ + -m hashlimit --hashlimit-name syn_multi_v6_log --hashlimit-mode srcip \ + --hashlimit-srcmask 128 \ + --hashlimit-above ${limit_new_tcp_connections_per_seconds_rate}/second \ + --hashlimit-burst $limit_new_tcp_connections_per_seconds_burst \ + -m limit --limit 2/second --limit-burst 10 \ + -j $LOG_TARGET $tag_log_prefix "$log_prefix SYN over limit (multiport):" + fi - #$ip6t -A INPUT -p tcp -m conntrack --ctstate NEW -j $LOG_TARGET $tag_log_prefix "$log_prefix Limit new TCP conn's: " - - # rate-limited logging für Überschreiter $ip6t -A INPUT -p tcp --syn \ -m multiport --dports $limit_new_tcp_connections_per_seconds_ports \ - -m hashlimit --hashlimit-name syn_multi_v4_log \ - --hashlimit 2/second --hashlimit-burst 10 \ - --hashlimit-mode srcip --hashlimit-srcmask 32 \ - -j $LOG_TARGET $tag_log_prefix "$log_prefix SYN over limit (multiport):" + -m hashlimit --hashlimit-name syn_multi_v6 --hashlimit-mode srcip \ + --hashlimit-srcmask 128 \ + --hashlimit-above ${limit_new_tcp_connections_per_seconds_rate}/second \ + --hashlimit-burst $limit_new_tcp_connections_per_seconds_burst \ + -j DROP + + else + + warn "xt_hashlimit not available; using simple global limit fallback for SYN rate limiting (multiport)." + + $ip6t -N syn-multi-limit + $ip6t -A syn-multi-limit \ + -m limit --limit ${limit_new_tcp_connections_per_seconds_rate}/second \ + --limit-burst $limit_new_tcp_connections_per_seconds_burst \ + -j RETURN + if $log_rejected || $log_all ; then + $ip6t -A syn-multi-limit -m limit --limit 2/second --limit-burst 10 \ + -j $LOG_TARGET $tag_log_prefix "$log_prefix SYN over limit (multiport):" + fi + $ip6t -A syn-multi-limit -j DROP + + $ip6t -A INPUT -p tcp --syn \ + -m multiport --dports $limit_new_tcp_connections_per_seconds_ports \ + -j syn-multi-limit fi - $ip6t -A INPUT -p tcp -m conntrack --ctstate NEW -j DROP + echo_done else echo_skipped diff --git a/roles/ipt-server/files/usr/local/sbin/ipt-firewall-server b/roles/ipt-server/files/usr/local/sbin/ipt-firewall-server index 57b311e..9693fef 100755 --- a/roles/ipt-server/files/usr/local/sbin/ipt-firewall-server +++ b/roles/ipt-server/files/usr/local/sbin/ipt-firewall-server @@ -1210,41 +1210,55 @@ echononl "\tLimit new (syn) TCP connections per second per source IP (multiport) if $limit_new_tcp_connections_per_seconds_per_source_IP \ && [[ ${#limit_new_tcp_connections_per_seconds_ports} -gt 0 ]]; then - #$ipt -A INPUT -p tcp -m conntrack --ctstate NEW -m limit --limit 60/s --limit-burst 20 -j ACCEPT + if [[ -z "$limit_new_tcp_connections_per_seconds_rate" \ + || ! "$limit_new_tcp_connections_per_seconds_rate" =~ ^[0-9]+$ ]]; then + limit_new_tcp_connections_per_seconds_rate=$default_limit_new_tcp_connections_per_seconds_rate + fi + limit_new_tcp_connections_per_seconds_burst=$((limit_new_tcp_connections_per_seconds_rate * 2)) - # Rate-Limit für neue SYNs auf 443 pro IP + # Only (syn) packets above the limit are dropped here. Packets below the + # limit are not accepted but pass on to the rules of the services, so this + # does not open any port and does not bypass later limits. if can_use_hashlimit ; then - $ipt -A INPUT -p tcp --syn \ - -m multiport --dports $limit_new_tcp_connections_per_seconds_ports \ - -m hashlimit --hashlimit-name syn_multi_v4 \ - --hashlimit 30/second --hashlimit-burst 60 \ - --hashlimit-mode srcip --hashlimit-srcmask 32 \ - -j ACCEPT - if $log_rejected || $log_all ; then + if $log_rejected || $log_all ; then + $ipt -A INPUT -p tcp --syn \ + -m multiport --dports $limit_new_tcp_connections_per_seconds_ports \ + -m hashlimit --hashlimit-name syn_multi_v4_log --hashlimit-mode srcip \ + --hashlimit-srcmask 32 \ + --hashlimit-above ${limit_new_tcp_connections_per_seconds_rate}/second \ + --hashlimit-burst $limit_new_tcp_connections_per_seconds_burst \ + -m limit --limit 2/second --limit-burst 10 \ + -j $LOG_TARGET $tag_log_prefix "$log_prefix SYN over limit (multiport):" + fi - # rate-limited logging für Überschreiter $ipt -A INPUT -p tcp --syn \ -m multiport --dports $limit_new_tcp_connections_per_seconds_ports \ - -m hashlimit --hashlimit-name syn_multi_v4_log \ - --hashlimit 2/second --hashlimit-burst 10 \ - --hashlimit-mode srcip --hashlimit-srcmask 32 \ - -j $LOG_TARGET $tag_log_prefix "$log_prefix SYN over limit (multiport):" + -m hashlimit --hashlimit-name syn_multi_v4 --hashlimit-mode srcip \ + --hashlimit-srcmask 32 \ + --hashlimit-above ${limit_new_tcp_connections_per_seconds_rate}/second \ + --hashlimit-burst $limit_new_tcp_connections_per_seconds_burst \ + -j DROP + else + + warn "xt_hashlimit not available; using simple global limit fallback for SYN rate limiting (multiport)." + + $ipt -N syn-multi-limit + $ipt -A syn-multi-limit \ + -m limit --limit ${limit_new_tcp_connections_per_seconds_rate}/second \ + --limit-burst $limit_new_tcp_connections_per_seconds_burst \ + -j RETURN + if $log_rejected || $log_all ; then + $ipt -A syn-multi-limit -m limit --limit 2/second --limit-burst 10 \ + -j $LOG_TARGET $tag_log_prefix "$log_prefix SYN over limit (multiport):" + fi + $ipt -A syn-multi-limit -j DROP + + $ipt -A INPUT -p tcp --syn \ + -m multiport --dports $limit_new_tcp_connections_per_seconds_ports \ + -j syn-multi-limit fi -else - warn "xt_hashlimit not available; using simple global limit fallback for SYN rate limiting (multiport)." - $ipt -A INPUT -p tcp --syn \ - -m multiport --dports $limit_new_tcp_connections_per_seconds_ports \ - -m limit --limit 30/second --limit-burst 60 \ - -j ACCEPT -fi - - - #$ipt -A INPUT -p tcp -m conntrack --ctstate NEW -j DROP - - $ipt -A INPUT -p tcp --syn -m multiport --dports $limit_new_tcp_connections_per_seconds_ports -j DROP - echo_done else diff --git a/roles/ipt-server/templates/etc/ipt-firewall/main_ipv4.conf.j2 b/roles/ipt-server/templates/etc/ipt-firewall/main_ipv4.conf.j2 index 6ab590a..555e1b5 100644 --- a/roles/ipt-server/templates/etc/ipt-firewall/main_ipv4.conf.j2 +++ b/roles/ipt-server/templates/etc/ipt-firewall/main_ipv4.conf.j2 @@ -347,6 +347,7 @@ per_IP_connection_limit={{ fw_per_IP_connection_limit }} limit_new_tcp_connections_per_seconds_per_source_IP={{ fw_limit_new_tcp_connections_per_seconds_per_source_IP | lower }} limit_new_tcp_connections_per_seconds_ports="{{ fw_limit_new_tcp_connections_per_seconds_ports }}" +limit_new_tcp_connections_per_seconds_rate="{{ fw_limit_new_tcp_connections_per_seconds_rate }}" # ------------- diff --git a/roles/ipt-server/templates/etc/ipt-firewall/main_ipv6.conf.j2 b/roles/ipt-server/templates/etc/ipt-firewall/main_ipv6.conf.j2 index 3cf36c2..c5a69f5 100644 --- a/roles/ipt-server/templates/etc/ipt-firewall/main_ipv6.conf.j2 +++ b/roles/ipt-server/templates/etc/ipt-firewall/main_ipv6.conf.j2 @@ -349,6 +349,7 @@ per_IP_connection_limit={{ (fw_per_IP_connection_limit_v6 | default(fw_per_IP_co limit_new_tcp_connections_per_seconds_per_source_IP={{ (fw_limit_new_tcp_connections_per_seconds_per_source_IP_v6 | default(fw_limit_new_tcp_connections_per_seconds_per_source_IP)) | lower }} limit_new_tcp_connections_per_seconds_ports="{{ (fw_limit_new_tcp_connections_per_seconds_ports_v6 | default(fw_limit_new_tcp_connections_per_seconds_ports)) }}" +limit_new_tcp_connections_per_seconds_rate="{{ (fw_limit_new_tcp_connections_per_seconds_rate_v6 | default(fw_limit_new_tcp_connections_per_seconds_rate)) }}" # -------------