summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Fort <nicolasfort1988@gmail.com>2022-05-11 16:41:21 +0000
committerNicolas Fort <nicolasfort1988@gmail.com>2022-05-11 16:41:21 +0000
commit1ca645d1a499441abb74c549e7e1fbd03087097d (patch)
tree9057243e8ff6c3450b7b91496672732c117d3b57
parent432fd1b5e7b5a1e5b8503bf0dcd106369e323dc7 (diff)
downloadvyos-1x-1ca645d1a499441abb74c549e7e1fbd03087097d.tar.gz
vyos-1x-1ca645d1a499441abb74c549e7e1fbd03087097d.zip
Firewall: T3907: add log-level options in firewall
-rw-r--r--interface-definitions/include/firewall/common-rule.xml.i20
-rw-r--r--interface-definitions/include/firewall/name-default-log.xml.i43
-rw-r--r--interface-definitions/include/firewall/rule-log-level.xml.i45
-rw-r--r--python/vyos/firewall.py5
-rw-r--r--python/vyos/template.py3
-rwxr-xr-xsmoketest/scripts/cli/test_firewall.py17
-rwxr-xr-xsrc/migration-scripts/firewall/6-to-727
7 files changed, 130 insertions, 30 deletions
diff --git a/interface-definitions/include/firewall/common-rule.xml.i b/interface-definitions/include/firewall/common-rule.xml.i
index 2a5137dbf..0b8838872 100644
--- a/interface-definitions/include/firewall/common-rule.xml.i
+++ b/interface-definitions/include/firewall/common-rule.xml.i
@@ -76,25 +76,7 @@
</leafNode>
</children>
</node>
-<leafNode name="log">
- <properties>
- <help>Option to log packets matching rule</help>
- <completionHelp>
- <list>enable disable</list>
- </completionHelp>
- <valueHelp>
- <format>enable</format>
- <description>Enable log</description>
- </valueHelp>
- <valueHelp>
- <format>disable</format>
- <description>Disable log</description>
- </valueHelp>
- <constraint>
- <regex>(enable|disable)</regex>
- </constraint>
- </properties>
-</leafNode>
+#include <include/firewall/rule-log-level.xml.i>
<node name="connection-status">
<properties>
<help>Connection status</help>
diff --git a/interface-definitions/include/firewall/name-default-log.xml.i b/interface-definitions/include/firewall/name-default-log.xml.i
index 979395146..c3f6f0171 100644
--- a/interface-definitions/include/firewall/name-default-log.xml.i
+++ b/interface-definitions/include/firewall/name-default-log.xml.i
@@ -1,8 +1,45 @@
<!-- include start from firewall/name-default-log.xml.i -->
<leafNode name="enable-default-log">
<properties>
- <help>Option to log packets hitting default-action</help>
- <valueless/>
+ <help>Option to log packets matching default-action</help>
+ <completionHelp>
+ <list>emerg alert crit err warn notice info debug</list>
+ </completionHelp>
+ <valueHelp>
+ <format>emerg</format>
+ <description>Emerg log level</description>
+ </valueHelp>
+ <valueHelp>
+ <format>alert</format>
+ <description>Alert log level</description>
+ </valueHelp>
+ <valueHelp>
+ <format>crit</format>
+ <description>Critical log level</description>
+ </valueHelp>
+ <valueHelp>
+ <format>err</format>
+ <description>Error log level</description>
+ </valueHelp>
+ <valueHelp>
+ <format>warn</format>
+ <description>Warning log level</description>
+ </valueHelp>
+ <valueHelp>
+ <format>notice</format>
+ <description>Notice log level</description>
+ </valueHelp>
+ <valueHelp>
+ <format>info</format>
+ <description>Info log level</description>
+ </valueHelp>
+ <valueHelp>
+ <format>debug</format>
+ <description>Debug log level</description>
+ </valueHelp>
+ <constraint>
+ <regex>(emerg|alert|crit|err|warn|notice|info|debug)</regex>
+ </constraint>
</properties>
</leafNode>
-<!-- include end -->
+<!-- include end --> \ No newline at end of file
diff --git a/interface-definitions/include/firewall/rule-log-level.xml.i b/interface-definitions/include/firewall/rule-log-level.xml.i
new file mode 100644
index 000000000..4842b73ca
--- /dev/null
+++ b/interface-definitions/include/firewall/rule-log-level.xml.i
@@ -0,0 +1,45 @@
+<!-- include start from firewall/common-rule.xml.i -->
+<leafNode name="log">
+ <properties>
+ <help>Option to log packets matching rule</help>
+ <completionHelp>
+ <list>emerg alert crit err warn notice info debug</list>
+ </completionHelp>
+ <valueHelp>
+ <format>emerg</format>
+ <description>Emerg log level</description>
+ </valueHelp>
+ <valueHelp>
+ <format>alert</format>
+ <description>Alert log level</description>
+ </valueHelp>
+ <valueHelp>
+ <format>crit</format>
+ <description>Critical log level</description>
+ </valueHelp>
+ <valueHelp>
+ <format>err</format>
+ <description>Error log level</description>
+ </valueHelp>
+ <valueHelp>
+ <format>warn</format>
+ <description>Warning log level</description>
+ </valueHelp>
+ <valueHelp>
+ <format>notice</format>
+ <description>Notice log level</description>
+ </valueHelp>
+ <valueHelp>
+ <format>info</format>
+ <description>Info log level</description>
+ </valueHelp>
+ <valueHelp>
+ <format>debug</format>
+ <description>Debug log level</description>
+ </valueHelp>
+ <constraint>
+ <regex>(emerg|alert|crit|err|warn|notice|info|debug)</regex>
+ </constraint>
+ </properties>
+</leafNode>
+<!-- include end --> \ No newline at end of file
diff --git a/python/vyos/firewall.py b/python/vyos/firewall.py
index 04fd44173..0c6811d72 100644
--- a/python/vyos/firewall.py
+++ b/python/vyos/firewall.py
@@ -146,9 +146,10 @@ def parse_rule(rule_conf, fw_name, rule_id, ip_name):
output.append(f'{proto} {prefix}port {operator} $P_{group_name}')
- if 'log' in rule_conf and rule_conf['log'] == 'enable':
+ if 'log' in rule_conf:
action = rule_conf['action'] if 'action' in rule_conf else 'accept'
- output.append(f'log prefix "[{fw_name[:19]}-{rule_id}-{action[:1].upper()}] "')
+ log_level = rule_conf['log']
+ output.append(f'log prefix "[{fw_name[:19]}-{rule_id}-{action[:1].upper()}]" level {log_level}')
if 'hop_limit' in rule_conf:
operators = {'eq': '==', 'gt': '>', 'lt': '<'}
diff --git a/python/vyos/template.py b/python/vyos/template.py
index 132f5ddde..b41525421 100644
--- a/python/vyos/template.py
+++ b/python/vyos/template.py
@@ -554,7 +554,8 @@ def nft_default_rule(fw_conf, fw_name):
if 'enable_default_log' in fw_conf:
action_suffix = default_action[:1].upper()
- output.append(f'log prefix "[{fw_name[:19]}-default-{action_suffix}] "')
+ log_level = fw_conf['enable_default_log']
+ output.append(f'log prefix "[{fw_name[:19]}-default-{action_suffix}]" level {log_level}')
output.append(nft_action(default_action))
output.append(f'comment "{fw_name} default-action {default_action}"')
diff --git a/smoketest/scripts/cli/test_firewall.py b/smoketest/scripts/cli/test_firewall.py
index b8f944575..7b9691d9d 100755
--- a/smoketest/scripts/cli/test_firewall.py
+++ b/smoketest/scripts/cli/test_firewall.py
@@ -91,12 +91,15 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):
def test_basic_rules(self):
self.cli_set(['firewall', 'name', 'smoketest', 'default-action', 'drop'])
+ self.cli_set(['firewall', 'name', 'smoketest', 'enable-default-log', 'info'])
self.cli_set(['firewall', 'name', 'smoketest', 'rule', '1', 'action', 'accept'])
self.cli_set(['firewall', 'name', 'smoketest', 'rule', '1', 'source', 'address', '172.16.20.10'])
self.cli_set(['firewall', 'name', 'smoketest', 'rule', '1', 'destination', 'address', '172.16.10.10'])
+ self.cli_set(['firewall', 'name', 'smoketest', 'rule', '1', 'log', 'debug'])
self.cli_set(['firewall', 'name', 'smoketest', 'rule', '2', 'action', 'reject'])
self.cli_set(['firewall', 'name', 'smoketest', 'rule', '2', 'protocol', 'tcp'])
self.cli_set(['firewall', 'name', 'smoketest', 'rule', '2', 'destination', 'port', '8888'])
+ self.cli_set(['firewall', 'name', 'smoketest', 'rule', '2', 'log', 'err'])
self.cli_set(['firewall', 'name', 'smoketest', 'rule', '2', 'tcp', 'flags', 'syn'])
self.cli_set(['firewall', 'name', 'smoketest', 'rule', '2', 'tcp', 'flags', 'not', 'ack'])
self.cli_set(['firewall', 'name', 'smoketest', 'rule', '3', 'action', 'accept'])
@@ -110,10 +113,10 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):
nftables_search = [
['iifname "eth0"', 'jump NAME_smoketest'],
- ['saddr 172.16.20.10', 'daddr 172.16.10.10', 'return'],
- ['tcp flags & (syn | ack) == syn', 'tcp dport { 8888 }', 'reject'],
+ ['saddr 172.16.20.10', 'daddr 172.16.10.10', 'log prefix "[smoketest-1-A]" level debug','return'],
+ ['tcp flags & (syn | ack) == syn', 'tcp dport { 8888 }', 'log prefix "[smoketest-2-R]" level err', 'reject'],
['tcp dport { 22 }', 'limit rate 5/minute', 'return'],
- ['smoketest default-action', 'drop']
+ ['log prefix "[smoketest-default-D]" level info','smoketest default-action', 'drop']
]
nftables_output = cmd('sudo nft list table ip filter')
@@ -128,9 +131,13 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):
def test_basic_rules_ipv6(self):
self.cli_set(['firewall', 'ipv6-name', 'v6-smoketest', 'default-action', 'drop'])
+ self.cli_set(['firewall', 'ipv6-name', 'v6-smoketest', 'enable-default-log', 'emerg'])
+
self.cli_set(['firewall', 'ipv6-name', 'v6-smoketest', 'rule', '1', 'action', 'accept'])
self.cli_set(['firewall', 'ipv6-name', 'v6-smoketest', 'rule', '1', 'source', 'address', '2002::1'])
self.cli_set(['firewall', 'ipv6-name', 'v6-smoketest', 'rule', '1', 'destination', 'address', '2002::1:1'])
+ self.cli_set(['firewall', 'ipv6-name', 'v6-smoketest', 'rule', '1', 'log', 'crit'])
+
self.cli_set(['firewall', 'ipv6-name', 'v6-smoketest', 'rule', '2', 'action', 'reject'])
self.cli_set(['firewall', 'ipv6-name', 'v6-smoketest', 'rule', '2', 'protocol', 'tcp_udp'])
self.cli_set(['firewall', 'ipv6-name', 'v6-smoketest', 'rule', '2', 'destination', 'port', '8888'])
@@ -141,9 +148,9 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):
nftables_search = [
['iifname "eth0"', 'jump NAME6_v6-smoketest'],
- ['saddr 2002::1', 'daddr 2002::1:1', 'return'],
+ ['saddr 2002::1', 'daddr 2002::1:1', 'log prefix "[v6-smoketest-1-A]" level crit', 'return'],
['meta l4proto { tcp, udp }', 'th dport { 8888 }', 'reject'],
- ['smoketest default-action', 'drop']
+ ['smoketest default-action', 'log prefix "[v6-smoketest-default-D]" level emerg', 'drop']
]
nftables_output = cmd('sudo nft list table ip6 filter')
diff --git a/src/migration-scripts/firewall/6-to-7 b/src/migration-scripts/firewall/6-to-7
index 5f4cff90d..1e698da0b 100755
--- a/src/migration-scripts/firewall/6-to-7
+++ b/src/migration-scripts/firewall/6-to-7
@@ -19,6 +19,11 @@
# utc: nftables userspace uses localtime and calculates the UTC offset automatically
# icmp/v6: migrate previously available `type-name` to valid type/code
# T4178: Update tcp flags to use multi value node
+# T3907: Add log levels
+# `enable-default-log` --> `enable-default-log warn`
+# `rule X log enable` --> `rule X log warn`
+# `rule X log disable` --> No log config
+
import re
@@ -100,6 +105,9 @@ icmpv6_translations = {
if config.exists(base + ['name']):
for name in config.list_nodes(base + ['name']):
+ if config.exists(base + ['name', name, 'enable-default-log']):
+ config.set(base + ['name', name, 'enable-default-log'], value='warn')
+
if not config.exists(base + ['name', name, 'rule']):
continue
@@ -108,6 +116,7 @@ if config.exists(base + ['name']):
rule_time = base + ['name', name, 'rule', rule, 'time']
rule_tcp_flags = base + ['name', name, 'rule', rule, 'tcp', 'flags']
rule_icmp = base + ['name', name, 'rule', rule, 'icmp']
+ rule_log = base + ['name', name, 'rule', rule, 'log']
if config.exists(rule_time + ['monthdays']):
config.delete(rule_time + ['monthdays'])
@@ -146,6 +155,13 @@ if config.exists(base + ['name']):
config.set(rule_icmp + ['type'], value=translate[0])
config.set(rule_icmp + ['code'], value=translate[1])
+ if config.exists(rule_log):
+ tmp = config.return_value(rule_log)
+ if tmp == 'disable':
+ config.delete(rule_log)
+ else:
+ config.set(rule_log, value='warn')
+
for src_dst in ['destination', 'source']:
pg_base = base + ['name', name, 'rule', rule, src_dst, 'group', 'port-group']
proto_base = base + ['name', name, 'rule', rule, 'protocol']
@@ -153,6 +169,9 @@ if config.exists(base + ['name']):
config.set(proto_base, value='tcp_udp')
if config.exists(base + ['ipv6-name']):
+ if config.exists(base + ['ipv6-name', name, 'enable-default-log']):
+ config.set(base + ['ipv6-name', name, 'enable-default-log'], value='warn')
+
for name in config.list_nodes(base + ['ipv6-name']):
if not config.exists(base + ['ipv6-name', name, 'rule']):
continue
@@ -162,6 +181,7 @@ if config.exists(base + ['ipv6-name']):
rule_time = base + ['ipv6-name', name, 'rule', rule, 'time']
rule_tcp_flags = base + ['ipv6-name', name, 'rule', rule, 'tcp', 'flags']
rule_icmp = base + ['ipv6-name', name, 'rule', rule, 'icmpv6']
+ rule_log = base + ['ipv6-name', name, 'rule', rule, 'log']
if config.exists(rule_time + ['monthdays']):
config.delete(rule_time + ['monthdays'])
@@ -212,6 +232,13 @@ if config.exists(base + ['ipv6-name']):
else:
config.rename(rule_icmp + ['type'], 'type-name')
+ if config.exists(rule_log):
+ tmp = config.return_value(rule_log)
+ if tmp == 'disable':
+ config.delete(rule_log)
+ else:
+ config.set(rule_log, value='warn')
+
for src_dst in ['destination', 'source']:
pg_base = base + ['ipv6-name', name, 'rule', rule, src_dst, 'group', 'port-group']
proto_base = base + ['ipv6-name', name, 'rule', rule, 'protocol']