diff --git a/src/initscripts/system/firewall b/src/initscripts/system/firewall
index 6727e4a20..39d9c0f23 100644
--- a/src/initscripts/system/firewall
+++ b/src/initscripts/system/firewall
@@ -39,11 +39,6 @@ fi
 
 NAT_MASK="0x0f000000"
 
-IPS_REPEAT_MARK="0x80000000"
-IPS_REPEAT_MASK="0x80000000"
-IPS_BYPASS_MARK="0x40000000"
-IPS_BYPASS_MASK="0x40000000"
-
 IPSET_DB_DIR="/var/lib/location/ipset"
 
 SYNPROXY_OPTIONS=(
@@ -84,16 +79,6 @@ 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 CONNMARK --save-mark --mask "$(( ~IPS_REPEAT_MASK & 0xffffffff ))"
-
-	# 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
@@ -237,12 +222,10 @@ iptables_init() {
 	iptables -A FORWARD -o tun+ -j OVPNBLOCK
 
 	# IPS (Suricata) chains
-	iptables -N IPS_INPUT
-	iptables -N IPS_FORWARD
-	iptables -N IPS_OUTPUT
+	iptables -t mangle -N IPS
 
-	for chain in INPUT FORWARD OUTPUT; do
-		iptables -A "${chain}" -m mark --mark "0x0/$(( IPS_REPEAT_MASK | IPS_BYPASS_MASK ))" -j "IPS_${chain}"
+	for chain in PREROUTING POSTROUTING; do
+		iptables -t mangle -A "${chain}" -j IPS
 	done
 
 	# OpenVPN transfer network translation
diff --git a/src/initscripts/system/suricata b/src/initscripts/system/suricata
index 79f9478c3..253ece117 100644
--- a/src/initscripts/system/suricata
+++ b/src/initscripts/system/suricata
@@ -27,13 +27,20 @@ PATH=/usr/local/sbin:/usr/local/bin:/bin:/usr/bin:/sbin:/usr/sbin; export PATH
 eval $(/usr/local/bin/readhash /var/ipfire/suricata/settings)
 eval $(/usr/local/bin/readhash /var/ipfire/ethernet/settings)
 
+IPS_REPEAT_MARK="0x80000000"
+IPS_REPEAT_MASK="0x80000000"
+IPS_BYPASS_MARK="0x40000000"
+IPS_BYPASS_MASK="0x40000000"
+
 # Name of the firewall chains.
 IPS_INPUT_CHAIN="IPS_INPUT"
 IPS_FORWARD_CHAIN="IPS_FORWARD"
 IPS_OUTPUT_CHAIN="IPS_OUTPUT"
 
 # Optional options for the Netfilter queue.
-NFQ_OPTS="--queue-bypass "
+NFQ_OPTS=(
+	"--queue-bypass"
+)
 
 # Array containing the 4 possible network zones.
 network_zones=( red green blue orange ovpn )
@@ -64,91 +71,48 @@ function get_cpu_count {
 
 # Function to flush the firewall chains.
 function flush_fw_chain {
-	# Call iptables and flush the chains
-	iptables -w -F "$IPS_INPUT_CHAIN"
-	iptables -w -F "$IPS_FORWARD_CHAIN"
-	iptables -w -F "$IPS_OUTPUT_CHAIN"
+	iptables -w -t mangle -F IPS
 }
 
 # Function to create the firewall rules to pass the traffic to suricata.
 function generate_fw_rules {
-	cpu_count=$(get_cpu_count)
-
-	# Loop through the array of network zones.
-	for zone in "${network_zones[@]}"; do
-		# Convert zone into upper case.
-		zone_upper=${zone^^}
-
-		# Generate variable name for checking if the IDS is
-		# enabled on the zone.
-		enable_ids_zone="ENABLE_IDS_$zone_upper"
-
-		# Check if the IDS is enabled for this network zone.
-		if [ "${!enable_ids_zone}" == "on" ]; then
-			# Check if the current processed zone is "red" and the configured type is PPPoE dialin.
-			if [ "$zone" == "red" ] && [ "$RED_TYPE" == "PPPOE" ] && [ "$RED_DRIVER" != "qmi_wwan" ]; then
-				# Set device name to ppp0.
-				network_device="ppp0"
-			elif [ "$zone" == "ovpn" ]; then
-				# Get all virtual net devices because the RW server and each
-				# N2N connection creates it's own tun device.
-				for virt_dev in /sys/devices/virtual/net/*; do
-					# Cut-off the directory.
-					dev="${virt_dev##*/}"
-
-					# Only process tun devices.
-					if [[ $dev =~ "tun" ]]; then
-						# Add the network device to the array of enabled zones.
-						enabled_ips_zones+=( "$dev" )
-					fi
-				done
-
-				# Process next zone.
-				continue
-			else
-				# Generate variable name which contains the device name.
-				zone_name="$zone_upper"
-				zone_name+="_DEV"
-
-				# Grab device name.
-				network_device=${!zone_name}
-			fi
-
-			# Add the network device to the array of enabled zones.
-			enabled_ips_zones+=( "$network_device" )
-		fi
-	done
-
 	# Assign NFQ_OPTS
-	NFQ_OPTIONS=$NFQ_OPTS
+	local NFQ_OPTIONS=( "${NFQ_OPTS[@]}" )
+
+	local cpu_count="$(get_cpu_count)"
 
 	# 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))"
-		NFQ_OPTIONS+=" --queue-cpu-fanout"
+		# 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"
+		# Send all packets to queue 0
+		NFQ_OPTIONS+=(
+			"--queue-num" "0"
+		)
 	fi
 
 	# Flush the firewall chains.
 	flush_fw_chain
 
-	# 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" -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" -j NFQUEUE $NFQ_OPTIONS
-			done
-		done
-	fi
+	# 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
+
+	# 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
+
+	# Send packets to suricata
+	iptables -w -t mangle -A IPS -j NFQUEUE "${NFQ_OPTIONS[@]}"
+
+	# 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_MARK ))/$(( IPS_BYPASS_MASK ))" \
+		-j CONNMARK --save-mark --mask "$(( IPS_BYPASS_MASK ))"
+
+	return 0
 }
 
 case "$1" in
