public inbox for ipfire-scm@lists.ipfire.org
 help / color / mirror / Atom feed
* [git.ipfire.org] IPFire 2.x development tree branch, master, updated. 84b04cb6d38eb0ca0fca426e4d6e0c0a2c467d9e
@ 2024-09-24  8:54 Michael Tremer
  0 siblings, 0 replies; only message in thread
From: Michael Tremer @ 2024-09-24  8:54 UTC (permalink / raw)
  To: ipfire-scm

[-- Attachment #1: Type: text/plain, Size: 97315 bytes --]

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "IPFire 2.x development tree".

The branch, master has been updated
       via  84b04cb6d38eb0ca0fca426e4d6e0c0a2c467d9e (commit)
       via  d99826dc71146a6d019341892d6f2d7b69ee2407 (commit)
       via  e5da7dea66167602b9255ac6b77d9ab32398a23d (commit)
       via  db151ad716beefcb9ab9fadd2bb3ac9934748793 (commit)
       via  09831e9ca9c27b024d305f40655298d8106cdf5c (commit)
       via  75a89ddf4aaccaf397e320a98bf1ecf65c78cff4 (commit)
       via  6826eed0a4a892bf6ef24abd312bad474568c988 (commit)
       via  4efa4c4b714f117cb561201f7f6c122cb7da624a (commit)
       via  0c5a683b7ed3cb268648c573bcbeead20f824e95 (commit)
       via  d98d10f7df7bd8715b338c6c3b30801f65243977 (commit)
       via  cf44d8d149dbda8aa8dccd89dd5e3ff75af628b9 (commit)
       via  5da15c5d3b1772f133d10a309d99b3588b98be0f (commit)
       via  4721fac3c88069d5ca426f6be750f9b860efecaa (commit)
       via  a85924cc2534c65eb10b800375ade8a5bb311dc1 (commit)
       via  8b73307b15a74b3e0781cfb3430298403e849ed6 (commit)
       via  63f4b3a7bc4bd80b036c02f2483fd82ac5810aca (commit)
       via  0d38ebeb059cca9f97316f4980ee4437110ddf55 (commit)
       via  525ff6d74dac833854dde69a152e98f1b5fd14d2 (commit)
       via  2438c6c2497015e92e823ecd2fbe9071a2cda575 (commit)
       via  d3db0465703fe15855b02c3487859c8ca5a0db2b (commit)
       via  d2f7d18e338975fa5d6a6f89b3eb86378e124612 (commit)
       via  891702cad16def266ab4ab1e8dde79367dd3d140 (commit)
       via  119cb837067ab16f6bf6ea88f512f8f8c38ea49c (commit)
       via  50f3e2a534d99ad4606535709e02f40ac89260fd (commit)
       via  1b7d1abdf0978be4dfd57f339313ce811322aaf9 (commit)
       via  72d501f9235e290c974b2e4207b822b164d3a2fc (commit)
       via  eb3156ed6b4a1de646259295db47c6cbeaa438ae (commit)
       via  79cce701a94fb903e94838faf4c2e1016a24ba62 (commit)
       via  7e1c564ec8f25cb00c49a5ceecdb004c0b186555 (commit)
       via  17887e69a82dc92880136940ccdff1254c612233 (commit)
       via  e088c2115843cb6d70ea5bc21af818f5dbd7e822 (commit)
       via  54a58a2891910ece5174ec8f20504ae2f80841e2 (commit)
       via  84a73d5f3997be2f1907c5eb4ad7a7069611ab4a (commit)
       via  655a95803a2fdc16ed7541b0c368620bb23d7740 (commit)
       via  50d987cc2194945be50030fde179e293f692135d (commit)
       via  7e5ec5699886664686d05ef3d7dc3006d162b5a7 (commit)
       via  558dcc66e632fe12b566edc4e39c519cdbc1b6a0 (commit)
      from  fc1537434f007977161c2ba46b823d276b8c5d7c (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 84b04cb6d38eb0ca0fca426e4d6e0c0a2c467d9e
Author: Michael Tremer <michael.tremer(a)ipfire.org>
Date:   Tue Sep 24 08:53:40 2024 +0000

    core189: Ship suricata changes
    
    Signed-off-by: Michael Tremer <michael.tremer(a)ipfire.org>

commit d99826dc71146a6d019341892d6f2d7b69ee2407
Author: Michael Tremer <michael.tremer(a)ipfire.org>
Date:   Tue Sep 24 10:33:22 2024 +0200

    suricata: Enable scanning IPsec packets
    
    Signed-off-by: Michael Tremer <michael.tremer(a)ipfire.org>

commit e5da7dea66167602b9255ac6b77d9ab32398a23d
Author: Michael Tremer <michael.tremer(a)ipfire.org>
Date:   Sun Sep 22 17:22:48 2024 +0200

    ids.cgi: Add UI to enable scanning on IPsec
    
    Signed-off-by: Michael Tremer <michael.tremer(a)ipfire.org>

commit db151ad716beefcb9ab9fadd2bb3ac9934748793
Author: Michael Tremer <michael.tremer(a)ipfire.org>
Date:   Sun Sep 22 17:08:03 2024 +0200

    suricata: Add support for zones having multiple interfaces
    
    Signed-off-by: Michael Tremer <michael.tremer(a)ipfire.org>

commit 09831e9ca9c27b024d305f40655298d8106cdf5c
Author: Michael Tremer <michael.tremer(a)ipfire.org>
Date:   Sun Sep 22 17:06:21 2024 +0200

    suricata: Split marking packets off into a separate chain
    
    This is required so that we can have different policies for incoming and
    outgoing packets.
    
    Signed-off-by: Michael Tremer <michael.tremer(a)ipfire.org>

commit 75a89ddf4aaccaf397e320a98bf1ecf65c78cff4
Author: Michael Tremer <michael.tremer(a)ipfire.org>
Date:   Sat Sep 21 17:55:09 2024 +0200

    suricata: Clear IPS bits after use
    
    Signed-off-by: Michael Tremer <michael.tremer(a)ipfire.org>

commit 6826eed0a4a892bf6ef24abd312bad474568c988
Author: Michael Tremer <michael.tremer(a)ipfire.org>
Date:   Sat Sep 21 12:39:32 2024 +0200

    suricata: Always count the whitelisted packets
    
    Even if there are no rules, if this does not exist, collectd will be
    unhappy and we cannot generate the graph.
    
    Signed-off-by: Michael Tremer <michael.tremer(a)ipfire.org>

commit 4efa4c4b714f117cb561201f7f6c122cb7da624a
Author: Michael Tremer <michael.tremer(a)ipfire.org>
Date:   Sat Sep 21 12:37:09 2024 +0200

    ids.cgi: Don't show the graph if there is no RRD data
    
    Signed-off-by: Michael Tremer <michael.tremer(a)ipfire.org>

commit 0c5a683b7ed3cb268648c573bcbeead20f824e95
Author: Michael Tremer <michael.tremer(a)ipfire.org>
Date:   Sat Sep 21 12:34:56 2024 +0200

    ids.cgi: Fix empty states of tables
    
    Signed-off-by: Michael Tremer <michael.tremer(a)ipfire.org>

commit d98d10f7df7bd8715b338c6c3b30801f65243977
Author: Michael Tremer <michael.tremer(a)ipfire.org>
Date:   Sat Sep 21 12:28:50 2024 +0200

    graphs.pl: Fix suricata graph name
    
    Signed-off-by: Michael Tremer <michael.tremer(a)ipfire.org>

commit cf44d8d149dbda8aa8dccd89dd5e3ff75af628b9
Author: Michael Tremer <michael.tremer(a)ipfire.org>
Date:   Tue Sep 17 04:04:07 2024 +0200

    firewall: Move the IPS back to INPUT/FORWARD/OUTPUT
    
    We cannot use the PREROUTING/POSTROUTING chains here because Suricata
    will fail to track NAT-ed connections.
    
    Signed-off-by: Michael Tremer <michael.tremer(a)ipfire.org>

commit 5da15c5d3b1772f133d10a309d99b3588b98be0f
Author: Michael Tremer <michael.tremer(a)ipfire.org>
Date:   Fri Sep 13 10:12:30 2024 +0200

    suricata: Track whitelisted traffic and add it to the IPS graph
    
    Signed-off-by: Michael Tremer <michael.tremer(a)ipfire.org>

commit 4721fac3c88069d5ca426f6be750f9b860efecaa
Author: Michael Tremer <michael.tremer(a)ipfire.org>
Date:   Wed Sep 11 00:43:59 2024 +0200

    IPS: Ada a graph that shows the IPS throughput
    
    This graph is split into three parts. One shows bypassed packets, the
    next one shows the actually scanned packets and lastly we show the total
    throughput.
    
    Signed-off-by: Michael Tremer <michael.tremer(a)ipfire.org>

commit a85924cc2534c65eb10b800375ade8a5bb311dc1
Author: Michael Tremer <michael.tremer(a)ipfire.org>
Date:   Tue Sep 10 23:45:53 2024 +0200

    suricata: Collect metrics on scanned and bypassed packets
    
    Signed-off-by: Michael Tremer <michael.tremer(a)ipfire.org>

commit 8b73307b15a74b3e0781cfb3430298403e849ed6
Author: Michael Tremer <michael.tremer(a)ipfire.org>
Date:   Tue Sep 10 23:23:38 2024 +0200

    suricata: Force Suricata to write a PID file again
    
    The PID file does not get written when Suricata is not being started in
    daemon mode and therefore we need to pass it as a command line
    parameter.
    
    The initscript should not deal with the PID file when starting but needs
    it to terminate the process and to check the process status.
    
    The web UI can use the PID file again.
    
    Signed-off-by: Michael Tremer <michael.tremer(a)ipfire.org>

commit 63f4b3a7bc4bd80b036c02f2483fd82ac5810aca
Author: Michael Tremer <michael.tremer(a)ipfire.org>
Date:   Tue Sep 10 23:23:18 2024 +0200

    suricata: Fix syntax error in watcher script
    
    Signed-off-by: Michael Tremer <michael.tremer(a)ipfire.org>

commit 0d38ebeb059cca9f97316f4980ee4437110ddf55
Author: Michael Tremer <michael.tremer(a)ipfire.org>
Date:   Tue Sep 10 23:17:20 2024 +0200

    suricata: Remove debugging code
    
    Signed-off-by: Michael Tremer <michael.tremer(a)ipfire.org>

commit 525ff6d74dac833854dde69a152e98f1b5fd14d2
Author: Michael Tremer <michael.tremer(a)ipfire.org>
Date:   Tue Sep 10 11:37:38 2024 +0200

    firewall: Move the IPS after the NAT marking
    
    This is because we might still land in the scenario where Suricata
    crashes and NFQUEUE will simply ACCEPT all packets which will terminate
    the processing of the mangle table.
    
    Therefore the NFQUEUE rule should be the last one so that we never skip
    any of the other processing.
    
    Signed-off-by: Michael Tremer <michael.tremer(a)ipfire.org>

commit 2438c6c2497015e92e823ecd2fbe9071a2cda575
Author: Michael Tremer <michael.tremer(a)ipfire.org>
Date:   Tue Sep 10 11:35:18 2024 +0200

    ids.cgi: Fix detection for the Suricata process
    
    We don't seem to have a PID file any more.
    
    Signed-off-by: Michael Tremer <michael.tremer(a)ipfire.org>

commit d3db0465703fe15855b02c3487859c8ca5a0db2b
Author: Michael Tremer <michael.tremer(a)ipfire.org>
Date:   Tue Sep 10 11:24:01 2024 +0200

    ids.cgi: Remove box from the top section
    
    Signed-off-by: Michael Tremer <michael.tremer(a)ipfire.org>

commit d2f7d18e338975fa5d6a6f89b3eb86378e124612
Author: Michael Tremer <michael.tremer(a)ipfire.org>
Date:   Tue Sep 10 11:22:59 2024 +0200

    ids.cgi: Sort whitelist entries
    
    Signed-off-by: Michael Tremer <michael.tremer(a)ipfire.org>

commit 891702cad16def266ab4ab1e8dde79367dd3d140
Author: Michael Tremer <michael.tremer(a)ipfire.org>
Date:   Tue Sep 10 11:17:33 2024 +0200

    ids.cgi: Use new-style table for whitelist entries
    
    Signed-off-by: Michael Tremer <michael.tremer(a)ipfire.org>

commit 119cb837067ab16f6bf6ea88f512f8f8c38ea49c
Author: Michael Tremer <michael.tremer(a)ipfire.org>
Date:   Tue Sep 10 11:09:58 2024 +0200

    ids.cgi: Use new style tables for rulesets
    
    Signed-off-by: Michael Tremer <michael.tremer(a)ipfire.org>

commit 50f3e2a534d99ad4606535709e02f40ac89260fd
Author: Michael Tremer <michael.tremer(a)ipfire.org>
Date:   Tue Sep 10 11:01:52 2024 +0200

    suricata: Fix broken spacing in the settings section
    
    Signed-off-by: Michael Tremer <michael.tremer(a)ipfire.org>

commit 1b7d1abdf0978be4dfd57f339313ce811322aaf9
Author: Michael Tremer <michael.tremer(a)ipfire.org>
Date:   Tue Sep 10 10:50:15 2024 +0200

    suricata: Add option to scan WireGuard
    
    Signed-off-by: Michael Tremer <michael.tremer(a)ipfire.org>

commit 72d501f9235e290c974b2e4207b822b164d3a2fc
Author: Michael Tremer <michael.tremer(a)ipfire.org>
Date:   Tue Sep 10 10:42:11 2024 +0200

    suricata: Don't load /var/ipfire/ethernet/settings
    
    We no longer need this directly as it is being pulled in from the
    network functions.
    
    Signed-off-by: Michael Tremer <michael.tremer(a)ipfire.org>

commit eb3156ed6b4a1de646259295db47c6cbeaa438ae
Author: Michael Tremer <michael.tremer(a)ipfire.org>
Date:   Tue Sep 10 10:41:19 2024 +0200

    suricata: Remove superfluous bits from the initscript
    
    I don't know why these hacks are here.
    
    Signed-off-by: Michael Tremer <michael.tremer(a)ipfire.org>

commit 79cce701a94fb903e94838faf4c2e1016a24ba62
Author: Michael Tremer <michael.tremer(a)ipfire.org>
Date:   Tue Sep 10 10:40:28 2024 +0200

    suricata: Restore the interface selection
    
    Signed-off-by: Michael Tremer <michael.tremer(a)ipfire.org>

commit 7e1c564ec8f25cb00c49a5ceecdb004c0b186555
Author: Michael Tremer <michael.tremer(a)ipfire.org>
Date:   Mon Sep 9 23:08:11 2024 +0200

    suricata: Start the new watcher in the background
    
    Signed-off-by: Michael Tremer <michael.tremer(a)ipfire.org>

commit 17887e69a82dc92880136940ccdff1254c612233
Author: Michael Tremer <michael.tremer(a)ipfire.org>
Date:   Mon Sep 9 20:09:22 2024 +0200

    suricata: Add a watcher to restart on unexpected termination
    
    This patch adds a watcher process that will restart suricata when it is
    being killed by SIGKILL (e.g. by the OOM killer) or after a SEGV.
    
    Signed-off-by: Michael Tremer <michael.tremer(a)ipfire.org>

commit e088c2115843cb6d70ea5bc21af818f5dbd7e822
Author: Michael Tremer <michael.tremer(a)ipfire.org>
Date:   Mon Sep 9 19:38:47 2024 +0200

    suricata: Be more efficient with marks
    
    This patch changes that we introduce a new mark which allows us to
    identify any newly bypassed connections and permanently store the bypass
    flag.
    
    We also only restore marks from the connection tracking when a packet
    has no marks, yet.
    
    Tested-by: Adolf Belka <adolf.belka(a)ipfire.org>
    Signed-off-by: Michael Tremer <michael.tremer(a)ipfire.org>

commit 54a58a2891910ece5174ec8f20504ae2f80841e2
Author: Michael Tremer <michael.tremer(a)ipfire.org>
Date:   Mon Sep 9 19:37:56 2024 +0200

    suricata: Replace removed CPU count function
    
    Signed-off-by: Michael Tremer <michael.tremer(a)ipfire.org>

commit 84a73d5f3997be2f1907c5eb4ad7a7069611ab4a
Author: Michael Tremer <michael.tremer(a)ipfire.org>
Date:   Mon Sep 9 12:46:23 2024 +0200

    suricata: Add whitelist to iptables
    
    This allows us to workaround better against any problems in Suricata
    because we never send any whitelisted packets to the IPS in the first
    place.
    
    Signed-off-by: Michael Tremer <michael.tremer(a)ipfire.org>

commit 655a95803a2fdc16ed7541b0c368620bb23d7740
Author: Michael Tremer <michael.tremer(a)ipfire.org>
Date:   Mon Sep 9 11:58:50 2024 +0200

    suricata: Remove some unused constants
    
    Signed-off-by: Michael Tremer <michael.tremer(a)ipfire.org>

commit 50d987cc2194945be50030fde179e293f692135d
Author: Michael Tremer <michael.tremer(a)ipfire.org>
Date:   Mon Sep 9 11:55:34 2024 +0200

    suricata: Use getconf to determine the number of processors
    
    Signed-off-by: Michael Tremer <michael.tremer(a)ipfire.org>

commit 7e5ec5699886664686d05ef3d7dc3006d162b5a7
Author: Michael Tremer <michael.tremer(a)ipfire.org>
Date:   Mon Sep 9 11:54:04 2024 +0200

    initscripts: Fix bash function definitions in suricata
    
    Signed-off-by: Michael Tremer <michael.tremer(a)ipfire.org>

commit 558dcc66e632fe12b566edc4e39c519cdbc1b6a0
Author: Michael Tremer <michael.tremer(a)ipfire.org>
Date:   Mon Sep 9 11:49:30 2024 +0200

    suricata: Move the IPS into the mangle table
    
    This should make the IPS more efficient, we should have fewer rules and
    the IPS will now sit at the edge of the networking stack as it will see
    packets immediately when they come and and just before they leave.
    
    Signed-off-by: Michael Tremer <michael.tremer(a)ipfire.org>

-----------------------------------------------------------------------

Summary of changes:
 config/cfgroot/graphs.pl                           |  87 ++++++++
 config/collectd/collectd.conf                      |   5 +
 config/rootfiles/common/suricata                   |   1 +
 config/rootfiles/core/189/filelists/files          |   8 +
 config/rootfiles/core/189/update.sh                |   1 +
 .../execute.sh => config/suricata/suricata-watcher |  45 +++-
 doc/language_issues.de                             |   1 +
 doc/language_issues.en                             |   8 +-
 doc/language_issues.es                             |   8 +
 doc/language_issues.fr                             |   8 +
 doc/language_issues.it                             |   8 +-
 doc/language_issues.nl                             |   8 +-
 doc/language_issues.pl                             |   8 +-
 doc/language_issues.ru                             |   8 +-
 doc/language_issues.tr                             |   8 +-
 doc/language_missings                              |  57 +++++
 html/cgi-bin/getrrdimage.cgi                       |  10 +-
 html/cgi-bin/ids.cgi                               | 145 +++++++------
 langs/de/cgi-bin/de.pl                             |   7 +
 langs/en/cgi-bin/en.pl                             |   8 +
 lfs/suricata                                       |   3 +
 src/initscripts/networking/functions.network       |  80 +++++++
 src/initscripts/system/firewall                    |  42 ++--
 src/initscripts/system/suricata                    | 240 ++++++++++-----------
 24 files changed, 572 insertions(+), 232 deletions(-)
 copy tools/execute.sh => config/suricata/suricata-watcher (68%)
 mode change 100755 => 100644

Difference in files:
diff --git a/config/cfgroot/graphs.pl b/config/cfgroot/graphs.pl
index 2439c5bf6..f07214cf8 100644
--- a/config/cfgroot/graphs.pl
+++ b/config/cfgroot/graphs.pl
@@ -1189,3 +1189,90 @@ sub updateconntrackgraph {
 
 	return "Error in RRD::Graph for conntrack: " . $ERROR . "\n" if $ERROR;
 }
+
+sub updateipsthroughputgraph {
+	my $period = $_[0];
+
+	my @command = (
+		@GRAPH_ARGS,
+		"-",
+		"--start",
+		"-1" . $period,
+		"-r",
+		"--lower-limit","0",
+		"-v $Lang::tr{'bytes per second'}",
+		"--color=BACK" . $color{"color21"},
+
+		# Read bypassed packets
+		"DEF:bypassed_bytes=$mainsettings{'RRDLOG'}/collectd/localhost/iptables-mangle-IPS/ipt_bytes-BYPASSED.rrd:value:AVERAGE",
+		#"DEF:bypassed_packets=$mainsettings{'RRDLOG'}/collectd/localhost/iptables-mangle-IPS/ipt_packets-BYPASSED.rrd:value:AVERAGE",
+
+		"VDEF:bypassed_bytes_avg=bypassed_bytes,AVERAGE",
+		"VDEF:bypassed_bytes_min=bypassed_bytes,MINIMUM",
+		"VDEF:bypassed_bytes_max=bypassed_bytes,MAXIMUM",
+
+		# Read scanned packets
+		"DEF:scanned_bytes=$mainsettings{'RRDLOG'}/collectd/localhost/iptables-mangle-IPS/ipt_bytes-SCANNED.rrd:value:AVERAGE",
+		#"DEF:scanned_packets=$mainsettings{'RRDLOG'}/collectd/localhost/iptables-mangle-IPS/ipt_packets-SCANNED.rrd:value:AVERAGE",
+
+		"VDEF:scanned_bytes_avg=scanned_bytes,AVERAGE",
+		"VDEF:scanned_bytes_min=scanned_bytes,MINIMUM",
+		"VDEF:scanned_bytes_max=scanned_bytes,MAXIMUM",
+
+		# Read whitelisted packets
+		"DEF:whitelisted_bytes=$mainsettings{'RRDLOG'}/collectd/localhost/iptables-mangle-IPS/ipt_bytes-WHITELISTED.rrd:value:AVERAGE",
+		#"DEF:whitelisted_packets=$mainsettings{'RRDLOG'}/collectd/localhost/iptables-mangle-IPS/ipt_packets-WHITELISTED.rrd:value:AVERAGE",
+
+		"VDEF:whitelisted_bytes_avg=whitelisted_bytes,AVERAGE",
+		"VDEF:whitelisted_bytes_min=whitelisted_bytes,MINIMUM",
+		"VDEF:whitelisted_bytes_max=whitelisted_bytes,MAXIMUM",
+
+		# Total
+		"CDEF:total_bytes=bypassed_bytes,scanned_bytes,ADDNAN,whitelisted_bytes,ADDNAN",
+		#"CDEF:total_packets=bypassed_packets,scanned_packets,ADDNAN,whitelisted_packets,ADDNAN",
+
+		"VDEF:total_bytes_avg=total_bytes,AVERAGE",
+		"VDEF:total_bytes_min=total_bytes,MINIMUM",
+		"VDEF:total_bytes_max=total_bytes,MAXIMUM",
+
+		# Add some space below the graph
+		"COMMENT: \\n",
+
+		# Headline
+		"COMMENT:" . sprintf("%32s", ""),
+		"COMMENT:" . sprintf("%16s", $Lang::tr{'average'}),
+		"COMMENT:" . sprintf("%16s", $Lang::tr{'minimum'}),
+		"COMMENT:" . sprintf("%16s", $Lang::tr{'maximum'}) . "\\j",
+
+		# Whitelisted Packets
+		"AREA:whitelisted_bytes$color{'color12'}A0:" . sprintf("%-30s", $Lang::tr{'whitelisted'}),
+		"GPRINT:whitelisted_bytes_avg:%9.2lf %sbps",
+		"GPRINT:whitelisted_bytes_min:%9.2lf %sbps",
+		"GPRINT:whitelisted_bytes_max:%9.2lf %sbps\\j",
+
+		# Bypassed Packets
+		"STACK:bypassed_bytes$color{'color11'}A0:" . sprintf("%-30s", $Lang::tr{'bypassed'}),
+		"GPRINT:bypassed_bytes_avg:%9.2lf %sbps",
+		"GPRINT:bypassed_bytes_min:%9.2lf %sbps",
+		"GPRINT:bypassed_bytes_max:%9.2lf %sbps\\j",
+
+		# Scanned Packets
+		"STACK:scanned_bytes$color{'color13'}A0:" . sprintf("%-30s", $Lang::tr{'scanned'}),
+		"GPRINT:scanned_bytes_avg:%9.2lf %sbps",
+		"GPRINT:scanned_bytes_min:%9.2lf %sbps",
+		"GPRINT:scanned_bytes_max:%9.2lf %sbps\\j",
+
+		"COMMENT: \\n",
+
+		# Total Packets
+		"COMMENT:" . sprintf("%-32s", $Lang::tr{'total'}),
+		"GPRINT:total_bytes_avg:%9.2lf %sbps",
+		"GPRINT:total_bytes_min:%9.2lf %sbps",
+		"GPRINT:total_bytes_max:%9.2lf %sbps\\j",
+	);
+
+	RRDs::graph(@command);
+	$ERROR = RRDs::error;
+
+	return "Error in RRD::Graph for suricata: " . $ERROR . "\n" if $ERROR;
+}
diff --git a/config/collectd/collectd.conf b/config/collectd/collectd.conf
index 27e1fe984..a90331f21 100644
--- a/config/collectd/collectd.conf
+++ b/config/collectd/collectd.conf
@@ -52,6 +52,11 @@ include "/etc/collectd.precache"
 	Chain filter SPOOFED_MARTIAN DROP_SPOOFED_MARTIAN
 	Chain filter HOSTILE_DROP_IN DROP_HOSTILE
 	Chain filter HOSTILE_DROP_OUT DROP_HOSTILE
+
+	# IPS
+	Chain mangle IPS BYPASSED
+	Chain mangle IPS SCANNED
+	Chain mangle IPS WHITELISTED
 </Plugin>
 
 #<Plugin logfile>
diff --git a/config/rootfiles/common/suricata b/config/rootfiles/common/suricata
index 53224d006..8fe53f7e6 100644
--- a/config/rootfiles/common/suricata
+++ b/config/rootfiles/common/suricata
@@ -1,6 +1,7 @@
 etc/suricata
 etc/suricata/suricata.yaml
 usr/bin/suricata
+usr/bin/suricata-watcher
 usr/sbin/convert-ids-backend-files
 #usr/share/doc/suricata
 #usr/share/doc/suricata/AUTHORS
diff --git a/config/rootfiles/core/189/filelists/files b/config/rootfiles/core/189/filelists/files
index 2586805ea..7afa1ac2e 100644
--- a/config/rootfiles/core/189/filelists/files
+++ b/config/rootfiles/core/189/filelists/files
@@ -1,4 +1,12 @@
+etc/collectd.conf
+etc/rc.d/init.d/firewall
 etc/rc.d/init.d/functions
+etc/rc.d/init.d/networking/functions.network
+etc/rc.d/init.d/suricata
+srv/web/ipfire/cgi-bin/getrrdimage.cgi
+srv/web/ipfire/cgi-bin/ids.cgi
 srv/web/ipfire/html/include/rrdimage.js
+usr/bin/suricata-watcher
+var/ipfire/graphs.pl
 var/ipfire/header.pl
 var/ipfire/ids-functions.pl
diff --git a/config/rootfiles/core/189/update.sh b/config/rootfiles/core/189/update.sh
index f2c8863d6..43323f38a 100644
--- a/config/rootfiles/core/189/update.sh
+++ b/config/rootfiles/core/189/update.sh
@@ -349,6 +349,7 @@ ldconfig
 telinit u
 
 # Start services
+/etc/init.d/collectd restart
 /usr/local/bin/openvpnctrl -s
 /usr/local/bin/openvpnctrl -sn2n
 
diff --git a/config/suricata/suricata-watcher b/config/suricata/suricata-watcher
new file mode 100644
index 000000000..d937ef8cc
--- /dev/null
+++ b/config/suricata/suricata-watcher
@@ -0,0 +1,58 @@
+#!/bin/bash
+###############################################################################
+#                                                                             #
+# IPFire.org - A Linux-based Firewall                                         #
+# Copyright (C) 2024  IPFire Team  <info(a)ipfire.org>                          #
+#                                                                             #
+# 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 <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+###############################################################################
+
+PIDFILE="/var/run/suricata.pid"
+
+main() {
+	local ret
+
+	# Suricata becomes unhappy if the PID file exists
+	unlink "${PIDFILE}" &>/dev/null
+
+	while :; do
+		# Launch suricata
+		/usr/bin/suricata --pidfile "${PIDFILE}" "$@" &>/dev/null
+
+		# Wait until suricata is done
+		ret=$?
+
+		case "${ret}" in
+			# If suricata has been killed by SIGKILL (e.g. by
+			# the OOM killer, or if it ran into a SEGV, we will
+			# restart the process.
+			137|139)
+				# Remove the PID file
+				unlink "${PIDFILE}" 2>/dev/null
+
+				sleep 1
+				continue
+				;;
+
+			*)
+				break
+				;;
+		esac
+	done
+
+	return ${ret}
+}
+
+main "$@" || exit $?
diff --git a/doc/language_issues.de b/doc/language_issues.de
index b3d7082df..bd335de41 100644
--- a/doc/language_issues.de
+++ b/doc/language_issues.de
@@ -400,6 +400,7 @@ WARNING: translation string unused: icmp type
 WARNING: translation string unused: id
 WARNING: translation string unused: ids oinkcode required
 WARNING: translation string unused: ids rules update
