summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/conf_mode/conntrack_sync.py135
-rw-r--r--src/etc/systemd/system/conntrackd.service.d/override.conf8
-rwxr-xr-xsrc/migration-scripts/conntrack-sync/1-to-266
-rwxr-xr-xsrc/op_mode/conntrack_sync.py136
-rwxr-xr-xsrc/validators/ipv43
-rwxr-xr-xsrc/validators/ipv4-multicast3
-rwxr-xr-xsrc/validators/ipv6-multicast3
7 files changed, 354 insertions, 0 deletions
diff --git a/src/conf_mode/conntrack_sync.py b/src/conf_mode/conntrack_sync.py
new file mode 100755
index 000000000..7f22fa2dd
--- /dev/null
+++ b/src/conf_mode/conntrack_sync.py
@@ -0,0 +1,135 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 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 os
+
+from sys import exit
+from vyos.config import Config
+from vyos.configdict import dict_merge
+from vyos.configverify import verify_interface_exists
+from vyos.util import call
+from vyos.util import dict_search
+from vyos.util import process_named_running
+from vyos.util import read_file
+from vyos.util import run
+from vyos.template import render
+from vyos.template import get_ipv4
+from vyos.validate import is_addr_assigned
+from vyos.xml import defaults
+from vyos import ConfigError
+from vyos import airbag
+airbag.enable()
+
+config_file = '/run/conntrackd/conntrackd.conf'
+
+def resync_vrrp():
+ tmp = run('/usr/libexec/vyos/conf_mode/vrrp.py')
+ if tmp > 0:
+ print('ERROR: error restarting VRRP daemon!')
+
+def get_config(config=None):
+ if config:
+ conf = config
+ else:
+ conf = Config()
+ base = ['service', 'conntrack-sync']
+ if not conf.exists(base):
+ return None
+
+ conntrack = 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)
+ conntrack = dict_merge(default_values, conntrack)
+
+ conntrack['hash_size'] = read_file('/sys/module/nf_conntrack/parameters/hashsize')
+ conntrack['table_size'] = read_file('/proc/sys/net/netfilter/nf_conntrack_max')
+
+ conntrack['vrrp'] = conf.get_config_dict(['high-availability', 'vrrp', 'sync-group'],
+ get_first_key=True)
+
+ return conntrack
+
+def verify(conntrack):
+ if not conntrack:
+ return None
+
+ if 'interface' not in conntrack:
+ raise ConfigError('Interface not defined!')
+
+ for interface in conntrack['interface']:
+ verify_interface_exists(interface)
+ # Interface must not only exist, it must also carry an IP address
+ if len(get_ipv4(interface)) < 1:
+ raise ConfigError(f'Interface {interface} requires an IP address!')
+
+ if 'expect_sync' in conntrack:
+ if len(conntrack['expect_sync']) > 1 and 'all' in conntrack['expect_sync']:
+ raise ConfigError('Cannot configure all with other protocol')
+
+ if 'listen_address' in conntrack:
+ address = conntrack['listen_address']
+ if not is_addr_assigned(address):
+ raise ConfigError(f'Specified listen-address {address} not assigned to any interface!')
+
+ vrrp_group = dict_search('failover_mechanism.vrrp.sync_group', conntrack)
+ if vrrp_group == None:
+ raise ConfigError(f'No VRRP sync-group defined!')
+ if vrrp_group not in conntrack['vrrp']:
+ raise ConfigError(f'VRRP sync-group {vrrp_group} not configured!')
+
+ return None
+
+def generate(conntrack):
+ if not conntrack:
+ if os.path.isfile(config_file):
+ os.unlink(config_file)
+ return None
+
+ render(config_file, 'conntrackd/conntrackd.conf.tmpl', conntrack)
+
+ return None
+
+def apply(conntrack):
+ if not conntrack:
+ # Failover mechanism daemon should be indicated that it no longer needs
+ # to execute conntrackd actions on transition. This is only required
+ # once when conntrackd is stopped and taken out of service!
+ if process_named_running('conntrackd'):
+ resync_vrrp()
+
+ call('systemctl stop conntrackd.service')
+ return None
+
+ # Failover mechanism daemon should be indicated that it needs to execute
+ # conntrackd actions on transition. This is only required once when conntrackd
+ # is started the first time!
+ if not process_named_running('conntrackd'):
+ resync_vrrp()
+
+ call('systemctl restart conntrackd.service')
+ return None
+
+if __name__ == '__main__':
+ try:
+ c = get_config()
+ verify(c)
+ generate(c)
+ apply(c)
+ except ConfigError as e:
+ print(e)
+ exit(1)
diff --git a/src/etc/systemd/system/conntrackd.service.d/override.conf b/src/etc/systemd/system/conntrackd.service.d/override.conf
new file mode 100644
index 000000000..eb611e0d9
--- /dev/null
+++ b/src/etc/systemd/system/conntrackd.service.d/override.conf
@@ -0,0 +1,8 @@
+[Unit]
+After=
+After=vyos-router.service
+ConditionPathExists=/run/conntrackd/conntrackd.conf
+
+[Service]
+ExecStart=
+ExecStart=/usr/sbin/conntrackd -C /run/conntrackd/conntrackd.conf
diff --git a/src/migration-scripts/conntrack-sync/1-to-2 b/src/migration-scripts/conntrack-sync/1-to-2
new file mode 100755
index 000000000..ebbd8c35a
--- /dev/null
+++ b/src/migration-scripts/conntrack-sync/1-to-2
@@ -0,0 +1,66 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 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/>.
+
+# VyOS 1.2 crux allowed configuring a lower or upper case loglevel. This
+# is no longer supported as the input data is validated and will lead to
+# an error. If user specifies an upper case logleve, make it lowercase
+
+from sys import argv
+from sys import exit
+
+from vyos.configtree import ConfigTree
+
+if (len(argv) < 1):
+ print("Must specify file name!")
+ exit(1)
+
+file_name = argv[1]
+
+with open(file_name, 'r') as f:
+ config_file = f.read()
+
+base = ['service', 'conntrack-sync']
+config = ConfigTree(config_file)
+
+if not config.exists(base):
+ # Nothing to do
+ exit(0)
+else:
+ base_accept_proto = base + ['accept-protocol']
+ if config.exists(base_accept_proto):
+ tmp = config.return_value(base_accept_proto)
+ config.delete(base_accept_proto)
+ for protocol in tmp.split(','):
+ config.set(base_accept_proto, value=protocol, replace=False)
+
+ base_ignore_addr = base + ['ignore-address', 'ipv4']
+ if config.exists(base_ignore_addr):
+ tmp = config.return_values(base_ignore_addr)
+ config.delete(base_ignore_addr)
+ for address in tmp:
+ config.set(base + ['ignore-address'], value=address, replace=False)
+
+ # we no longer support cluster mode
+ base_cluster = base + ['failover-mechanism', 'cluster']
+ if config.exists(base_cluster):
+ config.delete(base_cluster)
+
+ try:
+ with open(file_name, 'w') as f:
+ f.write(config.to_string())
+ except OSError as e:
+ print("Failed to save the modified config: {}".format(e))
+ exit(1)
diff --git a/src/op_mode/conntrack_sync.py b/src/op_mode/conntrack_sync.py
new file mode 100755
index 000000000..66ecf8439
--- /dev/null
+++ b/src/op_mode/conntrack_sync.py
@@ -0,0 +1,136 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 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 os
+import syslog
+import xmltodict
+
+from argparse import ArgumentParser
+from vyos.configquery import CliShellApiConfigQuery
+from vyos.util import cmd
+from vyos.util import run
+from vyos.template import render_to_string
+
+conntrackd_bin = '/usr/sbin/conntrackd'
+conntrackd_config = '/run/conntrackd/conntrackd.conf'
+
+parser = ArgumentParser(description='Conntrack Sync')
+group = parser.add_mutually_exclusive_group()
+group.add_argument('--restart', help='Restart connection tracking synchronization service', action='store_true')
+group.add_argument('--reset-cache-internal', help='Reset internal cache', action='store_true')
+group.add_argument('--reset-cache-external', help='Reset external cache', action='store_true')
+group.add_argument('--show-internal', help='Show internal (main) tracking cache', action='store_true')
+group.add_argument('--show-external', help='Show external (main) tracking cache', action='store_true')
+group.add_argument('--show-internal-expect', help='Show internal (expect) tracking cache', action='store_true')
+group.add_argument('--show-external-expect', help='Show external (expect) tracking cache', action='store_true')
+
+def is_configured():
+ """ Check if conntrack-sync service is configured """
+ config = CliShellApiConfigQuery()
+ if not config.exists(['service', 'conntrack-sync']):
+ print('Service conntrackd-sync not configured!')
+ exit(1)
+
+def send_bulk_update():
+ """ send bulk update of internal-cache to other systems """
+ tmp = run(f'{conntrackd_bin} -C {conntrackd_config} -B')
+ if tmp > 0:
+ print('ERROR: failed to send bulk update to other conntrack-sync systems')
+
+def request_sync():
+ """ request resynchronization with other systems """
+ tmp = run(f'{conntrackd_bin} -C {conntrackd_config} -n')
+ if tmp > 0:
+ print('ERROR: failed to request resynchronization of external cache')
+
+def flush_cache(direction):
+ """ flush conntrackd cache (internal or external) """
+ if direction not in ['internal', 'external']:
+ raise ValueError()
+ tmp = run(f'{conntrackd_bin} -C {conntrackd_config} -f {direction}')
+ if tmp > 0:
+ print('ERROR: failed to clear {direction} cache')
+
+def xml_to_stdout(xml):
+ out = []
+ for line in xml.splitlines():
+ if line == '\n':
+ continue
+ parsed = xmltodict.parse(line)
+ out.append(parsed)
+
+ print(render_to_string('conntrackd/conntrackd.op-mode.tmpl', {'data' : out}))
+
+if __name__ == '__main__':
+ args = parser.parse_args()
+ syslog.openlog(ident='conntrack-tools', logoption=syslog.LOG_PID,
+ facility=syslog.LOG_INFO)
+
+ if args.restart:
+ is_configured()
+
+ syslog.syslog('Restarting conntrack sync service...')
+ cmd('systemctl restart conntrackd.service')
+ # request resynchronization with other systems
+ request_sync()
+ # send bulk update of internal-cache to other systems
+ send_bulk_update()
+
+ elif args.reset_cache_external:
+ is_configured()
+ syslog.syslog('Resetting external cache of conntrack sync service...')
+
+ # flush the external cache
+ flush_cache('external')
+ # request resynchronization with other systems
+ request_sync()
+
+ elif args.reset_cache_internal:
+ is_configured()
+ syslog.syslog('Resetting internal cache of conntrack sync service...')
+ # flush the internal cache
+ flush_cache('internal')
+
+ # request resynchronization of internal cache with kernel conntrack table
+ tmp = run(f'{conntrackd_bin} -C {conntrackd_config} -R')
+ if tmp > 0:
+ print('ERROR: failed to resynchronize internal cache with kernel conntrack table')
+
+ # send bulk update of internal-cache to other systems
+ send_bulk_update()
+
+ elif args.show_external or args.show_internal or args.show_external_expect or args.show_internal_expect:
+ is_configured()
+ opt = ''
+ if args.show_external:
+ opt = '-e ct'
+ elif args.show_external_expect:
+ opt = '-e expect'
+ elif args.show_internal:
+ opt = '-i ct'
+ elif args.show_internal_expect:
+ opt = '-i expect'
+
+ if args.show_external or args.show_internal:
+ print('Main Table Entries:')
+ else:
+ print('Expect Table Entries:')
+ out = cmd(f'sudo {conntrackd_bin} -C {conntrackd_config} {opt} -x')
+ xml_to_stdout(out)
+
+ else:
+ parser.print_help()
+ exit(1)
diff --git a/src/validators/ipv4 b/src/validators/ipv4
new file mode 100755
index 000000000..53face090
--- /dev/null
+++ b/src/validators/ipv4
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+ipaddrcheck --is-ipv4 $1
diff --git a/src/validators/ipv4-multicast b/src/validators/ipv4-multicast
new file mode 100755
index 000000000..e5cbc9532
--- /dev/null
+++ b/src/validators/ipv4-multicast
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+ipaddrcheck --is-ipv4-multicast $1
diff --git a/src/validators/ipv6-multicast b/src/validators/ipv6-multicast
new file mode 100755
index 000000000..66cd90c9c
--- /dev/null
+++ b/src/validators/ipv6-multicast
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+ipaddrcheck --is-ipv6-multicast $1