From patchwork Mon Oct 18 10:10:21 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Tremer X-Patchwork-Id: 4795 Return-Path: Received: from mail01.ipfire.org (mail01.haj.ipfire.org [172.28.1.202]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) client-signature ECDSA (P-384)) (Client CN "mail01.haj.ipfire.org", Issuer "R3" (verified OK)) by web04.haj.ipfire.org (Postfix) with ESMTPS id 4HXtB30vw6z3wct for ; Mon, 18 Oct 2021 10:18:19 +0000 (UTC) Received: from mail02.haj.ipfire.org (mail02.haj.ipfire.org [172.28.1.201]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) client-signature ECDSA (P-384)) (Client CN "mail02.haj.ipfire.org", Issuer "R3" (verified OK)) by mail01.ipfire.org (Postfix) with ESMTPS id 4HXt9q3TjPz5Mb; Mon, 18 Oct 2021 10:18:07 +0000 (UTC) Received: from mail02.haj.ipfire.org (localhost [127.0.0.1]) by mail02.haj.ipfire.org (Postfix) with ESMTP id 4HXt9p4Fffz30Q7; Mon, 18 Oct 2021 10:18:06 +0000 (UTC) Received: from mail01.ipfire.org (mail01.haj.ipfire.org [172.28.1.202]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) client-signature ECDSA (P-384)) (Client CN "mail01.haj.ipfire.org", Issuer "R3" (verified OK)) by mail02.haj.ipfire.org (Postfix) with ESMTPS id 4HXt9n31w7z2yC8 for ; Mon, 18 Oct 2021 10:18:05 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by mail01.ipfire.org (Postfix) with ESMTPSA id 4HXt9n1RHvz1Tw; Mon, 18 Oct 2021 10:18:05 +0000 (UTC) DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=ipfire.org; s=202003ed25519; t=1634552285; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=j9AUOwQR0Pm8L1ZqF7WH1AU21f1p+kcnpTSyLoZaAf0=; b=kRfFdJhsH/T/0+MZqZw7ugueA8EGKAvsJdlI/pa7xALkLO6W0LK+P6KQZqMeNFXj9Fgz5x ZJsSsLdGiMXAs+BA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ipfire.org; s=202003rsa; t=1634552285; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=j9AUOwQR0Pm8L1ZqF7WH1AU21f1p+kcnpTSyLoZaAf0=; b=b8SbGuAZuSnHiDlG/AuhE/qCjXu1xyCBoedLgEm0e3h+RHwlsU1nVVWXxtqD0Fn0gyeA6s cHfdxiKlGCCcA4S2zouvwjUeBBinNtMod0wUOzw4NTeQ3BJw3pIdwq/s/4pJxt8OzZ6/Lr nUi1ziY0NM+WOaB3VueG8CyWHuDk9BjUiuCB6rijmQbcVFE2aIAmm0jiGZQLJOZldb6hsG E2KuaAQgxieCARjrnPOkopkqi7127ZFEPUmQmL98/aRlDvTIhJ9F3gTfCn/8HVizTrceTz QPPxdW0bCyN5VIK9fQYojN+5h2hKTbR/fNFj0r7ZS+7JI9mQpCnWNxjr6+28AQ== From: Michael Tremer To: development@lists.ipfire.org Subject: [PATCH 8/9] suricata: Introduce IPSBYPASS chain Date: Mon, 18 Oct 2021 10:10:21 +0000 Message-Id: <20211018101022.15448-8-michael.tremer@ipfire.org> In-Reply-To: <20211018101022.15448-1-michael.tremer@ipfire.org> References: <20211018101022.15448-1-michael.tremer@ipfire.org> MIME-Version: 1.0 X-BeenThere: development@lists.ipfire.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: IPFire development talk List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Michael Tremer Errors-To: development-bounces@lists.ipfire.org Sender: "Development" NFQUEUE does not let the packet continue where it was processed, but inserts it back into iptables at the start. That is why we need an extra IPSBYPASS chain which has the following tasks: * Make the BYPASS bit permanent for the entire connection * Clear the REPEAT bit The latter is more of cosmetic nature so that we can identify packets that have come from suricata again and those which have bypassed the IPS straight away. The IPS_* chain will now only be sent traffic to, when none of the two relevant bits has been set. Otherwise the packet has already been processed by suricata in the first pass or suricata has decided to bypass the connection. This massively reduces load on the IPS which allows many common connections (TLS connections with downloads) to bypass the IPS bringing us back to line speed. Signed-off-by: Michael Tremer Tested-by: Stefan Schantl --- src/initscripts/system/firewall | 23 ++++++++++++++++++++--- src/initscripts/system/suricata | 27 +++------------------------ 2 files changed, 23 insertions(+), 27 deletions(-) diff --git a/src/initscripts/system/firewall b/src/initscripts/system/firewall index ce428393d..530e8f1d6 100644 --- a/src/initscripts/system/firewall +++ b/src/initscripts/system/firewall @@ -17,6 +17,11 @@ NAT_MASK="0x0f000000" IPSEC_MARK="0x00800000" IPSEC_MASK="${IPSEC_MARK}" +IPS_REPEAT_MARK="0x80000000" +IPS_REPEAT_MASK="0x80000000" +IPS_BYPASS_MARK="0x40000000" +IPS_BYPASS_MASK="0x40000000" + function iptables() { /sbin/iptables --wait "$@" } @@ -41,6 +46,17 @@ iptables_init() { modprobe nf_log_ipv4 sysctl -q -w net.netfilter.nf_log.2=nf_log_ipv4 + # IPS Bypass Chain which stores the BYPASS bit in connection tracking + iptables -N IPSBYPASS + iptables -A IPSBYPASS -j MARK --set-xmark "0/$(( IPS_REPEAT_MASK ))" + iptables -A IPSBYPASS -j CONNMARK --save-mark + + # Jump into bypass chain when the BYPASS bit is set + for chain in INPUT FORWARD OUTPUT; do + iptables -A "${chain}" -m mark \ + --mark "$(( IPS_REPEAT_MARK | IPS_BYPASS_MARK ))/$(( IPS_REPEAT_MASK | IPS_BYPASS_MASK ))" -j IPSBYPASS + done + # Empty LOG_DROP and LOG_REJECT chains iptables -N LOG_DROP iptables -A LOG_DROP -m limit --limit 10/second -j LOG @@ -147,9 +163,10 @@ iptables_init() { iptables -N IPS_INPUT iptables -N IPS_FORWARD iptables -N IPS_OUTPUT - iptables -A INPUT -j IPS_INPUT - iptables -A FORWARD -j IPS_FORWARD - iptables -A OUTPUT -j IPS_OUTPUT + + for chain in INPUT FORWARD OUTPUT; do + iptables -A "${chain}" -m mark --mark "0x0/$(( IPS_REPEAT_MASK | IPS_BYPASS_MASK ))" -j "IPS_${chain}" + done # OpenVPN transfer network translation iptables -t nat -N OVPNNAT diff --git a/src/initscripts/system/suricata b/src/initscripts/system/suricata index 72d01b91d..13fcc7f34 100644 --- a/src/initscripts/system/suricata +++ b/src/initscripts/system/suricata @@ -34,12 +34,6 @@ network_zones=( red green blue orange ovpn ) # Array to store the network zones weather the IPS is enabled for. enabled_ips_zones=() -# Mark and Mask options. -REPEAT_MARK="0x80000000" -REPEAT_MASK="0x80000000" -BYPASS_MARK="0x40000000" -BYPASS_MASK="0x40000000" - # PID file of suricata. PID_FILE="/var/run/suricata.pid" @@ -134,34 +128,19 @@ function generate_fw_rules { # Flush the firewall chains. flush_fw_chain - # Skip anything that has the bypass bit set - local chain - for chain in "${IPS_INPUT_CHAIN}" "${IPS_FORWARD_CHAIN}" "${IPS_OUTPUT_CHAIN}"; do - iptables -w -A "${chain}" -m mark --mark "${BYPASS_MARK}/${BYPASS_MASK}" -j RETURN - done - # Check if the array of enabled_ips_zones contains any elements. if [[ ${enabled_ips_zones[@]} ]]; then # Loop through the array and create firewall rules. for enabled_ips_zone in "${enabled_ips_zones[@]}"; do # Create rules queue input and output related traffic and pass it to the IPS. - iptables -w -A "$IPS_INPUT_CHAIN" -i "$enabled_ips_zone" -m mark ! --mark "${REPEAT_MARK}/${REPEAT_MASK}" -j NFQUEUE $NFQ_OPTIONS - iptables -w -A "$IPS_OUTPUT_CHAIN" -o "$enabled_ips_zone" -m mark ! --mark "${REPEAT_MARK}/${REPEAT_MASK}" -j NFQUEUE $NFQ_OPTIONS + iptables -w -A "$IPS_INPUT_CHAIN" -i "$enabled_ips_zone" -j NFQUEUE $NFQ_OPTIONS + iptables -w -A "$IPS_OUTPUT_CHAIN" -o "$enabled_ips_zone" -j NFQUEUE $NFQ_OPTIONS # Create rules which are required to handle forwarded traffic. for enabled_ips_zone_forward in "${enabled_ips_zones[@]}"; do - iptables -w -A "$IPS_FORWARD_CHAIN" -i "$enabled_ips_zone" -o "$enabled_ips_zone_forward" -m mark ! --mark "${REPEAT_MARK}/${REPEAT_MASK}" -j NFQUEUE $NFQ_OPTIONS + iptables -w -A "$IPS_FORWARD_CHAIN" -i "$enabled_ips_zone" -o "$enabled_ips_zone_forward" -j NFQUEUE $NFQ_OPTIONS done done - - # Add common rules at the end of the chain - for chain in "${IPS_INPUT_CHAIN}" "${IPS_FORWARD_CHAIN}" "${IPS_OUTPUT_CHAIN}"; do - # Clear repeat bit - iptables -w -A "${chain}" -j MARK --set-xmark "0x0/${REPEAT_MASK}" - - # Store bypass bit in CONNMARK - iptables -w -A "${chain}" -m mark --mark "${BYPASS_MARK}/${BYPASS_MASK}" -j CONNMARK --save-mark - done fi }