diff options
-rw-r--r-- | data/templates/ids/fastnetmon.j2 | 11 | ||||
-rw-r--r-- | data/templates/ids/fastnetmon_networks_list.j2 | 4 | ||||
-rw-r--r-- | debian/vyos-1x.postinst | 4 | ||||
-rw-r--r-- | interface-definitions/service-ids-ddos-protection.xml.in | 22 | ||||
-rw-r--r-- | op-mode-definitions/monitor-log.xml.in | 15 | ||||
-rw-r--r-- | op-mode-definitions/show-log.xml.in | 15 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_service_ids.py | 14 | ||||
-rwxr-xr-x | src/conf_mode/service_ids_fastnetmon.py | 56 | ||||
-rw-r--r-- | src/etc/systemd/system/fastnetmon.service.d/override.conf | 12 |
9 files changed, 113 insertions, 40 deletions
diff --git a/data/templates/ids/fastnetmon.j2 b/data/templates/ids/fastnetmon.j2 index c482002fa..005338836 100644 --- a/data/templates/ids/fastnetmon.j2 +++ b/data/templates/ids/fastnetmon.j2 @@ -1,21 +1,22 @@ # enable this option if you want to send logs to local syslog facility +logging:logging_level = debug logging:local_syslog_logging = on # list of all your networks in CIDR format -networks_list_path = /etc/networks_list - -# list networks in CIDR format which will be not monitored for attacks -white_list_path = /etc/networks_whitelist +networks_list_path = /run/fastnetmon/networks_list # Enable/Disable any actions in case of attack enable_ban = on +enable_ban_ipv6 = on ## How many packets will be collected from attack traffic ban_details_records_count = 500 ## How long (in seconds) we should keep an IP in blocked state ## If you set 0 here it completely disables unban capability -ban_time = 1900 +{% if ban_time is vyos_defined %} +ban_time = {{ ban_time }} +{% endif %} # Check if the attack is still active, before triggering an unban callback with this option # If the attack is still active, check each run of the unban watchdog diff --git a/data/templates/ids/fastnetmon_networks_list.j2 b/data/templates/ids/fastnetmon_networks_list.j2 index 1c81180be..5f1b3ba4d 100644 --- a/data/templates/ids/fastnetmon_networks_list.j2 +++ b/data/templates/ids/fastnetmon_networks_list.j2 @@ -1,6 +1,4 @@ -{% if network is vyos_defined(var_type=str) %} -{{ network }} -{% else %} +{% if network is vyos_defined() %} {% for net in network %} {{ net }} {% endfor %} diff --git a/debian/vyos-1x.postinst b/debian/vyos-1x.postinst index da935bd4c..81121bfe9 100644 --- a/debian/vyos-1x.postinst +++ b/debian/vyos-1x.postinst @@ -88,8 +88,10 @@ fi # Remove unwanted daemon files from /etc # conntackd +# pmacct +# fastnetmon DELETE="/etc/logrotate.d/conntrackd.distrib /etc/init.d/conntrackd /etc/default/conntrackd - /etc/default/pmacctd /etc/pmacct" + /etc/default/pmacctd /etc/pmacct /etc/networks_list /etc/fastnetmon.conf" for file in $DELETE; do if [ -f ${file} ]; then rm -f ${file} diff --git a/interface-definitions/service-ids-ddos-protection.xml.in b/interface-definitions/service-ids-ddos-protection.xml.in index 5e65d3106..a176d6fff 100644 --- a/interface-definitions/service-ids-ddos-protection.xml.in +++ b/interface-definitions/service-ids-ddos-protection.xml.in @@ -18,6 +18,19 @@ <help>Path to fastnetmon alert script</help> </properties> </leafNode> + <leafNode name="ban-time"> + <properties> + <help>How long we should keep an IP in blocked state</help> + <valueHelp> + <format>u32:1-4294967294</format> + <description>Time in seconds</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 1-4294967294"/> + </constraint> + </properties> + <defaultValue>1900</defaultValue> + </leafNode> <leafNode name="direction"> <properties> <help>Direction for processing traffic</help> @@ -55,13 +68,18 @@ </node> <leafNode name="network"> <properties> - <help>Define monitoring networks</help> + <help>Specify IPv4 and IPv6 networks which belong to you</help> <valueHelp> <format>ipv4net</format> - <description>Processed network</description> + <description>Your IPv4 prefix(es)</description> + </valueHelp> + <valueHelp> + <format>ipv6net</format> + <description>Your IPv6 prefix(es)</description> </valueHelp> <constraint> <validator name="ipv4-prefix"/> + <validator name="ipv6-prefix"/> </constraint> <multi/> </properties> diff --git a/op-mode-definitions/monitor-log.xml.in b/op-mode-definitions/monitor-log.xml.in index f5e0ede59..99d64acb3 100644 --- a/op-mode-definitions/monitor-log.xml.in +++ b/op-mode-definitions/monitor-log.xml.in @@ -14,6 +14,19 @@ </properties> <command>grc journalctl --no-hostname --follow --boot</command> </node> + <node name="ids"> + <properties> + <help>Monitor log for Intrusion Detection System</help> + </properties> + <children> + <leafNode name="ddos-protection"> + <properties> + <help>Monitor last lines of DDOS protection</help> + </properties> + <command>journalctl --no-hostname --follow --boot --unit fastnetmon.service</command> + </leafNode> + </children> + </node> <node name="dhcp"> <properties> <help>Monitor last lines of Dynamic Host Control Protocol (DHCP)</help> @@ -111,7 +124,7 @@ </node> <node name="protocol"> <properties> - <help>Monitor log for Routing Protocols</help> + <help>Monitor log for Routing Protocol</help> </properties> <children> <leafNode name="ospf"> diff --git a/op-mode-definitions/show-log.xml.in b/op-mode-definitions/show-log.xml.in index 76879e5d6..ab9e128a8 100644 --- a/op-mode-definitions/show-log.xml.in +++ b/op-mode-definitions/show-log.xml.in @@ -32,6 +32,19 @@ </properties> <command>journalctl --no-hostname --boot --unit conntrackd.service</command> </leafNode> + <node name="ids"> + <properties> + <help>Show log for for Intrusion Detection System</help> + </properties> + <children> + <leafNode name="ddos-protection"> + <properties> + <help>Show log for DDOS protection</help> + </properties> + <command>journalctl --no-hostname --boot --unit fastnetmon.service</command> + </leafNode> + </children> + </node> <node name="dhcp"> <properties> <help>Show log for Dynamic Host Control Protocol (DHCP)</help> @@ -243,7 +256,7 @@ </node> <node name="protocol"> <properties> - <help>Show log for Routing Protocols</help> + <help>Show log for Routing Protocol</help> </properties> <children> <leafNode name="ospf"> diff --git a/smoketest/scripts/cli/test_service_ids.py b/smoketest/scripts/cli/test_service_ids.py index 18f1b8ec5..8720362ba 100755 --- a/smoketest/scripts/cli/test_service_ids.py +++ b/smoketest/scripts/cli/test_service_ids.py @@ -24,7 +24,8 @@ from vyos.util import process_named_running from vyos.util import read_file PROCESS_NAME = 'fastnetmon' -FASTNETMON_CONF = '/etc/fastnetmon.conf' +FASTNETMON_CONF = '/run/fastnetmon/fastnetmon.conf' +NETWORKS_CONF = '/run/fastnetmon/networks_list' base_path = ['service', 'ids', 'ddos-protection'] class TestServiceIDS(VyOSUnitTestSHIM.TestCase): @@ -48,7 +49,7 @@ class TestServiceIDS(VyOSUnitTestSHIM.TestCase): self.assertFalse(process_named_running(PROCESS_NAME)) def test_fastnetmon(self): - networks = ['10.0.0.0/24', '10.5.5.0/24'] + networks = ['10.0.0.0/24', '10.5.5.0/24', '2001:db8:10::/64', '2001:db8:20::/64'] interfaces = ['eth0', 'eth1'] fps = '3500' mbps = '300' @@ -86,9 +87,18 @@ class TestServiceIDS(VyOSUnitTestSHIM.TestCase): self.assertIn(f'threshold_mbps = {mbps}', config) self.assertIn(f'ban_for_pps = on', config) self.assertIn(f'threshold_pps = {pps}', config) + # default + self.assertIn(f'enable_ban = on', config) + self.assertIn(f'enable_ban_ipv6 = on', config) + self.assertIn(f'ban_time = 1900', config) tmp = ','.join(interfaces) self.assertIn(f'interfaces = {tmp}', config) + + network_config = read_file(NETWORKS_CONF) + for tmp in networks: + self.assertIn(f'{tmp}', network_config) + if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/src/conf_mode/service_ids_fastnetmon.py b/src/conf_mode/service_ids_fastnetmon.py index ae7e582ec..615658c84 100755 --- a/src/conf_mode/service_ids_fastnetmon.py +++ b/src/conf_mode/service_ids_fastnetmon.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2018-2020 VyOS maintainers and contributors +# Copyright (C) 2018-2022 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as @@ -19,14 +19,16 @@ import os from sys import exit from vyos.config import Config -from vyos import ConfigError -from vyos.util import call +from vyos.configdict import dict_merge from vyos.template import render +from vyos.util import call +from vyos.xml import defaults +from vyos import ConfigError from vyos import airbag airbag.enable() -config_file = r'/etc/fastnetmon.conf' -networks_list = r'/etc/networks_list' +config_file = r'/run/fastnetmon/fastnetmon.conf' +networks_list = r'/run/fastnetmon/networks_list' def get_config(config=None): if config: @@ -34,50 +36,54 @@ def get_config(config=None): else: conf = Config() base = ['service', 'ids', 'ddos-protection'] + if not conf.exists(base): + return None + fastnetmon = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True) + # We have gathered the dict representation of the CLI, but there are default + # options which we need to update into the dictionary retrived. + default_values = defaults(base) + fastnetmon = dict_merge(default_values, fastnetmon) + return fastnetmon def verify(fastnetmon): if not fastnetmon: return None - if not "mode" in fastnetmon: - raise ConfigError('ddos-protection mode is mandatory!') - - if not "network" in fastnetmon: - raise ConfigError('Required define network!') + if 'mode' not in fastnetmon: + raise ConfigError('Specify operating mode!') - if not "listen_interface" in fastnetmon: - raise ConfigError('Define listen-interface is mandatory!') + if 'listen_interface' not in fastnetmon: + raise ConfigError('Specify interface(s) for traffic capture') - if "alert_script" in fastnetmon: - if os.path.isfile(fastnetmon["alert_script"]): + if 'alert_script' in fastnetmon: + if os.path.isfile(fastnetmon['alert_script']): # Check script permissions - if not os.access(fastnetmon["alert_script"], os.X_OK): - raise ConfigError('Script {0} does not have permissions for execution'.format(fastnetmon["alert_script"])) + if not os.access(fastnetmon['alert_script'], os.X_OK): + raise ConfigError('Script "{alert_script}" is not executable!'.format(fastnetmon['alert_script'])) else: - raise ConfigError('File {0} does not exists!'.format(fastnetmon["alert_script"])) + raise ConfigError('File "{alert_script}" does not exists!'.format(fastnetmon)) def generate(fastnetmon): if not fastnetmon: - if os.path.isfile(config_file): - os.unlink(config_file) - if os.path.isfile(networks_list): - os.unlink(networks_list) + for file in [config_file, networks_list]: + if os.path.isfile(file): + os.unlink(file) - return + return None render(config_file, 'ids/fastnetmon.j2', fastnetmon) render(networks_list, 'ids/fastnetmon_networks_list.j2', fastnetmon) - return None def apply(fastnetmon): + systemd_service = 'fastnetmon.service' if not fastnetmon: # Stop fastnetmon service if removed - call('systemctl stop fastnetmon.service') + call(f'systemctl stop {systemd_service}') else: - call('systemctl restart fastnetmon.service') + call(f'systemctl reload-or-restart {systemd_service}') return None diff --git a/src/etc/systemd/system/fastnetmon.service.d/override.conf b/src/etc/systemd/system/fastnetmon.service.d/override.conf new file mode 100644 index 000000000..8f7f3774f --- /dev/null +++ b/src/etc/systemd/system/fastnetmon.service.d/override.conf @@ -0,0 +1,12 @@ +[Unit] +RequiresMountsFor=/run +ConditionPathExists=/run/fastnetmon/fastnetmon.conf +After= +After=vyos-router.service + +[Service] +Type=simple +WorkingDirectory=/run/fastnetmon +PIDFile=/run/fastnetmon/fastnetmon.pid +ExecStart= +ExecStart=/usr/sbin/fastnetmon --configuration_file /run/fastnetmon/fastnetmon.conf |