+WARNING: translation string unused: ids ruleset settings
 WARNING: translation string unused: ids unsupported provider
 WARNING: translation string unused: ike encryption
 WARNING: translation string unused: ike grouptype
diff --git a/doc/language_issues.en b/doc/language_issues.en
index 3aa4e9bd8..c762cc6f7 100644
--- a/doc/language_issues.en
+++ b/doc/language_issues.en
@@ -361,6 +361,7 @@ WARNING: untranslated string: broken = Broken
 WARNING: untranslated string: broken pipe = Broken pipe
 WARNING: untranslated string: buffered memory = Buffered Memory
 WARNING: untranslated string: buffers = buffers
+WARNING: untranslated string: bypassed = Bypassed
 WARNING: untranslated string: bytes per second = Bytes per Second
 WARNING: untranslated string: bytes received = Bytes Received
 WARNING: untranslated string: bytes sent = Bytes Sent
@@ -1070,7 +1071,7 @@ WARNING: untranslated string: ids remove rule structures = Remove old rule struc
 WARNING: untranslated string: ids reset provider = Reset provider
 WARNING: untranslated string: ids ruleset autoupdate in progress = Ruleset update in progress. Please wait until all operations have completed successfully...
 WARNING: untranslated string: ids ruleset is up to date = No update required - The ruleset is up to date.
