diff options
author | Nicolas Fort <nicolasfort1988@gmail.com> | 2022-08-27 15:35:52 +0000 |
---|---|---|
committer | Nicolas Fort <nicolasfort1988@gmail.com> | 2022-08-27 15:35:52 +0000 |
commit | 37cfa8cdb1c6a1d395109aabd3ee29e83db151da (patch) | |
tree | 8a710dc72fe799956330008f8031bc07f9d1a407 | |
parent | 9126170f0b09285cf79f8c40584312bccd67c3e8 (diff) | |
download | vyos-1x-37cfa8cdb1c6a1d395109aabd3ee29e83db151da.tar.gz vyos-1x-37cfa8cdb1c6a1d395109aabd3ee29e83db151da.zip |
Firewall: T4651: Add options to match packet size on firewall rules.
-rw-r--r-- | interface-definitions/firewall.xml.in | 40 | ||||
-rw-r--r-- | python/vyos/firewall.py | 26 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_firewall.py | 22 | ||||
-rwxr-xr-x | src/validators/ip-length | 29 |
4 files changed, 116 insertions, 1 deletions
diff --git a/interface-definitions/firewall.xml.in b/interface-definitions/firewall.xml.in index 2e9452dfd..f838f1b88 100644 --- a/interface-definitions/firewall.xml.in +++ b/interface-definitions/firewall.xml.in @@ -383,6 +383,26 @@ </children> </node> #include <include/firewall/common-rule.xml.i> + <leafNode name="ip-length"> + <properties> + <help>Payload size in bytes, including any extension header</help> + <valueHelp> + <format>u32:1-65535</format> + <description>Numbered packet length</description> + </valueHelp> + <valueHelp> + <format><start-end></format> + <description>Packet length range (e.g. 1001-1005)</description> + </valueHelp> + <valueHelp> + <format> </format> + <description>\n\n Multiple values can be specified as a comma-separated list.\n For example: '64, 512,1001-1005'</description> + </valueHelp> + <constraint> + <validator name="ip-length"/> + </constraint> + </properties> + </leafNode> <node name="hop-limit"> <properties> <help>Hop Limit</help> @@ -571,6 +591,26 @@ </children> </node> #include <include/firewall/common-rule.xml.i> + <leafNode name="ip-length"> + <properties> + <help>Packet size in bytes, including header and data</help> + <valueHelp> + <format>u32:1-65535</format> + <description>Numbered packet length</description> + </valueHelp> + <valueHelp> + <format><start-end></format> + <description>Packet length range (e.g. 1001-1005)</description> + </valueHelp> + <valueHelp> + <format> </format> + <description>\n\n Multiple values can be specified as a comma-separated list.\n For example: '64, 512,1001-1005'</description> + </valueHelp> + <constraint> + <validator name="ip-length"/> + </constraint> + </properties> + </leafNode> <node name="icmp"> <properties> <help>ICMP type and code information</help> diff --git a/python/vyos/firewall.py b/python/vyos/firewall.py index 663c4394a..a4fd64830 100644 --- a/python/vyos/firewall.py +++ b/python/vyos/firewall.py @@ -265,6 +265,32 @@ def parse_rule(rule_conf, fw_name, rule_id, ip_name): if 'type' in rule_conf[icmp]: output.append(icmp + ' type ' + rule_conf[icmp]['type']) + + if 'ip_length' in rule_conf: + #proto = rule_conf['protocol'] + length = rule_conf['ip_length'].split(',') + + lengths = [] + negated_lengths = [] + + for p in length: + if p[0] == '!': + negated_lengths.append(p[1:]) + else: + lengths.append(p) + + #if proto == 'tcp_udp': + # proto = 'th' + + if lengths: + lengths_str = ','.join(lengths) + output.append(f'ip{def_suffix} length {{{lengths_str}}}') + + if negated_lengths: + negated_lengths_str = ','.join(negated_lengths) + output.append(f'ip{def_suffix} length != {{{negated_lengths_str}}}') + + if 'ipsec' in rule_conf: if 'match_ipsec' in rule_conf['ipsec']: output.append('meta ipsec == 1') diff --git a/smoketest/scripts/cli/test_firewall.py b/smoketest/scripts/cli/test_firewall.py index 684a07681..5ca00eafa 100755 --- a/smoketest/scripts/cli/test_firewall.py +++ b/smoketest/scripts/cli/test_firewall.py @@ -209,6 +209,13 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase): self.cli_set(['firewall', 'name', 'smoketest', 'rule', '5', 'tcp', 'flags', 'syn']) self.cli_set(['firewall', 'name', 'smoketest', 'rule', '5', 'tcp', 'mss', mss_range]) + self.cli_set(['firewall', 'name', 'smoketest', 'rule', '6', 'action', 'accept']) + self.cli_set(['firewall', 'name', 'smoketest', 'rule', '6', 'ip-length', '64,512,1024']) + self.cli_set(['firewall', 'name', 'smoketest', 'rule', '7', 'action', 'accept']) + self.cli_set(['firewall', 'name', 'smoketest', 'rule', '7', 'ip-length', '0-30000']) + self.cli_set(['firewall', 'name', 'smoketest', 'rule', '8', 'action', 'accept']) + self.cli_set(['firewall', 'name', 'smoketest', 'rule', '8', 'ip-length', '!60000-65535']) + self.cli_set(['interfaces', 'ethernet', 'eth0', 'firewall', 'in', 'name', 'smoketest']) self.cli_commit() @@ -220,7 +227,10 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase): ['tcp dport { 22 }', 'limit rate 5/minute', 'return'], ['log prefix "[smoketest-default-D]"','smoketest default-action', 'drop'], ['tcp dport { 22 }', 'add @RECENT_smoketest_4 { ip saddr limit rate over 10/minute burst 10 packets }', 'drop'], - [f'tcp flags & syn == syn tcp option maxseg size {mss_range}'] + [f'tcp flags & syn == syn tcp option maxseg size {mss_range}'], + ['ip length { 64, 512, 1024 }', 'return'], + ['ip length { 0-30000 }', 'return'], + ['ip length != { 60000-65535 }', 'return'] ] self.verify_nftables(nftables_search, 'ip filter') @@ -239,6 +249,13 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase): 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']) + self.cli_set(['firewall', 'ipv6-name', 'v6-smoketest', 'rule', '3', 'action', 'accept']) + self.cli_set(['firewall', 'ipv6-name', 'v6-smoketest', 'rule', '3', 'ip-length', '64,512,1024']) + self.cli_set(['firewall', 'ipv6-name', 'v6-smoketest', 'rule', '4', 'action', 'accept']) + self.cli_set(['firewall', 'ipv6-name', 'v6-smoketest', 'rule', '4', 'ip-length', '0-30000']) + self.cli_set(['firewall', 'ipv6-name', 'v6-smoketest', 'rule', '5', 'action', 'accept']) + self.cli_set(['firewall', 'ipv6-name', 'v6-smoketest', 'rule', '5', 'ip-length', '!60000-65535']) + self.cli_set(['interfaces', 'ethernet', 'eth0', 'firewall', 'in', 'ipv6-name', 'v6-smoketest']) self.cli_commit() @@ -247,6 +264,9 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase): ['iifname "eth0"', 'jump NAME6_v6-smoketest'], ['saddr 2002::1', 'daddr 2002::1:1', 'log prefix "[v6-smoketest-1-A]" level crit', 'return'], ['meta l4proto { tcp, udp }', 'th dport { 8888 }', 'reject'], + ['ip6 length { 64, 512, 1024 }', 'return'], + ['ip6 length { 0-30000 }', 'return'], + ['ip6 length != { 60000-65535 }', 'return'], ['smoketest default-action', 'log prefix "[v6-smoketest-default-D]"', 'drop'] ] diff --git a/src/validators/ip-length b/src/validators/ip-length new file mode 100755 index 000000000..d96093849 --- /dev/null +++ b/src/validators/ip-length @@ -0,0 +1,29 @@ +#!/usr/bin/python3 + +from sys import argv +from sys import exit +import re + +if __name__ == '__main__': + if len(argv)>1: + lengths = argv[1].split(",") + + for length in lengths: + if length and length[0] == '!': + length = length[1:] + if re.match('^[0-9]{1,5}-[0-9]{1,5}$', length): + length_1, length_2 = length.split('-') + if int(length_1) not in range(0, 65536) or int(length_2) not in range(0, 65536): + print(f'Error: {length} is not a valid length range') + exit(1) + if int(length_1) > int(length_2): + print(f'Error: {length} is not a valid length range') + exit(1) + elif length.isnumeric(): + if int(length) not in range(0, 65536): + print(f'Error: {length} is not a valid length value') + exit(1) + else: + exit(2) + + exit(0)
\ No newline at end of file |