summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/conf_mode/interfaces_openvpn.py4
-rw-r--r--src/migration-scripts/openvpn/1-to-274
-rwxr-xr-xsrc/op_mode/conntrack_sync.py25
-rwxr-xr-xsrc/op_mode/lldp.py23
-rw-r--r--src/op_mode/tcpdump.py165
5 files changed, 283 insertions, 8 deletions
diff --git a/src/conf_mode/interfaces_openvpn.py b/src/conf_mode/interfaces_openvpn.py
index 627cc90ba..017010a61 100755
--- a/src/conf_mode/interfaces_openvpn.py
+++ b/src/conf_mode/interfaces_openvpn.py
@@ -515,6 +515,10 @@ def verify(openvpn):
print('Warning: using dh-params and EC keys simultaneously will ' \
'lead to DH ciphers being used instead of ECDH')
+ if dict_search('encryption.cipher', openvpn):
+ raise ConfigError('"encryption cipher" option is deprecated for TLS mode. '
+ 'Use "encryption ncp-ciphers" instead')
+
if dict_search('encryption.cipher', openvpn) == 'none':
print('Warning: "encryption none" was specified!')
print('No encryption will be performed and data is transmitted in ' \
diff --git a/src/migration-scripts/openvpn/1-to-2 b/src/migration-scripts/openvpn/1-to-2
new file mode 100644
index 000000000..1f82a2128
--- /dev/null
+++ b/src/migration-scripts/openvpn/1-to-2
@@ -0,0 +1,74 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2024 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/>.
+#
+# Removes --cipher option (deprecated) from OpenVPN configs
+# and moves it to --data-ciphers for server and client modes
+
+import sys
+
+from vyos.configtree import ConfigTree
+
+if len(sys.argv) < 2:
+ print("Must specify file name!")
+ sys.exit(1)
+
+file_name = sys.argv[1]
+
+with open(file_name, 'r') as f:
+ config_file = f.read()
+
+config = ConfigTree(config_file)
+
+if not config.exists(['interfaces', 'openvpn']):
+ # Nothing to do
+ sys.exit(0)
+else:
+ ovpn_intfs = config.list_nodes(['interfaces', 'openvpn'])
+ for i in ovpn_intfs:
+ # Remove 'encryption cipher' and add this value to 'encryption ncp-ciphers'
+ # for server and client mode.
+ # Site-to-site mode still can use --cipher option
+ cipher_path = ['interfaces', 'openvpn', i, 'encryption', 'cipher']
+ ncp_cipher_path = ['interfaces', 'openvpn', i, 'encryption', 'ncp-ciphers']
+ if config.exists(cipher_path):
+ if config.exists(['interfaces', 'openvpn', i, 'shared-secret-key']):
+ continue
+ cipher = config.return_value(cipher_path)
+ config.delete(cipher_path)
+ if cipher == 'none':
+ if not config.exists(ncp_cipher_path):
+ config.delete(['interfaces', 'openvpn', i, 'encryption'])
+ continue
+
+ ncp_ciphers = []
+ if config.exists(ncp_cipher_path):
+ ncp_ciphers = config.return_values(ncp_cipher_path)
+ config.delete(ncp_cipher_path)
+
+ # need to add the deleted cipher at the first place in the list
+ if cipher in ncp_ciphers:
+ ncp_ciphers.remove(cipher)
+ ncp_ciphers.insert(0, cipher)
+
+ for c in ncp_ciphers:
+ config.set(ncp_cipher_path, value=c, 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))
+ sys.exit(1)
diff --git a/src/op_mode/conntrack_sync.py b/src/op_mode/conntrack_sync.py
index 6c86ff492..f3b09b452 100755
--- a/src/op_mode/conntrack_sync.py
+++ b/src/op_mode/conntrack_sync.py
@@ -19,6 +19,8 @@ import sys
import syslog
import xmltodict
+from tabulate import tabulate
+
import vyos.opmode
from vyos.configquery import CliShellApiConfigQuery
@@ -27,7 +29,6 @@ from vyos.utils.commit import commit_in_progress
from vyos.utils.process import call
from vyos.utils.process import cmd
from vyos.utils.process import run
-from vyos.template import render_to_string
conntrackd_bin = '/usr/sbin/conntrackd'
conntrackd_config = '/run/conntrackd/conntrackd.conf'
@@ -59,6 +60,26 @@ def flush_cache(direction):
if tmp > 0:
raise vyos.opmode.Error('Failed to clear {direction} cache')
+def get_formatted_output(data):
+ data_entries = []
+ for parsed in data:
+ for meta in parsed.get('flow', {}).get('meta', []):
+ direction = meta['@direction']
+ if direction == 'original':
+ src = meta['layer3']['src']
+ dst = meta['layer3']['dst']
+ sport = meta['layer4'].get('sport')
+ dport = meta['layer4'].get('dport')
+ protocol = meta['layer4'].get('@protoname')
+ orig_src = f'{src}:{sport}' if sport else src
+ orig_dst = f'{dst}:{dport}' if dport else dst
+
+ data_entries.append([orig_src, orig_dst, protocol])
+
+ headers = ["Source", "Destination", "Protocol"]
+ output = tabulate(data_entries, headers, tablefmt="simple")
+ return output
+
def from_xml(raw, xml):
out = []
for line in xml.splitlines():
@@ -70,7 +91,7 @@ def from_xml(raw, xml):
if raw:
return out
else:
- return render_to_string('conntrackd/conntrackd.op-mode.j2', {'data' : out})
+ return get_formatted_output(out)
def restart():
is_configured()
diff --git a/src/op_mode/lldp.py b/src/op_mode/lldp.py
index 58cfce443..fac622b81 100755
--- a/src/op_mode/lldp.py
+++ b/src/op_mode/lldp.py
@@ -120,7 +120,12 @@ def _get_formatted_output(raw_data):
tmp.append('')
# Remote interface
- interface = jmespath.search('port.descr', values)
+ interface = None
+ if jmespath.search('port.id.type', values) == 'ifname':
+ # Remote peer has explicitly returned the interface name as the PortID
+ interface = jmespath.search('port.id.value', values)
+ if not interface:
+ interface = jmespath.search('port.descr', values)
if not interface:
interface = jmespath.search('port.id.value', values)
if not interface:
@@ -136,11 +141,17 @@ def _get_formatted_output(raw_data):
@_verify
def show_neighbors(raw: bool, interface: typing.Optional[str], detail: typing.Optional[bool]):
- lldp_data = _get_raw_data(interface=interface, detail=detail)
- if raw:
- return lldp_data
- else:
- return _get_formatted_output(lldp_data)
+ if raw or not detail:
+ lldp_data = _get_raw_data(interface=interface, detail=detail)
+ if raw:
+ return lldp_data
+ else:
+ return _get_formatted_output(lldp_data)
+ else: # non-raw, detail
+ tmp = 'lldpcli -f text show neighbors details'
+ if interface:
+ tmp += f' ports {interface}'
+ return cmd(tmp)
if __name__ == "__main__":
try:
diff --git a/src/op_mode/tcpdump.py b/src/op_mode/tcpdump.py
new file mode 100644
index 000000000..607b59603
--- /dev/null
+++ b/src/op_mode/tcpdump.py
@@ -0,0 +1,165 @@
+#! /usr/bin/env python3
+
+# Copyright (C) 2024 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
+
+from vyos.utils.process import call
+
+options = {
+ 'dump': {
+ 'cmd': '{command} -A',
+ 'type': 'noarg',
+ 'help': 'Print each packet (minus its link level header) in ASCII.'
+ },
+ 'hexdump': {
+ 'cmd': '{command} -X',
+ 'type': 'noarg',
+ 'help': 'Print each packet (minus its link level header) in both hex and ASCII.'
+ },
+ 'filter': {
+ 'cmd': '{command} \'{value}\'',
+ 'type': '<pcap-filter>',
+ 'help': 'Match traffic for capture and display with a pcap-filter expression.'
+ },
+ 'numeric': {
+ 'cmd': '{command} -nn',
+ 'type': 'noarg',
+ 'help': 'Do not attempt to resolve addresses, protocols or services to names.'
+ },
+ 'save': {
+ 'cmd': '{command} -w {value}',
+ 'type': '<file>',
+ 'help': 'Write captured raw packets to <file> rather than parsing or printing them out.'
+ },
+ 'verbose': {
+ 'cmd': '{command} -vvv -ne',
+ 'type': 'noarg',
+ 'help': 'Parse packets with increased detail output, including link-level headers and extended decoding protocol sanity checks.'
+ },
+}
+
+tcpdump = 'sudo /usr/bin/tcpdump'
+
+class List(list):
+ def first(self):
+ return self.pop(0) if self else ''
+
+ def last(self):
+ return self.pop() if self else ''
+
+ def prepend(self, value):
+ self.insert(0, value)
+
+
+def completion_failure(option: str) -> None:
+ """
+ Shows failure message after TAB when option is wrong
+ :param option: failure option
+ :type str:
+ """
+ sys.stderr.write('\n\n Invalid option: {}\n\n'.format(option))
+ sys.stdout.write('<nocomps>')
+ sys.exit(1)
+
+
+def expansion_failure(option, completions):
+ reason = 'Ambiguous' if completions else 'Invalid'
+ sys.stderr.write(
+ '\n\n {} command: {} [{}]\n\n'.format(reason, ' '.join(sys.argv),
+ option))
+ if completions:
+ sys.stderr.write(' Possible completions:\n ')
+ sys.stderr.write('\n '.join(completions))
+ sys.stderr.write('\n')
+ sys.stdout.write('<nocomps>')
+ sys.exit(1)
+
+
+def complete(prefix):
+ return [o for o in options if o.startswith(prefix)]
+
+
+def convert(command, args):
+ while args:
+ shortname = args.first()
+ longnames = complete(shortname)
+ if len(longnames) != 1:
+ expansion_failure(shortname, longnames)
+ longname = longnames[0]
+ if options[longname]['type'] == 'noarg':
+ command = options[longname]['cmd'].format(
+ command=command, value='')
+ elif not args:
+ sys.exit(f'monitor traffic: missing argument for {longname} option')
+ else:
+ command = options[longname]['cmd'].format(
+ command=command, value=args.first())
+ return command
+
+
+if __name__ == '__main__':
+ args = List(sys.argv[1:])
+ ifname = args.first()
+
+ # Slightly simplified & tweaked version of the code from mtr.py - it may be
+ # worthwhile to combine and centralise this in a common module.
+ if ifname == '--get-options-nested':
+ args.first() # pop monitor
+ args.first() # pop traffic
+ args.first() # pop interface
+ args.first() # pop <ifname>
+ usedoptionslist = []
+ while args:
+ option = args.first() # pop option
+ matched = complete(option) # get option parameters
+ usedoptionslist.append(option) # list of used options
+ # Select options
+ if not args:
+ # remove from Possible completions used options
+ for o in usedoptionslist:
+ if o in matched:
+ matched.remove(o)
+ if not matched:
+ sys.stdout.write('<nocomps>')
+ else:
+ sys.stdout.write(' '.join(matched))
+ sys.exit(0)
+
+ if len(matched) > 1:
+ sys.stdout.write(' '.join(matched))
+ sys.exit(0)
+ # If option doesn't have value
+ if matched:
+ if options[matched[0]]['type'] == 'noarg':
+ continue
+ else:
+ # Unexpected option
+ completion_failure(option)
+
+ value = args.first() # pop option's value
+ if not args:
+ matched = complete(option)
+ helplines = options[matched[0]]['type']
+ # Run helpfunction to get list of possible values
+ if 'helpfunction' in options[matched[0]]:
+ result = options[matched[0]]['helpfunction']()
+ if result:
+ helplines = '\n' + ' '.join(result)
+ sys.stdout.write(helplines)
+ sys.exit(0)
+
+ command = convert(tcpdump, args)
+ call(f'{command} -i {ifname}')