-WARNING: untranslated string: ids ruleset settings = Ruleset Settings
+WARNING: untranslated string: ids rulesets = Rulesets
 WARNING: untranslated string: ids show = Show
 WARNING: untranslated string: ids subscription code required = The selected ruleset requires a subscription code
 WARNING: untranslated string: ids the choosen provider is already in use = The choosen provider is already in use.
@@ -1191,6 +1192,7 @@ WARNING: untranslated string: ipfire has now shutdown = IPFire is shutting down
 WARNING: untranslated string: ipfire side is invalid = IPFire side is invalid.
 WARNING: untranslated string: ipfires hostname = IPFire's Hostname
 WARNING: untranslated string: ipinfo = IP info
+WARNING: untranslated string: ips throughput = Throughput
 WARNING: untranslated string: ipsec = IPsec
 WARNING: untranslated string: ipsec connection = IPsec Connection
 WARNING: untranslated string: ipsec dns server address is invalid = Invalid DNS server IP address(es)
@@ -1217,6 +1219,7 @@ WARNING: untranslated string: lan = LAN
 WARNING: untranslated string: languagepurpose = Select the language you wish IPFire to display in:
 WARNING: untranslated string: last = Last
 WARNING: untranslated string: last activity = Last Activity
+WARNING: untranslated string: last updated = Last Updated
 WARNING: untranslated string: lease expires = Lease expires
 WARNING: untranslated string: least preferred = least preferred
 WARNING: untranslated string: legend = Legend
@@ -1612,6 +1615,7 @@ WARNING: untranslated string: samba server role standalone = Standalone
 WARNING: untranslated string: saturday = Saturday
 WARNING: untranslated string: save = Save
 WARNING: untranslated string: save-adv-options = Save advanced options
+WARNING: untranslated string: scanned = Scanned
 WARNING: untranslated string: script name = Script name:
 WARNING: untranslated string: search = Search
 WARNING: untranslated string: secondary dns = Secondary DNS:
@@ -1802,6 +1806,7 @@ WARNING: untranslated string: tor traffic limit soft = Traffic limit almost reac
 WARNING: untranslated string: tor traffic read written = Total traffic (read/written)
 WARNING: untranslated string: tor use exit nodes = Use only these exit nodes (one fingerprint per line)
 WARNING: untranslated string: tor use guard nodes = Use only these guard nodes (one fingerprint per line)
+WARNING: untranslated string: total = Total
 WARNING: untranslated string: total connection time = Total Connection Time
 WARNING: untranslated string: total hits for log section = Total hits for log section
 WARNING: untranslated string: traffic stat in = In
@@ -2156,6 +2161,7 @@ WARNING: untranslated string: webradio playlist = Webradio Playlist
 WARNING: untranslated string: website = Website
 WARNING: untranslated string: wednesday = Wednesday
 WARNING: untranslated string: weeks = Weeks
+WARNING: untranslated string: whitelisted = Whitelisted
 WARNING: untranslated string: whois results from = WHOIS results from
 WARNING: untranslated string: winbind daemon = Winbind Daemon
 WARNING: untranslated string: wio = unknown string
diff --git a/doc/language_issues.es b/doc/language_issues.es
index fbbcd1e74..67f82a450 100644
--- a/doc/language_issues.es
+++ b/doc/language_issues.es
@@ -444,6 +444,7 @@ WARNING: translation string unused: ids rules license1
 WARNING: translation string unused: ids rules license2
 WARNING: translation string unused: ids rules license3
 WARNING: translation string unused: ids rules update
+WARNING: translation string unused: ids ruleset settings
 WARNING: translation string unused: ike encryption
 WARNING: translation string unused: ike grouptype
 WARNING: translation string unused: ike integrity
@@ -979,6 +980,7 @@ WARNING: untranslated string: Scan for Songs = unknown string
 WARNING: untranslated string: access point name = Access Point Name
 WARNING: untranslated string: access point name is invalid = Access Point Name is invalid
 WARNING: untranslated string: access point name is required = Access Point Name is required
+WARNING: untranslated string: bypassed = Bypassed
 WARNING: untranslated string: cpu frequency = CPU frequency
 WARNING: untranslated string: data transfer = Data Transfer
 WARNING: untranslated string: dhcp fixed ip address in dynamic range = Fixed IP Address in dynamic range
@@ -1028,8 +1030,11 @@ WARNING: untranslated string: hostile networks in = >From Hostile Networks
 WARNING: untranslated string: hostile networks out = To Hostile Networks
 WARNING: untranslated string: hostile networks total = Total Hostile Networks
 WARNING: untranslated string: ids provider eol = (EOL)
+WARNING: untranslated string: ids rulesets = Rulesets
 WARNING: untranslated string: info messages = unknown string
 WARNING: untranslated string: invalid ip or hostname = Invalid IP Address or Hostname
+WARNING: untranslated string: ips throughput = Throughput
+WARNING: untranslated string: last updated = Last Updated
 WARNING: untranslated string: load average = Load Average
 WARNING: untranslated string: log drop hostile in = Log dropped packets FROM hostile networks
 WARNING: untranslated string: log drop hostile out = Log dropped packets TO hostile networks
@@ -1048,12 +1053,15 @@ WARNING: untranslated string: route config changed = unknown string
 WARNING: untranslated string: routing config added = unknown string
 WARNING: untranslated string: routing config changed = unknown string
 WARNING: untranslated string: routing table = unknown string
+WARNING: untranslated string: scanned = Scanned
 WARNING: untranslated string: service boot setting unavailable = No valid runlevel symlink was found for the initscript of this service.
 WARNING: untranslated string: spec rstack overflow = Speculative Return Stack Overflow
 WARNING: untranslated string: system time = System Time (as of last page load)
 WARNING: untranslated string: timeformat = %Y-%m-%d at %H:%M:%S %Z
+WARNING: untranslated string: total = Total
 WARNING: untranslated string: transport mode does not support vti = VTI is not support in transport mode
 WARNING: untranslated string: warning = Warning
+WARNING: untranslated string: whitelisted = Whitelisted
 WARNING: untranslated string: wio = unknown string
 WARNING: untranslated string: wio checked = unknown string
 WARNING: untranslated string: wio cron = unknown string
diff --git a/doc/language_issues.fr b/doc/language_issues.fr
index 25193da6a..db8b6071e 100644
--- a/doc/language_issues.fr
+++ b/doc/language_issues.fr
@@ -428,6 +428,7 @@ WARNING: translation string unused: id
 WARNING: translation string unused: ids automatic rules update
 WARNING: translation string unused: ids oinkcode required
 WARNING: translation string unused: ids rules update
+WARNING: translation string unused: ids ruleset settings
 WARNING: translation string unused: ike encryption
 WARNING: translation string unused: ike grouptype
 WARNING: translation string unused: ike integrity
@@ -942,6 +943,7 @@ WARNING: translation string unused: zoneconf val vlan amount assignment error
 WARNING: translation string unused: zoneconf val vlan tag assignment error
 WARNING: translation string unused: zoneconf val vlan tag range error
 WARNING: translation string unused: zoneconf val zoneslave amount error
+WARNING: untranslated string: bypassed = Bypassed
 WARNING: untranslated string: core notice 3 = available.
 WARNING: untranslated string: data transfer = Data Transfer
 WARNING: untranslated string: enable disable client = unknown string
@@ -981,6 +983,9 @@ WARNING: untranslated string: guardian no entries = unknown string
 WARNING: untranslated string: guardian service = unknown string
 WARNING: untranslated string: hostile networks total = Total Hostile Networks
 WARNING: untranslated string: ids provider eol = (EOL)
+WARNING: untranslated string: ids rulesets = Rulesets
+WARNING: untranslated string: ips throughput = Throughput
+WARNING: untranslated string: last updated = Last Updated
 WARNING: untranslated string: load average = Load Average
 WARNING: untranslated string: oops something went wrong = Oops, something went wrong...
 WARNING: untranslated string: ovpn roadwarrior server = OpenVPN Roadwarrior Server
