diff options
| -rw-r--r-- | interface-definitions/include/firewall/action-forward.xml.i | 8 | ||||
| -rw-r--r-- | interface-definitions/include/firewall/action.xml.i | 8 | ||||
| -rw-r--r-- | interface-definitions/include/firewall/common-rule-inet.xml.i | 3 | ||||
| -rw-r--r-- | interface-definitions/include/firewall/synproxy.xml.i | 40 | ||||
| -rw-r--r-- | python/vyos/firewall.py | 14 | ||||
| -rwxr-xr-x | smoketest/scripts/cli/test_firewall.py | 27 | ||||
| -rwxr-xr-x | src/conf_mode/firewall.py | 10 | 
7 files changed, 103 insertions, 7 deletions
| diff --git a/interface-definitions/include/firewall/action-forward.xml.i b/interface-definitions/include/firewall/action-forward.xml.i index f61e51887..4e59f3c6f 100644 --- a/interface-definitions/include/firewall/action-forward.xml.i +++ b/interface-definitions/include/firewall/action-forward.xml.i @@ -3,7 +3,7 @@    <properties>      <help>Rule action</help>      <completionHelp> -      <list>accept continue jump reject return drop queue offload</list> +      <list>accept continue jump reject return drop queue offload synproxy</list>      </completionHelp>      <valueHelp>        <format>accept</format> @@ -37,8 +37,12 @@        <format>offload</format>        <description>Offload packet via flowtable</description>      </valueHelp> +    <valueHelp> +      <format>synproxy</format> +      <description>Synproxy connections</description> +    </valueHelp>      <constraint> -      <regex>(accept|continue|jump|reject|return|drop|queue|offload)</regex> +      <regex>(accept|continue|jump|reject|return|drop|queue|offload|synproxy)</regex>      </constraint>    </properties>  </leafNode> diff --git a/interface-definitions/include/firewall/action.xml.i b/interface-definitions/include/firewall/action.xml.i index 9391a7bee..954e4f23e 100644 --- a/interface-definitions/include/firewall/action.xml.i +++ b/interface-definitions/include/firewall/action.xml.i @@ -3,7 +3,7 @@    <properties>      <help>Rule action</help>      <completionHelp> -      <list>accept continue jump reject return drop queue</list> +      <list>accept continue jump reject return drop queue synproxy</list>      </completionHelp>      <valueHelp>        <format>accept</format> @@ -33,8 +33,12 @@        <format>queue</format>        <description>Enqueue packet to userspace</description>      </valueHelp> +    <valueHelp> +      <format>synproxy</format> +      <description>Synproxy connections</description> +    </valueHelp>      <constraint> -      <regex>(accept|continue|jump|reject|return|drop|queue)</regex> +      <regex>(accept|continue|jump|reject|return|drop|queue|synproxy)</regex>      </constraint>    </properties>  </leafNode> diff --git a/interface-definitions/include/firewall/common-rule-inet.xml.i b/interface-definitions/include/firewall/common-rule-inet.xml.i index 3dbfbb65c..872abe6cc 100644 --- a/interface-definitions/include/firewall/common-rule-inet.xml.i +++ b/interface-definitions/include/firewall/common-rule-inet.xml.i @@ -220,6 +220,7 @@      </leafNode>    </children>  </node> +#include <include/firewall/synproxy.xml.i>  <node name="state">    <properties>      <help>Session state</help> @@ -373,4 +374,4 @@      </leafNode>    </children>  </node> -<!-- include end -->
\ No newline at end of file +<!-- include end --> diff --git a/interface-definitions/include/firewall/synproxy.xml.i b/interface-definitions/include/firewall/synproxy.xml.i new file mode 100644 index 000000000..a65126ea9 --- /dev/null +++ b/interface-definitions/include/firewall/synproxy.xml.i @@ -0,0 +1,40 @@ +<!-- include start from firewall/synproxy.xml.i --> +<node name="synproxy"> +  <properties> +    <help>Synproxy options</help> +  </properties> +  <children> +    <node name="tcp"> +      <properties> +        <help>TCP synproxy options</help> +      </properties> +      <children> +        <leafNode name="mss"> +          <properties> +            <help>TCP Maximum segment size</help> +            <valueHelp> +              <format>u32:501-65535</format> +              <description>Maximum segment size for synproxy connections</description> +            </valueHelp> +            <constraint> +              <validator name="numeric" argument="--range 501-65535"/> +            </constraint> +          </properties> +        </leafNode> +        <leafNode name="window-scale"> +          <properties> +            <help>TCP window scale for synproxy connections</help> +            <valueHelp> +              <format>u32:1-14</format> +              <description>TCP window scale</description> +            </valueHelp> +            <constraint> +              <validator name="numeric" argument="--range 1-14"/> +            </constraint> +          </properties> +        </leafNode> +      </children> +    </node> +  </children> +</node> +<!-- include end --> diff --git a/python/vyos/firewall.py b/python/vyos/firewall.py index 7e43b815a..ab40688cc 100644 --- a/python/vyos/firewall.py +++ b/python/vyos/firewall.py @@ -263,6 +263,10 @@ def parse_rule(rule_conf, hook, fw_name, rule_id, ip_name):                      output.append(f'{proto} {prefix}port {operator} @P_{group_name}') +    if rule_conf['action'] == 'synproxy': +        if 'synproxy' in rule_conf: +            output.append('ct state invalid,untracked') +      if 'hop_limit' in rule_conf:          operators = {'eq': '==', 'gt': '>', 'lt': '<'}          for op, operator in operators.items(): @@ -433,6 +437,16 @@ def parse_rule(rule_conf, hook, fw_name, rule_id, ip_name):                  if 'queue_options' in rule_conf:                      queue_opts = ','.join(rule_conf['queue_options'])                      output.append(f'{queue_opts}') + +        # Synproxy +        if 'synproxy' in rule_conf: +            synproxy_mss = dict_search_args(rule_conf, 'synproxy', 'tcp', 'mss') +            if synproxy_mss: +                output.append(f'mss {synproxy_mss}') +            synproxy_ws = dict_search_args(rule_conf, 'synproxy', 'tcp', 'window_scale') +            if synproxy_ws: +                output.append(f'wscale {synproxy_ws} timestamp sack-perm') +      else:          output.append('return') diff --git a/smoketest/scripts/cli/test_firewall.py b/smoketest/scripts/cli/test_firewall.py index 4a577562d..67e949f95 100755 --- a/smoketest/scripts/cli/test_firewall.py +++ b/smoketest/scripts/cli/test_firewall.py @@ -1,6 +1,6 @@  #!/usr/bin/env python3  # -# Copyright (C) 2021-2022 VyOS maintainers and contributors +# Copyright (C) 2021-2023 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 @@ -338,6 +338,31 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):          self.verify_nftables(nftables_search, 'ip vyos_filter') +    def test_ipv4_synproxy(self): +        tcp_mss = '1460' +        tcp_wscale = '7' +        dport = '22' + +        self.cli_set(['firewall', 'ipv4', 'input', 'filter', 'rule', '10', 'action', 'drop']) +        self.cli_set(['firewall', 'ipv4', 'input', 'filter', 'rule', '10', 'protocol', 'tcp']) +        self.cli_set(['firewall', 'ipv4', 'input', 'filter', 'rule', '10', 'destination', 'port', dport]) +        self.cli_set(['firewall', 'ipv4', 'input', 'filter', 'rule', '10', 'synproxy', 'tcp', 'mss', tcp_mss]) +        self.cli_set(['firewall', 'ipv4', 'input', 'filter', 'rule', '10', 'synproxy', 'tcp', 'window-scale', tcp_wscale]) + +        with self.assertRaises(ConfigSessionError): +            self.cli_commit() + +        self.cli_set(['firewall', 'ipv4', 'input', 'filter', 'rule', '10', 'action', 'synproxy']) + +        self.cli_commit() + +        nftables_search = [ +            [f'tcp dport {dport} ct state invalid,untracked', f'synproxy mss {tcp_mss} wscale {tcp_wscale} timestamp sack-perm'] +        ] + +        self.verify_nftables(nftables_search, 'ip vyos_filter') + +      def test_ipv4_mask(self):          name = 'smoketest-mask'          interface = 'eth0' diff --git a/src/conf_mode/firewall.py b/src/conf_mode/firewall.py index 3d799318e..2ca4bbe2d 100755 --- a/src/conf_mode/firewall.py +++ b/src/conf_mode/firewall.py @@ -1,6 +1,6 @@  #!/usr/bin/env python3  # -# Copyright (C) 2021-2022 VyOS maintainers and contributors +# Copyright (C) 2021-2023 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 @@ -173,6 +173,14 @@ def verify_rule(firewall, rule_conf, ipv6):          if not dict_search_args(firewall, 'flowtable', offload_target):              raise ConfigError(f'Invalid offload-target. Flowtable "{offload_target}" does not exist on the system') +    if rule_conf['action'] != 'synproxy' and 'synproxy' in rule_conf: +        raise ConfigError('"synproxy" option allowed only for action synproxy') +    if rule_conf['action'] == 'synproxy': +        if not rule_conf.get('synproxy', {}).get('tcp'): +            raise ConfigError('synproxy TCP MSS is not defined') +        if rule_conf.get('protocol', {}) != 'tcp': +            raise ConfigError('For action "synproxy" the protocol must be set to TCP') +      if 'queue_options' in rule_conf:          if 'queue' not in rule_conf['action']:              raise ConfigError('queue-options defined, but action queue needed and it is not defined') | 
