diff options
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | interface-definitions/firewall-options.xml | 55 | ||||
-rwxr-xr-x | src/conf_mode/firewall_options.py | 142 |
3 files changed, 198 insertions, 0 deletions
@@ -9,6 +9,7 @@ interface_definitions: find $(CURDIR)/interface-definitions/ -type f -name "*.xml" | xargs -I {} $(CURDIR)/scripts/build-command-templates {} $(CURDIR)/schema/interface_definition.rng $(TMPL_DIR) || exit 1 # XXX: delete top level node.def's that now live in other packages + rm -f $(TMPL_DIR)/firewall/node.def rm -f $(TMPL_DIR)/interfaces/node.def rm -f $(TMPL_DIR)/protocols/node.def rm -f $(TMPL_DIR)/system/node.def diff --git a/interface-definitions/firewall-options.xml b/interface-definitions/firewall-options.xml new file mode 100644 index 000000000..2936cc703 --- /dev/null +++ b/interface-definitions/firewall-options.xml @@ -0,0 +1,55 @@ +<?xml version="1.0"?> +<interfaceDefinition> + <node name="firewall"> + <children> + <node name="options"> + <properties> + <help>Firewall options/Packet manipulation</help> + <priority>990</priority> + </properties> + <children> + <tagNode name="interface" owner="sudo ${vyos_conf_scripts_dir}/firewall_options.py"> + <properties> + <help>Interface clamping options</help> + <completionHelp> + <script>${vyos_completion_dir}/list_interfaces.py</script> + </completionHelp> + </properties> + <children> + <leafNode name="disable"> + <properties> + <help>Disable this rule</help> + <valueless/> + </properties> + </leafNode> + <leafNode name="adjust-mss"> + <properties> + <help>Adjust MSS for IPv4 transit packets</help> + <valueHelp> + <format>500-1460</format> + <description>TCP Maximum segment size in bytes</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 500-1460"/> + </constraint> + </properties> + </leafNode> + <leafNode name="adjust-mss6"> + <properties> + <help>Adjust MSS for IPv6 transit packets</help> + <valueHelp> + <format>1280-1492</format> + <description>TCP Maximum segment size in bytes</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 1280-1492"/> + </constraint> + </properties> + </leafNode> + </children> + </tagNode> + </children> + </node> + </children> + </node> +</interfaceDefinition> diff --git a/src/conf_mode/firewall_options.py b/src/conf_mode/firewall_options.py new file mode 100755 index 000000000..e2c306904 --- /dev/null +++ b/src/conf_mode/firewall_options.py @@ -0,0 +1,142 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2018 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 +# published by the Free Software Foundation. +# +# 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/>. +# + +import sys +import os +import copy + +from vyos.config import Config +from vyos import ConfigError + +default_config_data = { + 'intf_opts': [], + 'new_chain4': False, + 'new_chain6': False +} + +def get_config(): + opts = copy.deepcopy(default_config_data) + conf = Config() + if not conf.exists('firewall options'): + return None + else: + conf.set_level('firewall options') + + # Parse configuration of each individual instance + if conf.exists('interface'): + for intf in conf.list_nodes('interface'): + conf.set_level('firewall options interface {0}'.format(intf)) + config = { + 'intf': intf, + 'disabled': False, + 'mss4': '', + 'mss6': '' + } + + # Check if individual option is disabled + if conf.exists('disable'): + config['disabled'] = True + + # + # Get MSS value IPv4 + # + if conf.exists('adjust-mss'): + config['mss4'] = conf.return_value('adjust-mss') + + # We need a marker that a new iptables chain needs to be generated + if not opts['new_chain4']: + opts['new_chain4'] = True + + # + # Get MSS value IPv6 + # + if conf.exists('adjust-mss6'): + config['mss6'] = conf.return_value('adjust-mss6') + + # We need a marker that a new ip6tables chain needs to be generated + if not opts['new_chain6']: + opts['new_chain6'] = True + + # Append interface options to global list + opts['intf_opts'].append(config) + + return opts + +def verify(tcp): + # syntax verification is done via cli + return None + +def apply(tcp): + target = 'VYOS_FW_OPTIONS' + + # always cleanup iptables + os.system('iptables --table mangle --delete FORWARD --jump {} >&/dev/null'.format(target)) + os.system('iptables --table mangle --flush {} >&/dev/null'.format(target)) + os.system('iptables --table mangle --delete-chain {} >&/dev/null'.format(target)) + + # always cleanup ip6tables + os.system('ip6tables --table mangle --delete FORWARD --jump {} >&/dev/null'.format(target)) + os.system('ip6tables --table mangle --flush {} >&/dev/null'.format(target)) + os.system('ip6tables --table mangle --delete-chain {} >&/dev/null'.format(target)) + + # Setup new iptables rules + if tcp['new_chain4']: + os.system('iptables --table mangle --new-chain {} >&/dev/null'.format(target)) + os.system('iptables --table mangle --append FORWARD --jump {} >&/dev/null'.format(target)) + + for opts in tcp['intf_opts']: + intf = opts['intf'] + mss = opts['mss4'] + + # Check if this rule iis disabled + if opts['disabled']: + continue + + # adjust TCP MSS per interface + if mss: + os.system('iptables --table mangle --append {} --out-interface {} --protocol tcp ' \ + '--tcp-flags SYN,RST SYN --jump TCPMSS --set-mss {} >&/dev/null'.format(target, intf, mss)) + + # Setup new ip6tables rules + if tcp['new_chain6']: + os.system('ip6tables --table mangle --new-chain {} >&/dev/null'.format(target)) + os.system('ip6tables --table mangle --append FORWARD --jump {} >&/dev/null'.format(target)) + + for opts in tcp['intf_opts']: + intf = opts['intf'] + mss = opts['mss6'] + + # Check if this rule iis disabled + if opts['disabled']: + continue + + # adjust TCP MSS per interface + if mss: + os.system('ip6tables --table mangle --append {} --out-interface {} --protocol tcp ' \ + '--tcp-flags SYN,RST SYN --jump TCPMSS --set-mss {} >&/dev/null'.format(target, intf, mss)) + + return None + +if __name__ == '__main__': + + try: + c = get_config() + verify(c) + apply(c) + except ConfigError as e: + print(e) + sys.exit(1) |