@@ -989,9 +994,12 @@ WARNING: untranslated string: processors = Processors
 WARNING: untranslated string: reg_file_data_sampling = Register File Data Sampling (RFDS)
 WARNING: untranslated string: routing config added = unknown string
 WARNING: untranslated string: routing config changed = unknown string
+WARNING: untranslated string: scanned = Scanned
 WARNING: untranslated string: system time = System Time (as of last page load)
 WARNING: untranslated string: timeformat = %Y-%m-%d at %H:%M:%S %Z
+WARNING: untranslated string: total = Total
 WARNING: untranslated string: warning = Warning
+WARNING: untranslated string: whitelisted = Whitelisted
 WARNING: untranslated string: wio = unknown string
 WARNING: untranslated string: wio checked = unknown string
 WARNING: untranslated string: wio cron = unknown string
diff --git a/doc/language_issues.it b/doc/language_issues.it
index f00d959d5..553417e59 100644
--- a/doc/language_issues.it
+++ b/doc/language_issues.it
@@ -948,6 +948,7 @@ WARNING: untranslated string: autonomous system = Autonomous System
 WARNING: untranslated string: available = available
 WARNING: untranslated string: block = Block
 WARNING: untranslated string: broken = Broken
+WARNING: untranslated string: bypassed = Bypassed
 WARNING: untranslated string: cake profile bridged-llcsnap 32 = Bridged LLC SNAP (32 bytes)
 WARNING: untranslated string: cake profile bridged-ptm 19 = Bridged PTM (19 bytes)
 WARNING: untranslated string: cake profile bridged-vcmux 24 = Bridged VC-MUX (24 bytes)
@@ -1132,7 +1133,7 @@ WARNING: untranslated string: ids remove rule structures = Remove old rule struc
 WARNING: untranslated string: ids reset provider = Reset provider
 WARNING: untranslated string: ids ruleset autoupdate in progress = Ruleset update in progress. Please wait until all operations have completed successfully...
 WARNING: untranslated string: ids ruleset is up to date = No update required - The ruleset is up to date.
-WARNING: untranslated string: ids ruleset settings = Ruleset Settings
+WARNING: untranslated string: ids rulesets = Rulesets
 WARNING: untranslated string: ids show = Show
 WARNING: untranslated string: ids subscription code required = The selected ruleset requires a subscription code
 WARNING: untranslated string: ids the choosen provider is already in use = The choosen provider is already in use.
@@ -1173,6 +1174,7 @@ WARNING: untranslated string: ipblocklist logs = IP Address Blocklist Logs
 WARNING: untranslated string: ipblocklist name = Name
 WARNING: untranslated string: ipblocklist output = Packets dropped (OUT)
 WARNING: untranslated string: ipblocklist use ipblocklists = Enable IP Blocklists
+WARNING: untranslated string: ips throughput = Throughput
 WARNING: untranslated string: ipsec connection = IPsec Connection
 WARNING: untranslated string: ipsec dns server address is invalid = Invalid DNS server IP address(es)
 WARNING: untranslated string: ipsec interface mode gre = GRE
@@ -1185,6 +1187,7 @@ WARNING: untranslated string: ipsec roadwarrior endpoint = Host-to-Net Endpoint
 WARNING: untranslated string: ipsec routing table entries = IPsec Routing Table Entries
 WARNING: untranslated string: ipsec settings = IPsec Settings
 WARNING: untranslated string: itlb multihit = iTLB MultiHit
+WARNING: untranslated string: last updated = Last Updated
 WARNING: untranslated string: link-layer encapsulation = Link-Layer Encapsulation
 WARNING: untranslated string: load average = Load Average
 WARNING: untranslated string: local ip address = Local IP Address
@@ -1272,6 +1275,7 @@ WARNING: untranslated string: samba join a domain = Join a domain
 WARNING: untranslated string: samba join domain = Join domain
 WARNING: untranslated string: samba server role member = Domain Member
 WARNING: untranslated string: samba server role standalone = Standalone
+WARNING: untranslated string: scanned = Scanned
 WARNING: untranslated string: search = Search
 WARNING: untranslated string: secret = Secret
 WARNING: untranslated string: sent = Sent
@@ -1309,6 +1313,7 @@ WARNING: untranslated string: token not set = No Token has been given.
 WARNING: untranslated string: tor guard country any = Any country
 WARNING: untranslated string: tor guard nodes = Guard Nodes
 WARNING: untranslated string: tor use guard nodes = Use only these guard nodes (one fingerprint per line)
+WARNING: untranslated string: total = Total
 WARNING: untranslated string: traffic stat in = In
 WARNING: untranslated string: traffic stat out = Out
 WARNING: untranslated string: traffic stat title = RED Traffic
@@ -1342,6 +1347,7 @@ WARNING: untranslated string: vpn weak = Weak
 WARNING: untranslated string: vulnerability = Vulnerability
 WARNING: untranslated string: vulnerable = Vulnerable
 WARNING: untranslated string: warning = Warning
+WARNING: untranslated string: whitelisted = Whitelisted
 WARNING: untranslated string: whois results from = WHOIS results from
 WARNING: untranslated string: winbind daemon = Winbind Daemon
 WARNING: untranslated string: wio = unknown string
diff --git a/doc/language_issues.nl b/doc/language_issues.nl
index 9607f98af..0b16d098d 100644
--- a/doc/language_issues.nl
+++ b/doc/language_issues.nl
@@ -950,6 +950,7 @@ WARNING: untranslated string: autonomous system = Autonomous System
 WARNING: untranslated string: available = available
 WARNING: untranslated string: block = Block
 WARNING: untranslated string: broken = Broken
+WARNING: untranslated string: bypassed = Bypassed
 WARNING: untranslated string: cake profile bridged-llcsnap 32 = Bridged LLC SNAP (32 bytes)
 WARNING: untranslated string: cake profile bridged-ptm 19 = Bridged PTM (19 bytes)
 WARNING: untranslated string: cake profile bridged-vcmux 24 = Bridged VC-MUX (24 bytes)
@@ -1138,7 +1139,7 @@ WARNING: untranslated string: ids remove rule structures = Remove old rule struc
 WARNING: untranslated string: ids reset provider = Reset provider
 WARNING: untranslated string: ids ruleset autoupdate in progress = Ruleset update in progress. Please wait until all operations have completed successfully...
 WARNING: untranslated string: ids ruleset is up to date = No update required - The ruleset is up to date.
-WARNING: untranslated string: ids ruleset settings = Ruleset Settings
+WARNING: untranslated string: ids rulesets = Rulesets
 WARNING: untranslated string: ids show = Show
 WARNING: untranslated string: ids subscription code required = The selected ruleset requires a subscription code
 WARNING: untranslated string: ids the choosen provider is already in use = The choosen provider is already in use.
@@ -1181,6 +1182,7 @@ WARNING: untranslated string: ipblocklist logs = IP Address Blocklist Logs
 WARNING: untranslated string: ipblocklist name = Name
 WARNING: untranslated string: ipblocklist output = Packets dropped (OUT)
 WARNING: untranslated string: ipblocklist use ipblocklists = Enable IP Blocklists
+WARNING: untranslated string: ips throughput = Throughput
 WARNING: untranslated string: ipsec connection = IPsec Connection
 WARNING: untranslated string: ipsec dns server address is invalid = Invalid DNS server IP address(es)
 WARNING: untranslated string: ipsec interface mode gre = GRE
@@ -1193,6 +1195,7 @@ WARNING: untranslated string: ipsec roadwarrior endpoint = Host-to-Net Endpoint
 WARNING: untranslated string: ipsec routing table entries = IPsec Routing Table Entries
 WARNING: untranslated string: ipsec settings = IPsec Settings
 WARNING: untranslated string: itlb multihit = iTLB MultiHit
+WARNING: untranslated string: last updated = Last Updated
 WARNING: untranslated string: link-layer encapsulation = Link-Layer Encapsulation
 WARNING: untranslated string: load average = Load Average
 WARNING: untranslated string: local ip address = Local IP Address
@@ -1295,6 +1298,7 @@ WARNING: untranslated string: samba join a domain = Join a domain
 WARNING: untranslated string: samba join domain = Join domain
 WARNING: untranslated string: samba server role member = Domain Member
 WARNING: untranslated string: samba server role standalone = Standalone
+WARNING: untranslated string: scanned = Scanned
 WARNING: untranslated string: search = Search
 WARNING: untranslated string: secret = Secret
 WARNING: untranslated string: sent = Sent
@@ -1335,6 +1339,7 @@ WARNING: untranslated string: token not set = No Token has been given.
 WARNING: untranslated string: tor guard country any = Any country
 WARNING: untranslated string: tor guard nodes = Guard Nodes
 WARNING: untranslated string: tor use guard nodes = Use only these guard nodes (one fingerprint per line)
+WARNING: untranslated string: total = Total
 WARNING: untranslated string: transfers = Transfers
 WARNING: untranslated string: transport mode does not support vti = VTI is not support in transport mode
 WARNING: untranslated string: twelve hours = 12 Hours
@@ -1365,6 +1370,7 @@ WARNING: untranslated string: vpn weak = Weak
 WARNING: untranslated string: vulnerability = Vulnerability
 WARNING: untranslated string: vulnerable = Vulnerable
 WARNING: untranslated string: warning = Warning
+WARNING: untranslated string: whitelisted = Whitelisted
 WARNING: untranslated string: whois results from = WHOIS results from
 WARNING: untranslated string: winbind daemon = Winbind Daemon
 WARNING: untranslated string: wio = unknown string
diff --git a/doc/language_issues.pl b/doc/language_issues.pl
index 92ad3b7be..a3acd734f 100644
--- a/doc/language_issues.pl
+++ b/doc/language_issues.pl
@@ -875,6 +875,7 @@ WARNING: untranslated string: available = available
 WARNING: untranslated string: bit = bit
 WARNING: untranslated string: block = Block
 WARNING: untranslated string: broken = Broken
+WARNING: untranslated string: bypassed = Bypassed
 WARNING: untranslated string: cake profile bridged-llcsnap 32 = Bridged LLC SNAP (32 bytes)
 WARNING: untranslated string: cake profile bridged-ptm 19 = Bridged PTM (19 bytes)
 WARNING: untranslated string: cake profile bridged-vcmux 24 = Bridged VC-MUX (24 bytes)
@@ -1276,7 +1277,7 @@ WARNING: untranslated string: ids remove rule structures = Remove old rule struc
 WARNING: untranslated string: ids reset provider = Reset provider
 WARNING: untranslated string: ids ruleset autoupdate in progress = Ruleset update in progress. Please wait until all operations have completed successfully...
 WARNING: untranslated string: ids ruleset is up to date = No update required - The ruleset is up to date.
-WARNING: untranslated string: ids ruleset settings = Ruleset Settings
+WARNING: untranslated string: ids rulesets = Rulesets
 WARNING: untranslated string: ids show = Show
 WARNING: untranslated string: ids subscription code required = The selected ruleset requires a subscription code
 WARNING: untranslated string: ids the choosen provider is already in use = The choosen provider is already in use.
@@ -1323,6 +1324,7 @@ WARNING: untranslated string: ipblocklist logs = IP Address Blocklist Logs
 WARNING: untranslated string: ipblocklist name = Name
 WARNING: untranslated string: ipblocklist output = Packets dropped (OUT)
 WARNING: untranslated string: ipblocklist use ipblocklists = Enable IP Blocklists
+WARNING: untranslated string: ips throughput = Throughput
 WARNING: untranslated string: ipsec = IPsec
 WARNING: untranslated string: ipsec connection = IPsec Connection
 WARNING: untranslated string: ipsec dns server address is invalid = Invalid DNS server IP address(es)
@@ -1338,6 +1340,7 @@ WARNING: untranslated string: ipsec routing table entries = IPsec Routing Table
 WARNING: untranslated string: ipsec settings = IPsec Settings
 WARNING: untranslated string: itlb multihit = iTLB MultiHit
 WARNING: untranslated string: last = Last
+WARNING: untranslated string: last updated = Last Updated
 WARNING: untranslated string: least preferred = least preferred
 WARNING: untranslated string: lifetime = Lifetime:
 WARNING: untranslated string: link-layer encapsulation = Link-Layer Encapsulation
@@ -1474,6 +1477,7 @@ WARNING: untranslated string: samba join a domain = Join a domain
 WARNING: untranslated string: samba join domain = Join domain
 WARNING: untranslated string: samba server role member = Domain Member
 WARNING: untranslated string: samba server role standalone = Standalone
+WARNING: untranslated string: scanned = Scanned
 WARNING: untranslated string: search = Search
 WARNING: untranslated string: secret = Secret
 WARNING: untranslated string: sent = Sent
@@ -1568,6 +1572,7 @@ WARNING: untranslated string: tor traffic limit soft = Traffic limit almost reac
 WARNING: untranslated string: tor traffic read written = Total traffic (read/written)
 WARNING: untranslated string: tor use exit nodes = Use only these exit nodes (one fingerprint per line)
 WARNING: untranslated string: tor use guard nodes = Use only these guard nodes (one fingerprint per line)
+WARNING: untranslated string: total = Total
 WARNING: untranslated string: traffic stat in = In
 WARNING: untranslated string: traffic stat out = Out
 WARNING: untranslated string: traffic stat title = RED Traffic
