summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/templates/conntrackd/conntrackd.conf.tmpl107
-rw-r--r--debian/control3
-rw-r--r--interface-definitions/service_conntrack-sync.xml.in168
-rwxr-xr-xsrc/conf_mode/conntrack_sync.py106
-rw-r--r--src/etc/systemd/system/conntrackd.service.d/override.conf8
-rwxr-xr-xsrc/migration-scripts/conntrack-sync/1-to-261
-rwxr-xr-xsrc/validators/ipv43
-rwxr-xr-xsrc/validators/ipv4-multicast3
-rwxr-xr-xsrc/validators/ipv6-multicast3
9 files changed, 462 insertions, 0 deletions
diff --git a/data/templates/conntrackd/conntrackd.conf.tmpl b/data/templates/conntrackd/conntrackd.conf.tmpl
new file mode 100644
index 000000000..86501023f
--- /dev/null
+++ b/data/templates/conntrackd/conntrackd.conf.tmpl
@@ -0,0 +1,107 @@
+# autogenerated by conntrack_sync.py
+
+# Synchronizer settings
+Sync {
+ Mode FTFW {
+ DisableExternalCache {{ 'on' if disable_external_cache is defined else 'off' }}
+ }
+{% for iface, iface_config in interface.items() %}
+{% if loop.first %}
+{% if iface_config.peer is defined and iface_config.peer is not none %}
+ UDP {
+{% if listen_address is defined and listen_address is not none %}
+ IPv4_address {{ listen_address }}
+{% endif %}
+ IPv4_Destination_Address {{ iface_config.peer }}
+ Port 3780
+{% else %}
+{% set ip_address = iface | get_ipv4 %}
+ Multicast {
+ IPv4_address {{ mcast_group }}
+ Group 3780
+ IPv4_interface {{ ip_address[0] | ip_from_cidr }}
+{% endif %}
+ Interface {{ iface }}
+{% endif %}
+{% endfor %}
+ SndSocketBuffer {{ sync_queue_size | int *1024 *1024 }}
+ RcvSocketBuffer {{ sync_queue_size | int *1024 *1024 }}
+ Checksum on
+ }
+{% if expect_sync is defined and expect_sync is not none %}
+ Options {
+{% if 'all' in expect_sync %}
+ ExpectationSync on
+{% else %}
+ ExpectationSync {
+{% for protocol in expect_sync %}
+ {{ protocol }}
+{% endfor %}
+{% endif %}
+ }
+ }
+{% endif %}
+}
+Helper {
+ Type rpc inet tcp {
+ QueueNum 3
+ Policy rpc {
+ ExpectMax 1
+ ExpectTimeout 300
+ }
+ }
+ Type rpc inet udp {
+ QueueNum 4
+ Policy rpc {
+ ExpectMax 1
+ ExpectTimeout 300
+ }
+ }
+ Type tns inet tcp {
+ QueueNum 5
+ Policy tns {
+ ExpectMax 1
+ ExpectTimeout 300
+ }
+ }
+}
+
+# General settings
+General {
+ Nice -20
+ HashSize {{ hash_size }}
+ HashLimit {{ table_size | int *2 }}
+ LogFile off
+ Syslog on
+ LockFile /var/lock/conntrack.lock
+ UNIX {
+ Path /run/conntrackd/conntrackd.ctl
+ Backlog 20
+ }
+ NetlinkBufferSize {{ 2 *1024 *1024 }}
+ NetlinkBufferSizeMaxGrowth {{ event_listen_queue_size | int *1024 *1024 }}
+ NetlinkOverrunResync off
+ NetlinkEventsReliable on
+{% if ignore_address is defined or accept_protocol is defined %}
+ Filter From Userspace {
+{% if ignore_address is defined and ignore_address is not none %}
+ Address Ignore {
+{% for address in ignore_address if address | is_ipv4 %}
+ IPv4_address {{ address }}
+{% endfor %}
+{% for address in ignore_address if address | is_ipv6 %}
+ IPv6_address {{ address }}
+{% endfor %}
+ }
+{% endif %}
+{% if accept_protocol is defined and accept_protocol is not none %}
+ Protocol Accept {
+{% for protocol in accept_protocol %}
+ {{ protocol | upper }}
+{% endfor %}
+ }
+{% endif %}
+ }
+{% endif %}
+}
+
diff --git a/debian/control b/debian/control
index 851152d95..de030310e 100644
--- a/debian/control
+++ b/debian/control
@@ -35,6 +35,7 @@ Depends:
bmon,
bsdmainutils,
conntrack,
+ conntrackd,
conserver-client,
conserver-server,
console-data,
@@ -67,6 +68,8 @@ Depends:
lcdproc,
libatomic1,
libndp-tools,
+ libnetfilter-conntrack3,
+ libnfnetlink0,
libpam-radius-auth (>= 1.5.0),
libvyosconfig0,
lldpd,
diff --git a/interface-definitions/service_conntrack-sync.xml.in b/interface-definitions/service_conntrack-sync.xml.in
new file mode 100644
index 000000000..45d211479
--- /dev/null
+++ b/interface-definitions/service_conntrack-sync.xml.in
@@ -0,0 +1,168 @@
+<?xml version="1.0"?>
+<interfaceDefinition>
+ <node name="service">
+ <children>
+ <node name="conntrack-sync" owner="${vyos_conf_scripts_dir}/conntrack_sync.py">
+ <properties>
+ <help>Connection tracking synchronization</help>
+ <priority>995</priority>
+ </properties>
+ <children>
+ <leafNode name="accept-protocol">
+ <properties>
+ <help>Protocols for which local conntrack entries will be synced</help>
+ <completionHelp>
+ <list>tcp udp icmp sctp</list>
+ </completionHelp>
+ <valueHelp>
+ <format>tcp</format>
+ <description>Sync Transmission Control Protocol conntrack entries</description>
+ </valueHelp>
+ <valueHelp>
+ <format>udp</format>
+ <description>Sync User Datagram Protocol conntrack entries</description>
+ </valueHelp>
+ <valueHelp>
+ <format>icmp</format>
+ <description>Sync Internet Control Message Protocol conntrack entries</description>
+ </valueHelp>
+ <valueHelp>
+ <format>sctp</format>
+ <description>Sync Stream Control Transmission Protocol conntrack entries</description>
+ </valueHelp>
+ <constraint>
+ <regex>^(tcp|udp|icmp|sctp)$</regex>
+ </constraint>
+ <constraintErrorMessage>Allowed protocols: tcp udp icmp or sctp</constraintErrorMessage>
+ <multi/>
+ </properties>
+ </leafNode>
+ <leafNode name="disable-external-cache">
+ <properties>
+ <help>Directly injects the flow-states into the in-kernel Connection Tracking System of the backup firewall.</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ <leafNode name="event-listen-queue-size">
+ <properties>
+ <help>Queue size for local conntrack events</help>
+ <valueHelp>
+ <format>u32</format>
+ <description>Queue size in MB</description>
+ </valueHelp>
+ </properties>
+ <defaultValue>8</defaultValue>
+ </leafNode>
+ <leafNode name="expect-sync">
+ <properties>
+ <help>Protocol for which expect entries need to be synchronized</help>
+ <completionHelp>
+ <list>all ftp sip h323 nfs sqlnet</list>
+ </completionHelp>
+ <constraint>
+ <regex>^(all|ftp|sip|h323|nfs|sqlnet)$</regex>
+ </constraint>
+ <constraintErrorMessage>Invalid protocol</constraintErrorMessage>
+ <multi/>
+ </properties>
+ </leafNode>
+ <node name="failover-mechanism">
+ <properties>
+ <help>Failover mechanism to use for conntrack-sync</help>
+ </properties>
+ <children>
+ <node name="cluster">
+ <properties>
+ <help>Cluster as failover-mechanism to use for conntrack-sync</help>
+ </properties>
+ <children>
+ <leafNode name="group">
+ <properties>
+ <help>Cluster group [DEPRECATED]</help>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
+ <node name="vrrp">
+ <properties>
+ <help>VRRP as failover-mechanism to use for conntrack-sync</help>
+ </properties>
+ <children>
+ <leafNode name="sync-group">
+ <properties>
+ <help>VRRP sync group [REQUIRED]</help>
+ <completionHelp>
+ <path>high-availability vrrp sync-group</path>
+ </completionHelp>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
+ </children>
+ </node>
+ <leafNode name="ignore-address">
+ <properties>
+ <help>IP addresses for which local conntrack entries will not be synced</help>
+ <valueHelp>
+ <format>ipv4</format>
+ <description>IPv4 address to ignore</description>
+ </valueHelp>
+ <valueHelp>
+ <format>ipv4net</format>
+ <description>IPv4 prefix to ignore</description>
+ </valueHelp>
+ <valueHelp>
+ <format>ipv6</format>
+ <description>IPv6 address to ignore</description>
+ </valueHelp>
+ <valueHelp>
+ <format>ipv6net</format>
+ <description>IPv6 prefix to ignore</description>
+ </valueHelp>
+ <constraint>
+ <validator name="ipv4"/>
+ <validator name="ipv6"/>
+ </constraint>
+ <multi/>
+ </properties>
+ </leafNode>
+ <tagNode name="interface">
+ <properties>
+ <help>Interface to use for syncing conntrack entries</help>
+ <completionHelp>
+ <script>${vyos_completion_dir}/list_interfaces.py --bridgeable</script>
+ </completionHelp>
+ </properties>
+ <children>
+ <leafNode name="peer">
+ <properties>
+ <help>IP address of the peer to send the UDP conntrack info too. This disable multicast.</help>
+ </properties>
+ </leafNode>
+ </children>
+ </tagNode>
+ #include <include/listen-address-ipv4.xml.i>
+ <leafNode name="mcast-group">
+ <properties>
+ <help>Multicast group to use for syncing conntrack entries</help>
+ <constraint>
+ <validator name="ipv4-multicast"/>
+ </constraint>
+ </properties>
+ <defaultValue>225.0.0.50</defaultValue>
+ </leafNode>
+ <leafNode name="sync-queue-size">
+ <properties>
+ <help>Queue size for syncing conntrack entries</help>
+ <valueHelp>
+ <format>u32</format>
+ <description>Queue size in MB</description>
+ </valueHelp>
+ </properties>
+ <defaultValue>1</defaultValue>
+ </leafNode>
+ </children>
+ </node>
+ </children>
+ </node>
+</interfaceDefinition>
diff --git a/src/conf_mode/conntrack_sync.py b/src/conf_mode/conntrack_sync.py
new file mode 100755
index 000000000..c1c90d1fc
--- /dev/null
+++ b/src/conf_mode/conntrack_sync.py
@@ -0,0 +1,106 @@
+#!/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 read_file
+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 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')
+
+ 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!')
+
+ 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:
+ call('systemctl stop conntrackd.service')
+ return None
+
+ 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..3a76fc0e0
--- /dev/null
+++ b/src/migration-scripts/conntrack-sync/1-to-2
@@ -0,0 +1,61 @@
+#!/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)
+
+ 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/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