#!/bin/sh ############################################################################### # # # IPFire.org - A linux based firewall # # Copyright (C) 2007-2022 IPFire Team # # # # This program is free software: you can redistribute it and/or modify # # it under the terms of the GNU General Public License as published by # # the Free Software Foundation, either version 3 of the License, or # # (at your option) any later version. # # # # This program is distributed in the hope that it will be useful, # # but WITHOUT ANY WARRANTY; without even the implied warranty of # # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # # GNU General Public License for more details. # # # # You should have received a copy of the GNU General Public License # # along with this program. If not, see . # # # ############################################################################### . /etc/sysconfig/rc . ${rc_functions} . /etc/init.d/networking/functions.network eval $(/usr/local/bin/readhash /var/ipfire/suricata/settings) IPS_REPEAT_MARK="0x80000000" IPS_REPEAT_MASK="0x80000000" # The IPS requested that this connection is being bypassed IPS_BYPASS_REQUESTED_MARK="0x40000000" IPS_BYPASS_REQUESTED_MASK="0x40000000" # Marks a connection to be bypassed IPS_BYPASS_MARK="0x20000000" IPS_BYPASS_MASK="0x20000000" # Set if we request to scan this packet IPS_SCAN_MARK="0x10000000" IPS_SCAN_MASK="0x10000000" # Supported network zones NETWORK_ZONES=( "RED" "GREEN" "ORANGE" "BLUE" "WG" "OVPN" ) # Optional options for the Netfilter queue. NFQ_OPTS=( "--queue-bypass" ) # Function to flush the firewall chains. flush_fw_chain() { iptables -w -t mangle -F IPS } # Function to create the firewall rules to pass the traffic to suricata. generate_fw_rules() { # Assign NFQ_OPTS local NFQ_OPTIONS=( "${NFQ_OPTS[@]}" ) local cpu_count="$(getconf _NPROCESSORS_ONLN)" # Check if there are multiple cpu cores available. if [ "$cpu_count" -gt "1" ]; then # Balance beetween all queues NFQ_OPTIONS+=( "--queue-balance" "0:$(($cpu_count-1))" "--queue-cpu-fanout" ) else # Send all packets to queue 0 NFQ_OPTIONS+=( "--queue-num" "0" ) fi # Flush the firewall chains. flush_fw_chain # Don't process packets where the IPS has requested to bypass the stream iptables -w -t mangle -A IPS -m mark --mark "$(( IPS_BYPASS_MARK ))/$(( IPS_BYPASS_MASK ))" -j RETURN # If suricata decided to bypass a stream, we will store the mark in the connection tracking table iptables -w -t mangle -A IPS \ -m mark --mark "$(( IPS_BYPASS_REQUESTED_MARK ))/$(( IPS_BYPASS_REQUESTED_MASK ))" \ -j CONNMARK --set-mark "$(( IPS_BYPASS_MARK ))/$(( IPS_BYPASS_MASK ))" # Don't process packets that have already been seen by the IPS iptables -w -t mangle -A IPS -m mark --mark "$(( IPS_REPEAT_MARK ))/$(( IPS_REPEAT_MASK ))" -j RETURN local zone local status local intf # Mark packets for all zones that we want to scan for zone in "${NETWORK_ZONES[@]}"; do status="ENABLE_IDS_${zone}" if [ "${!status}" = "on" ]; then intf="$(network_get_intf "${zone}")" # Skip if we could not determine an interface if [ -z "${intf}" ]; then continue fi iptables -w -t mangle -A IPS -i "${intf}" -j MARK --set-mark "$(( IPS_SCAN_MARK ))/$(( IPS_SCAN_MASK ))" iptables -w -t mangle -A IPS -o "${intf}" -j MARK --set-mark "$(( IPS_SCAN_MARK ))/$(( IPS_SCAN_MASK ))" fi done # Don't keep processing packets we don't want to scan iptables -w -t mangle -A IPS -m mark ! --mark "$(( IPS_SCAN_MARK ))/$(( IPS_SCAN_MASK ))" -j RETURN # Never send any whitelisted packets to the IPS if [ -r "/var/ipfire/suricata/ignored" ]; then local id network remark enabled rest while IFS=',' read -r id network remark enabled rest; do echo "$network" echo "$remark" # Skip disabled entries [ "${enabled}" = "enabled" ] || continue iptables -w -t mangle -A IPS -s "${network}" -j RETURN iptables -w -t mangle -A IPS -d "${network}" -j RETURN done < "/var/ipfire/suricata/ignored" fi # Send packets to suricata iptables -w -t mangle -A IPS -j NFQUEUE "${NFQ_OPTIONS[@]}" return 0 } case "$1" in start) # Get amount of CPU cores cpu_count="$(getconf _NPROCESSORS_ONLN)" # Numer of NFQUES. NFQUEUES="-q 0" if [ $cpu_count -gt "1" ]; then NFQUEUES+=":$(($cpu_count-1))" fi # Check if the IDS should be started. if [ "$ENABLE_IDS" == "on" ]; then # Start the IDS. boot_mesg "Starting Intrusion Detection System..." loadproc -b /usr/bin/suricata-watcher -c /etc/suricata/suricata.yaml $NFQUEUES # Flush the firewall chain flush_fw_chain # Generate firewall rules generate_fw_rules fi ;; stop) boot_mesg "Stopping Intrusion Detection System..." killproc /usr/bin/suricata # Flush firewall chain. flush_fw_chain # Don't report returncode of rm if suricata was not started exit 0 ;; status) statusproc /usr/bin/suricata ;; restart) $0 stop $0 start ;; reload) # Send SIGUSR2 to the suricata process to perform a reload # of the ruleset. kill -USR2 $(pidof suricata) # Flush the firewall chain. flush_fw_chain # Generate firewall rules. generate_fw_rules ;; *) echo "Usage: $0 {start|stop|restart|reload|status}" exit 1 ;; esac