@@ -1606,6 +1611,7 @@ WARNING: untranslated string: vpn weak = Weak
 WARNING: untranslated string: vulnerability = Vulnerability
 WARNING: untranslated string: vulnerable = Vulnerable
 WARNING: untranslated string: warning = Warning
+WARNING: untranslated string: whitelisted = Whitelisted
 WARNING: untranslated string: whois results from = WHOIS results from
 WARNING: untranslated string: winbind daemon = Winbind Daemon
 WARNING: untranslated string: wio = unknown string
diff --git a/doc/language_issues.ru b/doc/language_issues.ru
index 35a590b6b..66b6cae13 100644
--- a/doc/language_issues.ru
+++ b/doc/language_issues.ru
@@ -870,6 +870,7 @@ WARNING: untranslated string: available = available
 WARNING: untranslated string: bit = bit
 WARNING: untranslated string: block = Block
 WARNING: untranslated string: broken = Broken
+WARNING: untranslated string: bypassed = Bypassed
 WARNING: untranslated string: cake profile bridged-llcsnap 32 = Bridged LLC SNAP (32 bytes)
 WARNING: untranslated string: cake profile bridged-ptm 19 = Bridged PTM (19 bytes)
 WARNING: untranslated string: cake profile bridged-vcmux 24 = Bridged VC-MUX (24 bytes)
@@ -1271,7 +1272,7 @@ WARNING: untranslated string: ids remove rule structures = Remove old rule struc
 WARNING: untranslated string: ids reset provider = Reset provider
 WARNING: untranslated string: ids ruleset autoupdate in progress = Ruleset update in progress. Please wait until all operations have completed successfully...
 WARNING: untranslated string: ids ruleset is up to date = No update required - The ruleset is up to date.
-WARNING: untranslated string: ids ruleset settings = Ruleset Settings
+WARNING: untranslated string: ids rulesets = Rulesets
 WARNING: untranslated string: ids show = Show
 WARNING: untranslated string: ids subscription code required = The selected ruleset requires a subscription code
 WARNING: untranslated string: ids the choosen provider is already in use = The choosen provider is already in use.
@@ -1319,6 +1320,7 @@ WARNING: untranslated string: ipblocklist logs = IP Address Blocklist Logs
 WARNING: untranslated string: ipblocklist name = Name
 WARNING: untranslated string: ipblocklist output = Packets dropped (OUT)
 WARNING: untranslated string: ipblocklist use ipblocklists = Enable IP Blocklists
+WARNING: untranslated string: ips throughput = Throughput
 WARNING: untranslated string: ipsec = IPsec
 WARNING: untranslated string: ipsec connection = IPsec Connection
 WARNING: untranslated string: ipsec dns server address is invalid = Invalid DNS server IP address(es)
@@ -1334,6 +1336,7 @@ WARNING: untranslated string: ipsec routing table entries = IPsec Routing Table
 WARNING: untranslated string: ipsec settings = IPsec Settings
 WARNING: untranslated string: itlb multihit = iTLB MultiHit
 WARNING: untranslated string: last = Last
+WARNING: untranslated string: last updated = Last Updated
 WARNING: untranslated string: least preferred = least preferred
 WARNING: untranslated string: lifetime = Lifetime:
 WARNING: untranslated string: link-layer encapsulation = Link-Layer Encapsulation
@@ -1467,6 +1470,7 @@ WARNING: untranslated string: samba join a domain = Join a domain
 WARNING: untranslated string: samba join domain = Join domain
 WARNING: untranslated string: samba server role member = Domain Member
 WARNING: untranslated string: samba server role standalone = Standalone
+WARNING: untranslated string: scanned = Scanned
 WARNING: untranslated string: search = Search
 WARNING: untranslated string: secret = Secret
 WARNING: untranslated string: sent = Sent
@@ -1561,6 +1565,7 @@ WARNING: untranslated string: tor traffic limit soft = Traffic limit almost reac
 WARNING: untranslated string: tor traffic read written = Total traffic (read/written)
 WARNING: untranslated string: tor use exit nodes = Use only these exit nodes (one fingerprint per line)
 WARNING: untranslated string: tor use guard nodes = Use only these guard nodes (one fingerprint per line)
+WARNING: untranslated string: total = Total
 WARNING: untranslated string: traffic stat in = In
 WARNING: untranslated string: traffic stat out = Out
 WARNING: untranslated string: traffic stat title = RED Traffic
@@ -1599,6 +1604,7 @@ WARNING: untranslated string: vpn weak = Weak
 WARNING: untranslated string: vulnerability = Vulnerability
 WARNING: untranslated string: vulnerable = Vulnerable
 WARNING: untranslated string: warning = Warning
+WARNING: untranslated string: whitelisted = Whitelisted
 WARNING: untranslated string: whois results from = WHOIS results from
 WARNING: untranslated string: winbind daemon = Winbind Daemon
 WARNING: untranslated string: wio = unknown string
diff --git a/doc/language_issues.tr b/doc/language_issues.tr
index 3bf595efe..ec657539f 100644
--- a/doc/language_issues.tr
+++ b/doc/language_issues.tr
@@ -935,6 +935,7 @@ WARNING: untranslated string: asn lookup failed = AS lookup failed
 WARNING: untranslated string: autonomous system = Autonomous System
 WARNING: untranslated string: available = available
 WARNING: untranslated string: broken = Broken
+WARNING: untranslated string: bypassed = Bypassed
 WARNING: untranslated string: cake profile bridged-llcsnap 32 = Bridged LLC SNAP (32 bytes)
 WARNING: untranslated string: cake profile bridged-ptm 19 = Bridged PTM (19 bytes)
 WARNING: untranslated string: cake profile bridged-vcmux 24 = Bridged VC-MUX (24 bytes)
@@ -1074,7 +1075,7 @@ WARNING: untranslated string: ids remove rule structures = Remove old rule struc
 WARNING: untranslated string: ids reset provider = Reset provider
 WARNING: untranslated string: ids ruleset autoupdate in progress = Ruleset update in progress. Please wait until all operations have completed successfully...
 WARNING: untranslated string: ids ruleset is up to date = No update required - The ruleset is up to date.
-WARNING: untranslated string: ids ruleset settings = Ruleset Settings
+WARNING: untranslated string: ids rulesets = Rulesets
 WARNING: untranslated string: ids show = Show
 WARNING: untranslated string: ids subscription code required = The selected ruleset requires a subscription code
 WARNING: untranslated string: ids the choosen provider is already in use = The choosen provider is already in use.
@@ -1110,6 +1111,7 @@ WARNING: untranslated string: ipblocklist logs = IP Address Blocklist Logs
 WARNING: untranslated string: ipblocklist name = Name
 WARNING: untranslated string: ipblocklist output = Packets dropped (OUT)
 WARNING: untranslated string: ipblocklist use ipblocklists = Enable IP Blocklists
+WARNING: untranslated string: ips throughput = Throughput
 WARNING: untranslated string: ipsec connection = IPsec Connection
 WARNING: untranslated string: ipsec dns server address is invalid = Invalid DNS server IP address(es)
 WARNING: untranslated string: ipsec interface mode gre = GRE
@@ -1122,6 +1124,7 @@ WARNING: untranslated string: ipsec roadwarrior endpoint = Host-to-Net Endpoint
 WARNING: untranslated string: ipsec routing table entries = IPsec Routing Table Entries
 WARNING: untranslated string: ipsec settings = IPsec Settings
 WARNING: untranslated string: itlb multihit = iTLB MultiHit
+WARNING: untranslated string: last updated = Last Updated
 WARNING: untranslated string: link-layer encapsulation = Link-Layer Encapsulation
 WARNING: untranslated string: load average = Load Average
 WARNING: untranslated string: local ip address = Local IP Address
@@ -1179,6 +1182,7 @@ WARNING: untranslated string: routing config changed = unknown string
 WARNING: untranslated string: routing table = unknown string
 WARNING: untranslated string: samba server role member = Domain Member
 WARNING: untranslated string: samba server role standalone = Standalone
+WARNING: untranslated string: scanned = Scanned
 WARNING: untranslated string: secret = Secret
 WARNING: untranslated string: sent = Sent
 WARNING: untranslated string: service boot setting unavailable = No valid runlevel symlink was found for the initscript of this service.
@@ -1212,6 +1216,7 @@ WARNING: untranslated string: token not set = No Token has been given.
 WARNING: untranslated string: tor guard country any = Any country
 WARNING: untranslated string: tor guard nodes = Guard Nodes
 WARNING: untranslated string: tor use guard nodes = Use only these guard nodes (one fingerprint per line)
+WARNING: untranslated string: total = Total
 WARNING: untranslated string: traffic stat in = In
 WARNING: untranslated string: traffic stat out = Out
 WARNING: untranslated string: traffic stat title = RED Traffic
@@ -1226,6 +1231,7 @@ WARNING: untranslated string: vpn wait = WAITING
 WARNING: untranslated string: vulnerability = Vulnerability
 WARNING: untranslated string: vulnerable = Vulnerable
 WARNING: untranslated string: warning = Warning
+WARNING: untranslated string: whitelisted = Whitelisted
 WARNING: untranslated string: whois results from = WHOIS results from
 WARNING: untranslated string: winbind daemon = Winbind Daemon
 WARNING: untranslated string: wio = unknown string
diff --git a/doc/language_missings b/doc/language_missings
index 98856b0e8..6a44630bd 100644
--- a/doc/language_missings
+++ b/doc/language_missings
@@ -103,6 +103,7 @@
 < upload fcdsl.o
 < user management
 < vpn configuration main
+< wg
 < winbind daemon
 < wireguard
 < wlanap 802.11w disabled
@@ -120,6 +121,7 @@
 < access point name is invalid
 < access point name is required
 < addon
+< bypassed
 < cpu frequency
 < data transfer
 < dhcp fixed ip address in dynamic range
@@ -136,8 +138,11 @@
 < hostile networks out
 < hostile networks total
 < ids provider eol
+< ids rulesets
 < ids unsupported provider
 < invalid ip or hostname
+< ips throughput
+< last updated
 < load average
 < log drop hostile in
 < log drop hostile out
@@ -150,12 +155,16 @@
 < reg_file_data_sampling
 < reiserfs warning1
 < reiserfs warning2
+< scanned
 < service boot setting unavailable
 < spec rstack overflow
 < system time
 < timeformat
+< total
 < transport mode does not support vti
 < warning
+< wg
+< whitelisted
 < wireguard
 < wlanap
 < wlanap psk
@@ -168,6 +177,7 @@
 < ansi t1.483
 < bewan adsl pci st
 < bewan adsl usb
+< bypassed
 < data transfer
 < extrahd because it it outside the allowed mount path
 < fwdfw syn flood protection
@@ -175,16 +185,23 @@
 < g.lite
 < hostile networks total
 < ids provider eol
+< ids rulesets
 < ids unsupported provider
+< ips throughput
+< last updated
 < load average
 < oops something went wrong
 < ovpn roadwarrior server
 < processors
 < reg_file_data_sampling
+< scanned
 < system time
 < timeformat
+< total
 < upload fcdsl.o
 < warning
+< wg
+< whitelisted
 < wireguard
 < wlanap psk
 < wlanap wireless mode
@@ -226,6 +243,7 @@
 < available
 < block
 < broken
+< bypassed
 < cake profile bridged-llcsnap 32
 < cake profile bridged-ptm 19
 < cake profile bridged-vcmux 24
@@ -444,6 +462,7 @@
 < ids reset provider
 < ids ruleset autoupdate in progress
 < ids ruleset is up to date
+< ids rulesets
 < ids ruleset settings
 < ids show
 < ids subscription code required
@@ -503,7 +522,9 @@
 < ipsec roadwarrior endpoint
 < ipsec routing table entries
 < ipsec settings
+< ips throughput
 < itlb multihit
+< last updated
 < legacy architecture warning
 < link-layer encapsulation
 < load average
@@ -595,6 +616,7 @@
 < samba join domain
 < samba server role member
 < samba server role standalone
+< scanned
 < search
 < secret
 < sent
@@ -633,6 +655,7 @@
 < tor guard country any
 < tor guard nodes
 < tor use guard nodes
+< total
 < traffic stat in
 < traffic stat out
 < traffic stat title
@@ -668,6 +691,8 @@
 < vulnerable
 < warning
 < Weekly
+< wg
+< whitelisted
 < whois results from
 < winbind daemon
 < wireguard
@@ -761,6 +786,7 @@
 < available
 < block
 < broken
+< bypassed
 < cake profile bridged-llcsnap 32
 < cake profile bridged-ptm 19
 < cake profile bridged-vcmux 24
@@ -984,6 +1010,7 @@
 < ids reset provider
 < ids ruleset autoupdate in progress
 < ids ruleset is up to date
+< ids rulesets
 < ids ruleset settings
 < ids show
 < ids subscription code required
@@ -1045,7 +1072,9 @@
 < ipsec roadwarrior endpoint
 < ipsec routing table entries
 < ipsec settings
+< ips throughput
 < itlb multihit
+< last updated
 < legacy architecture warning
 < link-layer encapsulation
 < load average
@@ -1155,6 +1184,7 @@
 < samba join domain
 < samba server role member
 < samba server role standalone
+< scanned
 < search
 < secret
 < sent
@@ -1197,6 +1227,7 @@
 < tor guard country any
 < tor guard nodes
 < tor use guard nodes
+< total
 < transfers
 < transport mode does not support vti
 < twelve hours
@@ -1229,6 +1260,8 @@
 < vulnerable
 < warning
 < Weekly
+< wg
+< whitelisted
 < whois results from
 < winbind daemon
 < wireguard
@@ -1336,6 +1369,7 @@
 < bit
 < block
 < broken
+< bypassed
 < cake profile bridged-llcsnap 32
 < cake profile bridged-ptm 19
 < cake profile bridged-vcmux 24
@@ -1829,6 +1863,7 @@
 < ids reset provider
 < ids ruleset autoupdate in progress
 < ids ruleset is up to date
+< ids rulesets
 < ids ruleset settings
 < ids show
 < ids subscription code required
@@ -1897,8 +1932,10 @@
 < ipsec roadwarrior endpoint
 < ipsec routing table entries
 < ipsec settings
+< ips throughput
 < itlb multihit
 < last
+< last updated
 < least preferred
 < legacy architecture warning
 < lifetime
@@ -2057,6 +2094,7 @@
 < samba join domain
 < samba server role member
 < samba server role standalone
+< scanned
 < search
 < secret
 < sent
@@ -2160,6 +2198,7 @@
 < tor traffic read written
 < tor use exit nodes
 < tor use guard nodes
+< total
 < traffic stat in
 < traffic stat out
 < traffic stat title
@@ -2205,6 +2244,8 @@
 < vulnerable
 < warning
 < Weekly
+< wg
+< whitelisted
 < whois results from
 < winbind daemon
 < wireguard
@@ -2344,6 +2385,7 @@
 < bit
 < block
 < broken
+< bypassed
 < cake profile bridged-llcsnap 32
 < cake profile bridged-ptm 19
 < cake profile bridged-vcmux 24
@@ -2842,6 +2884,7 @@
 < ids reset provider
 < ids ruleset autoupdate in progress
 < ids ruleset is up to date
+< ids rulesets
 < ids ruleset settings
 < ids show
 < ids subscription code required
@@ -2911,8 +2954,10 @@
 < ipsec roadwarrior endpoint
 < ipsec routing table entries
 < ipsec settings
+< ips throughput
 < itlb multihit
 < last
+< last updated
 < least preferred
 < legacy architecture warning
 < lifetime
@@ -3069,6 +3114,7 @@
 < samba join domain
 < samba server role member
 < samba server role standalone
+< scanned
 < search
 < secret
 < sent
@@ -3172,6 +3218,7 @@
 < tor traffic read written
 < tor use exit nodes
 < tor use guard nodes
+< total
 < traffic stat in
 < traffic stat out
 < traffic stat title
@@ -3218,6 +3265,8 @@
 < warning
 < week-graph
 < Weekly
+< wg
+< whitelisted
 < whois results from
 < winbind daemon
 < wireguard
@@ -3333,6 +3382,7 @@
 < autonomous system
 < available
 < broken
+< bypassed
 < cake profile bridged-llcsnap 32
 < cake profile bridged-ptm 19
 < cake profile bridged-vcmux 24
@@ -3447,6 +3497,7 @@
 < ids reset provider
 < ids ruleset autoupdate in progress
 < ids ruleset is up to date
+< ids rulesets
 < ids ruleset settings
 < ids show
 < ids subscription code required
@@ -3501,7 +3552,9 @@
 < ipsec roadwarrior endpoint
 < ipsec routing table entries
 < ipsec settings
+< ips throughput
 < itlb multihit
+< last updated
 < legacy architecture warning
 < link-layer encapsulation
 < load average
@@ -3558,6 +3611,7 @@
 < runmode
 < samba server role member
 < samba server role standalone
+< scanned
 < secret
 < sent
 < service boot setting unavailable
@@ -3592,6 +3646,7 @@
 < tor guard country any
 < tor guard nodes
 < tor use guard nodes
+< total
 < traffic stat in
 < traffic stat out
 < traffic stat title
@@ -3608,6 +3663,8 @@
 < vulnerable
 < warning
 < Weekly
+< wg
+< whitelisted
 < whois results from
 < winbind daemon
 < wireguard
diff --git a/html/cgi-bin/getrrdimage.cgi b/html/cgi-bin/getrrdimage.cgi
index f80f0138f..77556217d 100644
--- a/html/cgi-bin/getrrdimage.cgi
+++ b/html/cgi-bin/getrrdimage.cgi
@@ -35,7 +35,7 @@ require "${General::swroot}/graphs.pl";
 
 # List of graph origins that getrrdimage.cgi can process directly
 # (unknown origins are forwarded to ensure compatibility)
-my @supported_origins = ("hardwaregraphs.cgi", "media.cgi",
+my @supported_origins = ("ids.cgi", "hardwaregraphs.cgi", "media.cgi",
 	"memory.cgi", "netexternal.cgi", "netinternal.cgi", "netother.cgi",
 	"netovpnrw.cgi", "netovpnsrv.cgi", "qos.cgi", "services.cgi", "system.cgi");
 
@@ -80,7 +80,13 @@ _start_svg_output();
 # Graphs are first grouped by their origin.
 # This is because some graph categories require special parameter handling.
 my $graphstatus = '';
-if($origin eq "hardwaregraphs.cgi") {		## hardwaregraphs.cgi
+if ($origin eq "ids.cgi") {				## ids.cgi
+	if ($graph eq "ips-throughput") {
+		$graphstatus = Graphs::updateipsthroughputgraph($range);
+	} else {
+		$graphstatus = "Unknown graph name.";
+	}
+} elsif($origin eq "hardwaregraphs.cgi") {		## hardwaregraphs.cgi
 	if($graph eq "hwtemp") {
 		$graphstatus = Graphs::updatehwtempgraph($range);
 	} elsif($graph eq "hwfan") {
diff --git a/html/cgi-bin/ids.cgi b/html/cgi-bin/ids.cgi
index 502e2a125..4eaf4911d 100644
--- a/html/cgi-bin/ids.cgi
+++ b/html/cgi-bin/ids.cgi
@@ -53,6 +53,9 @@ my %ignored=();
 # the list of zones in an array.
 my @network_zones = &Network::get_available_network_zones();
 
+# Always show IPsec & Wireguard
+push(@network_zones, "ipsec", "wg");
+
 # Check if openvpn is started and add it to the array of network zones.
 if ( -e "/var/run/openvpn.pid") {
 	push(@network_zones, "ovpn");
@@ -69,7 +72,9 @@ my %colourhash = (
 	'green' => $Header::colourgreen,
 	'blue' => $Header::colourblue,
 	'orange' => $Header::colourorange,
-	'ovpn' => $Header::colourovpn
+	'ipsec' => $Header::colourvpn,
+	'ovpn' => $Header::colourovpn,
+	'wg' => $Header::colourwg,
 );
 
 &Header::showhttpheaders();
@@ -1003,7 +1008,7 @@ sub show_mainpage() {
 	$checked{'ENABLE_IDS'}{$idssettings{'ENABLE_IDS'}} = "checked='checked'";
 
 	# Draw current state of the IDS
-	&Header::openbox('100%', 'left', $Lang::tr{'intrusion detection system'});
+	&Header::opensection();
 
 	&Header::ServiceStatus({
 		$Lang::tr{'intrusion prevention system'} => {
@@ -1013,30 +1018,29 @@ sub show_mainpage() {
 
 	# Only show this area, if at least one ruleset provider is configured.
 	if (%used_providers) {
+		my $num_zones = scalar @network_zones;
 
 print <<END
-
-		<br><br><h2>$Lang::tr{'settings'}</h2>
+		<br>
 
 		<form method='post' action='$ENV{'SCRIPT_NAME'}'>
 			<table width='100%' border='0'>
 				<tr>
-					<td class='base' colspan='2'>
+					<td colspan='$num_zones'>
 						<input type='checkbox' name='ENABLE_IDS' $checked{'ENABLE_IDS'}{'on'}>&nbsp;$Lang::tr{'ids enable'}
 					</td>
-
-				</td>
 				</tr>
 
-				<tr>
-					<td><br><br></td>
-					<td><br><br></td>
-					<td><br><br></td>
-					<td><br><br></td>
+				<tr> <!-- empty row for spacing -->
+					<td colspan='$num_zones'>
+						&nbsp;
+					</td>
 				</tr>
 
 				<tr>
-					<td colspan='4'><b>$Lang::tr{'ids monitored interfaces'}</b><br></td>
+					<td colspan='$num_zones'>
+						<b>$Lang::tr{'ids monitored interfaces'}</b>
+					</td>
 				</tr>
 
 				<tr>
@@ -1064,21 +1068,29 @@ END
 				$checked_input = "checked = 'checked'";
 			}
 
-			print "<td class='base' width='20%'>\n";
-			print "<input type='checkbox' name='ENABLE_IDS_$zone_upper' $checked_input>\n";
-			print "&nbsp;$Lang::tr{'enabled on'}<font color='$colourhash{$zone}'> $Lang::tr{$zone_name}</font>\n";
-			print "</td>\n";
+			print <<END;
+				<td>
+					<label>
+						<input type='checkbox' name='ENABLE_IDS_$zone_upper' $checked_input>
+						&nbsp; $Lang::tr{'enabled on'}<font color='$colourhash{$zone}'> $Lang::tr{$zone_name}</font>
+					</label>
+				</td>
+END
 		}
 
 print <<END
 				</tr>
-			</table>
 
-			<br><br>
+				<tr> <!-- empty row for spacing -->
+					<td colspan='$num_zones'>
+						&nbsp;
+					</td>
+				</tr>
 
-			<table width='100%'>
 				<tr>
-					<td align='right'><input type='submit' name='IDS' value='$Lang::tr{'save'}' /></td>
+					<td colspan='$num_zones' align='right'>
+						<input type='submit' name='IDS' value='$Lang::tr{'save'}' />
+					</td>
 				</tr>
 			</table>
 		</form>
@@ -1087,21 +1099,25 @@ END
 
 	}
 
-	&Header::closebox();
+	&Header::closesection();
+
+	# Throughput Graph
+	if (-e "/var/log/rrd/collectd/localhost/iptables-mangle-IPS/ipt_bytes-BYPASSED.rrd") {
+		&Header::graph("$Lang::tr{'ips throughput'}", "ids.cgi", "ips-throughput", "day");
+	}
 
 	#
 	# Used Ruleset Providers section.
 	#
-	&Header::openbox('100%', 'center', $Lang::tr{'ids ruleset settings'});
+	&Header::openbox('100%', 'center', $Lang::tr{'ids rulesets'});
 
 print <<END;
-	<table width='100%' border='0'>
+	<table width='100%' border='0' class='tbl'>
 		<tr>
-			<td class='base' bgcolor='$color{'color20'}'><b>$Lang::tr{'ids provider'}</b></td>
-			<td class='base' bgcolor='$color{'color20'}'><b>$Lang::tr{'date'}</b></td>
-			<td class='base' bgcolor='$color{'color20'}' align='center'><b>$Lang::tr{'ids autoupdates'}</b></td>
-			<td class='base' bgcolor='$color{'color20'}' align='center'><b>$Lang::tr{'action'}</b></td>
-			<td class='base' colspan='3' bgcolor='$color{'color20'}'></td>
+			<th>$Lang::tr{'ids provider'}</td>
+			<th>$Lang::tr{'last updated'}</td>
+			<th align='center'>$Lang::tr{'ids autoupdates'}</td>
+			<th align='center' colspan='3'>$Lang::tr{'action'}</td>
 		</tr>
 END
 		my $line = 1;
@@ -1122,13 +1138,6 @@ END
 				my $status  = $used_providers{$id}[3];
 				my $unsupported;
 
-				# Check if the item number is even or not.
-				if ($line % 2) {
-					$col="bgcolor='$color{'color22'}'";
-				} else {
-					$col="bgcolor='$color{'color20'}'";
-				}
-
 				# Handle providers which are not longer supported.
 				unless ($IDS::Ruleset::Providers{$provider}{'dl_url'}) {
 					$col = "bgcolor='$Header::colouryellow'";
@@ -1161,8 +1170,8 @@ END
 
 print <<END;
 				<tr>
-					<td width='33%' class='base' $col>$provider_name $unsupported</td>
-					<td width='30%' class='base' $col>$rulesetdate</td>
+					<th scope='row' width='33%' $col>$provider_name $unsupported</th>
+					<td width='30%' $col align='center'>$rulesetdate</td>
 
 					<td align='center' $col>
 						<form method='post' action='$ENV{'SCRIPT_NAME'}'>
@@ -1205,7 +1214,7 @@ END
 		} else {
 			# Print notice that currently no hosts are ignored.
 			print "<tr>\n";
-			print "<td class='base' colspan='2'>$Lang::tr{'guardian no entries'}</td>\n";
+			print "<td class='base' colspan='6'>$Lang::tr{'guardian no entries'}</td>\n";
 			print "</tr>\n";
 		}
 
@@ -1214,8 +1223,6 @@ END
 	# Section to add new elements or edit existing ones.
 	print <<END;
 	<br>
-	<hr>
-	<br>
 
 	<form method='post' action='$ENV{'SCRIPT_NAME'}'>
 		<div align='right'>
@@ -1240,11 +1247,11 @@ END
 	&Header::openbox('100%', 'center', $Lang::tr{'ids ignored hosts'});
 
 	print <<END;
-	<table width='100%'>
+	<table class='tbl'>
 		<tr>
-			<td class='base' bgcolor='$color{'color20'}'><b>$Lang::tr{'ip address'}</b></td>
-			<td class='base' bgcolor='$color{'color20'}'><b>$Lang::tr{'remark'}</b></td>
-			<td class='base' colspan='3' bgcolor='$color{'color20'}'></td>
+			<th>$Lang::tr{'ip address'}</td>
+			<th>$Lang::tr{'remark'}</td>
+			<th colspan='3'></td>
 		</tr>
 END
 		# Check if some hosts have been added to be ignored.
@@ -1252,7 +1259,7 @@ END
 			my $col = "";
 
 			# Loop through all entries of the hash.
-			while( (my $key) = each %ignored)  {
+			foreach my $key (sort { $ignored{$a}[0] <=> $ignored{$b}[0] } keys %ignored)  {
 				# Assign data array positions to some nice variable names.
 				my $address = $ignored{$key}[0];
 				my $remark = $ignored{$key}[1];
@@ -1261,10 +1268,6 @@ END
 				# Check if the key (id) number is even or not.
 				if ($cgiparams{'ID'} eq $key) {
 					$col="bgcolor='${Header::colouryellow}'";
-				} elsif ($key % 2) {
-					$col="bgcolor='$color{'color22'}'";
-				} else {
-					$col="bgcolor='$color{'color20'}'";
 				}
 
 				# Choose icon for the checkbox.
@@ -1282,8 +1285,8 @@ END
 
 print <<END;
 				<tr>
-					<td width='20%' class='base' $col>$address</td>
-					<td width='65%' class='base' $col>$remark</td>
+					<td width='20%' $col>$address</td>
+					<td width='65%' $col>$remark</td>
 
 					<td align='center' $col>
 						<form method='post' action='$ENV{'SCRIPT_NAME'}'>
@@ -1314,7 +1317,7 @@ END
 			} else {
 				# Print notice that currently no hosts are ignored.
 				print "<tr>\n";
-				print "<td class='base' colspan='2'>$Lang::tr{'guardian no entries'}</td>\n";
+				print "<td class='base' colspan='5'>$Lang::tr{'guardian no entries'}</td>\n";
 				print "</tr>\n";
 			}
 
@@ -1322,12 +1325,10 @@ END
 
 		# Section to add new elements or edit existing ones.
 print <<END;
-		<br>
-		<hr>
-		<br>
+		<form method='post' action='$ENV{'SCRIPT_NAME'}'>
+			<input type='hidden' name='ID' value='$cgiparams{'ID'}'>
 
-		<div align='center'>
-			<table width='100%'>
+			<table class='form'>
 END
 
 		# Assign correct headline and button text.
@@ -1338,30 +1339,36 @@ END
 		# Check if an ID (key) has been given, in this case an existing entry should be edited.
 		if ($cgiparams{'ID'} ne '') {
 			$buttontext = $Lang::tr{'update'};
-				print "<tr><td class='boldbase' colspan='3'><b>$Lang::tr{'update'}</b></td></tr>\n";
+				print "<tr><td colspan='2'><h6>$Lang::tr{'update'}</h6></td></tr>\n";
 
 				# Grab address and remark for the given key.
 				$entry_address = $ignored{$cgiparams{'ID'}}[0];
 				$entry_remark = $ignored{$cgiparams{'ID'}}[1];
 			} else {
 				$buttontext = $Lang::tr{'add'};
-				print "<tr><td class='boldbase' colspan='3'><b>$Lang::tr{'dnsforward add a new entry'}</b></td></tr>\n";
+				print "<tr><td colspan='2'><h6>$Lang::tr{'dnsforward add a new entry'}</h6></td></tr>\n";
 			}
 
 print <<END;
-				<form method='post' action='$ENV{'SCRIPT_NAME'}'>
-				<input type='hidden' name='ID' value='$cgiparams{'ID'}'>
 				<tr>
-					<td width='30%'>$Lang::tr{'ip address'}: </td>
-					<td width='50%'><input type='text' name='IGNORE_ENTRY_ADDRESS' value='$entry_address' size='24' /></td>
+					<td>$Lang::tr{'ip address'}</td>
+					<td>
+						<input type='text' name='IGNORE_ENTRY_ADDRESS' value='$entry_address' size='24' />
+					</td>
+				</tr>
+
+				<tr>
+					<td>$Lang::tr{'remark'}</td>
+					<td>
+						<input type='text' name=IGNORE_ENTRY_REMARK value='$entry_remark' size='24' />
+					</td>
+				</tr>
 
-					<td width='30%'>$Lang::tr{'remark'}: </td>
-					<td wicth='50%'><input type='text' name=IGNORE_ENTRY_REMARK value='$entry_remark' size='24' /></td>
-					<td align='center' width='20%'><input type='submit' name='WHITELIST' value='$buttontext' /></td>
+				<tr class='action'>
+					<td colspan='2'><input type='submit' name='WHITELIST' value='$buttontext' /></td>
 				</tr>
-				</form>
 			</table>
-		</div>
+		</form>
 END
 
 	&Header::closebox();
diff --git a/langs/de/cgi-bin/de.pl b/langs/de/cgi-bin/de.pl
index a718228bc..0598952ca 100644
--- a/langs/de/cgi-bin/de.pl
+++ b/langs/de/cgi-bin/de.pl
@@ -503,6 +503,7 @@
 'broken pipe' => 'Zerbrochene Pipe',
 'buffered memory' => 'Pufferspeicher    ',
 'buffers' => 'Puffer',
+'bypassed' => 'Übersprungen',
 'bytes' => 'Bytes',
 'bytes per second' => 'Bytes pro Sekunde',
 'bytes received' => 'Bytes empfangen',
@@ -1413,6 +1414,7 @@
 'ids ruleset autoupdate in progress' => 'Der Regelsatz wird gerade aktualisiert. Bitte warten Sie, bis dieser Vorgang erfolgreich beendet wurde...',
 'ids ruleset is up to date' => 'Regelset ist aktuell - Keine Aktualisierung notwendig.',
 'ids ruleset settings' => 'Regelsatzeinstellungen',
+'ids rulesets' => 'Regelsätze',
 'ids show' => 'Anzeigen',
 'ids the choosen provider is already in use' => 'Der gewhählte Provider wird bereits verwendet.',
 'ids unable to download the ruleset' => 'Das Regelset konnte nicht heruntergeladen werden.',
@@ -1571,6 +1573,7 @@
 'ipfire side is invalid' => 'IPFire Seite ist ungültig.',
 'ipfires hostname' => 'IPFire\'s Hostname',
 'ipinfo' => 'IP-Info',
+'ips throughput' => 'Durchsatz',
 'ipsec' => 'IPsec',
 'ipsec connection' => 'IPsec-Verbindung',
 'ipsec interface mode gre' => 'GRE',
@@ -1603,6 +1606,7 @@
 'languagepurpose' => 'Wählen Sie eine Sprache, in der IPFire angezeigt werden soll:',
 'last' => 'Letzte',
 'last activity' => 'Letzte Aktivität',
+'last updated' => 'Zuletzt Aktualisiert',
 'lateprompting' => 'Late prompting',
 'lease expires' => 'Zuordnung verfällt',
 'least preferred' => 'weniger präferiert',
@@ -2218,6 +2222,7 @@
 'save error' => 'Konfigurationsarchiv-Datei konnte nicht gespeichert werden',
 'save settings' => 'Einstellungen speichern',
 'save-adv-options' => 'Erweiterte Optionen speichern',
+'scanned' => 'Gescannt',
 'script name' => 'Skriptname:',
 'search' => 'Suchen',
 'secondary dns' => 'Sekundärer DNS-Server:',
@@ -2493,6 +2498,7 @@
 'tor traffic read written' => 'Gesamter Traffic (empfangen/gesendet)',
 'tor use exit nodes' => 'Nur diese Exitknoten benutzen (ein Fingerabdruck pro Zeile)',
 'tor use guard nodes' => 'Nur diese Guardknoten benutzen (ein Fingerabdruck pro Zeile)',
+'total' => 'Gesamt',
 'total connection time' => 'Gesamte Verbindungszeit',
 'total hits for log section' => 'Gesamte Treffer für Protokollsektion',
 'traffic back' => 'Zurück',
@@ -2936,6 +2942,7 @@
 'week-graph' => 'Woche',
 'weekly firewallhits' => 'wöchentliche Firewalltreffer',
 'weeks' => 'Wochen',
+'whitelisted' => 'Ausgenommen',
 'whois results from' => 'WHOIS-Ergebnisse von',
 'wildcards' => 'Wildcards',
 'wins server' => 'WINS-Server',
diff --git a/langs/en/cgi-bin/en.pl b/langs/en/cgi-bin/en.pl
index dca9f1645..91ea2e64a 100644
--- a/langs/en/cgi-bin/en.pl
+++ b/langs/en/cgi-bin/en.pl
@@ -524,6 +524,7 @@
 'broken pipe' => 'Broken pipe',
 'buffered memory' => 'Buffered Memory',
 'buffers' => 'buffers',
+'bypassed' => 'Bypassed',
 'bytes per second' => 'Bytes per Second',
 'bytes received' => 'Bytes Received',
 'bytes sent' => 'Bytes Sent',
@@ -1466,6 +1467,7 @@
 'ids ruleset autoupdate in progress' => 'Ruleset update in progress. Please wait until all operations have completed successfully...',
 'ids ruleset is up to date' => 'No update required - The ruleset is up to date.',
 'ids ruleset settings' => 'Ruleset Settings',
+'ids rulesets' => 'Rulesets',
 'ids show' => 'Show',
 'ids subscription code required' => 'The selected ruleset requires a subscription code',
 'ids the choosen provider is already in use' => 'The choosen provider is already in use.',
@@ -1625,6 +1627,7 @@
 'ipfire side is invalid' => 'IPFire side is invalid.',
 'ipfires hostname' => 'IPFire\'s Hostname',
 'ipinfo' => 'IP info',
+'ips throughput' => 'Throughput',
 'ipsec' => 'IPsec',
 'ipsec connection' => 'IPsec Connection',
 'ipsec dns server address is invalid' => 'Invalid DNS server IP address(es)',
@@ -1660,6 +1663,7 @@
 'languagepurpose' => 'Select the language you wish IPFire to display in:',
 'last' => 'Last',
 'last activity' => 'Last Activity',
+'last updated' => 'Last Updated',
 'lateprompting' => 'Lateprompting',
 'lease expires' => 'Lease expires',
 'least preferred' => 'least preferred',
@@ -2289,6 +2293,7 @@
 'save error' => 'Unable to save configuration archive file',
 'save settings' => 'Save settings',
 'save-adv-options' => 'Save advanced options',
+'scanned' => 'Scanned',
 'script name' => 'Script name:',
 'search' => 'Search',
 'secondary dns' => 'Secondary DNS:',
@@ -2573,6 +2578,7 @@
 'tor traffic read written' => 'Total traffic (read/written)',
 'tor use exit nodes' => 'Use only these exit nodes (one fingerprint per line)',
 'tor use guard nodes' => 'Use only these guard nodes (one fingerprint per line)',
+'total' => 'Total',
 'total connection time' => 'Total Connection Time',
 'total hits for log section' => 'Total hits for log section',
 'traffic back' => 'Back',
@@ -3020,6 +3026,8 @@
 'week-graph' => 'Week',
 'weekly firewallhits' => 'weekly firewallhits',
 'weeks' => 'Weeks',
+'wg' => 'WireGuard',
+'whitelisted' => 'Whitelisted',
 'whois results from' => 'WHOIS results from',
 'wildcards' => 'Wildcards',
 'winbind daemon' => 'Winbind Daemon',
diff --git a/lfs/suricata b/lfs/suricata
index 88f3c4575..dcee61ea1 100644
--- a/lfs/suricata
+++ b/lfs/suricata
@@ -132,5 +132,8 @@ $(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
 	# Install converter script needed for Core Update 167
 	install -m 0755 $(DIR_SRC)/config/suricata/convert-ids-backend-files /usr/sbin/convert-ids-backend-files
 
+	# Install the watcher
+	install -v -m 755 $(DIR_SRC)/config/suricata/suricata-watcher /usr/bin/suricata-watcher
+
 	@rm -rf $(DIR_APP)
 	@$(POSTBUILD)
diff --git a/src/initscripts/networking/functions.network b/src/initscripts/networking/functions.network
index e134d0cce..eb83b183d 100644
--- a/src/initscripts/networking/functions.network
+++ b/src/initscripts/networking/functions.network
@@ -54,6 +54,86 @@ bin2ip() {
 	echo "${address[*]}"
 }
 
+network_get_intfs() {
+	local zone="${1}"
+
+	case "${zone^^}" in
+		RED)
+			# For PPPoE, the RED interface is called ppp0 (unless we use QMI)
+			if [ "${RED_TYPE}" = "PPPOE" ] && [ "${RED_DRIVER}" != "qmi_wwan" ]; then
+				echo "ppp0"
+				return 0
+
+			# Otherwise we return RED_DEV
+			elif [ -n "${RED_DEV}" ]; then
+				echo "${RED_DEV}"
+				return 0
+			fi
+			;;
+
+		GREEN)
+			if [ -n "${GREEN_DEV}" ]; then
+				echo "${GREEN_DEV}"
+				return 0
+			fi
+			;;
+
+		ORANGE)
+			if [ -n "${ORANGE_DEV}" ]; then
+				echo "${ORANGE_DEV}"
+				return 0
+			fi
+			;;
+
+		BLUE)
+			if [ -n "${BLUE_DEV}" ]; then
+				echo "${BLUE_DEV}"
+				return 0
+			fi
+			;;
+
+		IPSEC)
+			local VARS=(
+				id status x1 x2 type x3 x4 x5 x6 x7 x8 x9 x10
+				x11 x12 x13 x14 x15 x16 x17 x18 x19 x20
+				x21 x22 x23 x24 x25 x26 x27 x28 x29 x30
+				x31 x32 x33 x34 interface_mode rest
+			)
+
+			while IFS="," read -r "${VARS[@]}"; do
+				# Check if the connection is enabled
+				[ "${status}" = "on" ] || continue
+
+				# Check if this a net-to-net connection
+				[ "${type}" = "net" ] || continue
+
+				# Determine the interface name
+				case "${interface_mode}" in
+					gre|vti)
+						echo "${interface_mode}${id}"
+						;;
+				esac
+			done < /var/ipfire/vpn/config
+
+			return 0
+			;;
+
+		WIREGUARD|WG)
+			echo "wg+"
+			return 0
+			;;
+
+		OPENVPN|OVPN)
+			# OpenVPN is using all tun devices
+			echo "tun+"
+			return 0
+			;;
+	esac
+
+	# Not found
+	return 1
+}
+
 network_get_address() {
 	local network="${1}"
 
diff --git a/src/initscripts/system/firewall b/src/initscripts/system/firewall
index 6727e4a20..139d94aa0 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
@@ -175,7 +160,7 @@ iptables_init() {
 	iptables -A CTOUTPUT -p icmp -m conntrack --ctstate RELATED -j ACCEPT
 
 	# Restore any connection marks
-	iptables -t mangle -A PREROUTING -j CONNMARK --restore-mark
+	iptables -t mangle -A PREROUTING -m mark --mark 0 -j CONNMARK --restore-mark
 
 	# Fix for braindead ISPs
 	iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
@@ -236,15 +221,6 @@ iptables_init() {
 	iptables -A FORWARD -i tun+ -j OVPNBLOCK
 	iptables -A FORWARD -o tun+ -j OVPNBLOCK
 
-	# IPS (Suricata) chains
-	iptables -N IPS_INPUT
-	iptables -N IPS_FORWARD
-	iptables -N 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
 	iptables -t nat -A POSTROUTING -j OVPNNAT
@@ -399,6 +375,22 @@ iptables_init() {
 			-m mark --mark "0x04000000/${NAT_MASK}" -j SNAT --to-source "${ORANGE_ADDRESS}"
 	fi
 
+	# IPS (Suricata) chains
+	iptables -t mangle -N IPS
+	iptables -t mangle -N IPS_CLEAR
+	iptables -t mangle -N IPS_SCAN_IN
+	iptables -t mangle -N IPS_SCAN_OUT
+
+	iptables -t mangle -A INPUT   -j IPS_SCAN_IN
+	iptables -t mangle -A FORWARD -j IPS_SCAN_IN
+	iptables -t mangle -A FORWARD -j IPS_SCAN_OUT
+	iptables -t mangle -A OUTPUT  -j IPS_SCAN_OUT
+
+	for chain in INPUT FORWARD OUTPUT; do
+		iptables -t mangle -A "${chain}" -j IPS
+		iptables -t mangle -A "${chain}" -j IPS_CLEAR
+	done
+
 	# RED chain, used for the red interface
 	iptables -N REDINPUT
 	iptables -A INPUT -j REDINPUT
diff --git a/src/initscripts/system/suricata b/src/initscripts/system/suricata
index 79f9478c3..a753e32e6 100644
--- a/src/initscripts/system/suricata
+++ b/src/initscripts/system/suricata
@@ -21,140 +21,150 @@
 
 . /etc/sysconfig/rc
 . ${rc_functions}
-
-PATH=/usr/local/sbin:/usr/local/bin:/bin:/usr/bin:/sbin:/usr/sbin; export PATH
+. /etc/init.d/networking/functions.network
 
 eval $(/usr/local/bin/readhash /var/ipfire/suricata/settings)
-eval $(/usr/local/bin/readhash /var/ipfire/ethernet/settings)
-
-# 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 "
+IPS_REPEAT_MARK="0x80000000"
+IPS_REPEAT_MASK="0x80000000"
 
-# Array containing the 4 possible network zones.
-network_zones=( red green blue orange ovpn )
+# The IPS requested that this connection is being bypassed
+IPS_BYPASS_REQUESTED_MARK="0x40000000"
+IPS_BYPASS_REQUESTED_MASK="0x40000000"
 
-# Array to store the network zones weather the IPS is enabled for.
-enabled_ips_zones=()
+# Marks a connection to be bypassed
+IPS_BYPASS_MARK="0x20000000"
+IPS_BYPASS_MASK="0x20000000"
 
-# PID file of suricata.
-PID_FILE="/var/run/suricata.pid"
+# Set if we request to scan this packet
+IPS_SCAN_MARK="0x10000000"
+IPS_SCAN_MASK="0x10000000"
 
-# Function to get the amount of CPU cores of the system.
-function get_cpu_count {
-	CPUCOUNT=0
+# Set if a packet has been whitelisted
+IPS_WHITELISTED_MARK="0x08000000"
+IPS_WHITELISTED_MASK="0x08000000"
 
-	# Loop through "/proc/cpuinfo" and count the amount of CPU cores.
-	while read line; do
-		[ "$line" ] && [ -z "${line%processor*}" ]  && ((CPUCOUNT++))
-	done </proc/cpuinfo
+# Supported network zones
+NETWORK_ZONES=( "RED" "GREEN" "ORANGE" "BLUE" "IPSEC" "WG" "OVPN" )
 
-	# Limit to a maximum of 16 cores, because suricata does not support more than
-	# 16 netfilter queues at the moment.
-	if [ $CPUCOUNT -gt "16" ]; then
-		echo "16"
-	else
-		echo $CPUCOUNT
-	fi
-}
+# Optional options for the Netfilter queue.
+NFQ_OPTS=(
+	"--queue-bypass"
+)
 
 # 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"
+flush_fw_chain() {
+	iptables -w -t mangle -F IPS
+	iptables -w -t mangle -F IPS_CLEAR
+	iptables -w -t mangle -F IPS_SCAN_IN
+	iptables -w -t mangle -F IPS_SCAN_OUT
 }
 
 # 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
-
+generate_fw_rules() {
 	# Assign NFQ_OPTS
-	NFQ_OPTIONS=$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))"
-		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
+	# Don't process packets where the IPS has requested to bypass the stream
+	iptables -w -t mangle -A IPS \
+		-m comment --comment "BYPASSED" \
+		-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
+	for chain in IPS IPS_SCAN_IN IPS_SCAN_OUT; do
+		iptables -w -t mangle -A "${chain}" \
+			-m mark --mark "$(( IPS_REPEAT_MARK ))/$(( IPS_REPEAT_MASK ))" -j RETURN
+	done
+
+	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
+			# Handle IPsec packets
+			case "${zone}" in
+				IPSEC)
+					iptables -w -t mangle -A IPS_SCAN_IN \
+						-m policy --pol ipsec --dir in -j MARK --set-mark "$(( IPS_SCAN_MARK ))/$(( IPS_SCAN_MASK ))"
+					iptables -w -t mangle -A IPS_SCAN_OUT \
+						-m policy --pol ipsec --dir out -j MARK --set-mark "$(( IPS_SCAN_MARK ))/$(( IPS_SCAN_MASK ))"
+					;;
+			esac
+
+			# Add interfaces
+			for intf in $(network_get_intfs "${zone}"); do
+				iptables -w -t mangle -A IPS_SCAN_IN \
+					-i "${intf}" -j MARK --set-mark "$(( IPS_SCAN_MARK ))/$(( IPS_SCAN_MASK ))"
+				iptables -w -t mangle -A IPS_SCAN_OUT \
+					-o "${intf}" -j MARK --set-mark "$(( IPS_SCAN_MARK ))/$(( IPS_SCAN_MASK ))"
 			done
-		done
+		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
+			# Skip disabled entries
+			[ "${enabled}" = "enabled" ] || continue
+
+			iptables -w -t mangle -A IPS -s "${network}" -j MARK --set-mark "$(( IPS_WHITELISTED_MARK ))/$(( IPS_WHITELISTED_MASK ))"
+			iptables -w -t mangle -A IPS -d "${network}" -j MARK --set-mark "$(( IPS_WHITELISTED_MARK ))/$(( IPS_WHITELISTED_MASK ))"
+		done < "/var/ipfire/suricata/ignored"
 	fi
+
+	# Count and skip the whitelisted packets
+	iptables -w -t mangle -A IPS \
+		-m comment --comment "WHITELISTED" \
+		-m mark --mark "$(( IPS_WHITELISTED_MARK ))/$(( IPS_WHITELISTED_MASK ))" -j RETURN
+
+	# Send packets to suricata
+	iptables -w -t mangle -A IPS -m comment --comment "SCANNED" -j NFQUEUE "${NFQ_OPTIONS[@]}"
+
+	# Clear all bits again after packets have been sent to the IPS
+	# This is required so that encapsulated packets can't inherit any set bits here and won't be scanned.
+	iptables -w -t mangle -A IPS_CLEAR \
+			-j MARK --set-mark "0/$(( IPS_BYPASS_MASK | IPS_BYPASS_REQUESTED_MASK | IPS_REPEAT_MASK | IPS_SCAN_MASK ))"
+
+	return 0
 }
 
 case "$1" in
         start)
-		# Get amount of CPU cores.
-		cpu_count=$(get_cpu_count)
+		# Get amount of CPU cores
+		cpu_count="$(getconf _NPROCESSORS_ONLN)"
 
 		# Numer of NFQUES.
 		NFQUEUES="-q 0"
@@ -167,11 +177,7 @@ case "$1" in
 		if [ "$ENABLE_IDS" == "on" ]; then
 			# Start the IDS.
 			boot_mesg "Starting Intrusion Detection System..."
-			/usr/bin/suricata -c /etc/suricata/suricata.yaml -D $NFQUEUES >/dev/null 2>/dev/null
-			evaluate_retval
-
-			# Allow reading the pidfile.
-			chmod 644 $PID_FILE
+			loadproc -b /usr/bin/suricata-watcher -c /etc/suricata/suricata.yaml $NFQUEUES
 
 			# Flush the firewall chain
 			flush_fw_chain
@@ -183,32 +189,24 @@ case "$1" in
 
         stop)
 		boot_mesg "Stopping Intrusion Detection System..."
-		killproc -p $PID_FILE /var/run
+		killproc -p /var/run/suricata.pid /usr/bin/suricata
 
 		# Flush firewall chain.
 		flush_fw_chain
 
-		# Sometimes suricata not correct shutdown. So killall.
-		killall -KILL /usr/bin/suricata 2>/dev/null
-
-		# Remove suricata control socket.
-		rm /var/run/suricata/* >/dev/null 2>/dev/null
-
-		# Trash remain pid file if still exists.
-		rm -f $PID_FILE >/dev/null 2>/dev/null
-
 		# Don't report returncode of rm if suricata was not started
 		exit 0
         ;;
 
         status)
-                statusproc /usr/bin/suricata
+                PIDFILE="/var/run/suricata.pid" statusproc /usr/bin/suricata
                 ;;
 
         restart)
                 $0 stop
                 $0 start
                 ;;
+
 	reload)
 		# Send SIGUSR2 to the suricata process to perform a reload
 		# of the ruleset.
@@ -226,5 +224,3 @@ case "$1" in
                 exit 1
                 ;;
 esac
-
-chmod 644 /var/log/suricata/* 2>/dev/null


hooks/post-receive
--
IPFire 2.x development tree

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2024-09-24  8:54 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-09-24  8:54 [git.ipfire.org] IPFire 2.x development tree branch, master, updated. 84b04cb6d38eb0ca0fca426e4d6e0c0a2c467d9e Michael Tremer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox