summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/conf_mode/service_dns_forwarding.py7
-rwxr-xr-xsrc/conf_mode/system_login.py10
-rwxr-xr-xsrc/etc/netplug/vyos-netplug-dhcp-client3
-rwxr-xr-xsrc/init/vyos-router2
-rwxr-xr-xsrc/op_mode/image_installer.py5
-rwxr-xr-xsrc/op_mode/stp.py185
-rwxr-xr-xsrc/services/vyos-commitd14
-rwxr-xr-xsrc/services/vyos-conntrack-logger2
-rwxr-xr-xsrc/services/vyos-hostsd4
9 files changed, 213 insertions, 19 deletions
diff --git a/src/conf_mode/service_dns_forwarding.py b/src/conf_mode/service_dns_forwarding.py
index e3bdbc9f8..5636d6f83 100755
--- a/src/conf_mode/service_dns_forwarding.py
+++ b/src/conf_mode/service_dns_forwarding.py
@@ -366,6 +366,13 @@ def apply(dns):
hc.add_name_server_tags_recursor(['dhcp-' + interface,
'dhcpv6-' + interface ])
+ # add dhcp interfaces
+ if 'dhcp' in dns:
+ for interface in dns['dhcp']:
+ if interface_exists(interface):
+ hc.add_name_server_tags_recursor(['dhcp-' + interface,
+ 'dhcpv6-' + interface ])
+
# hostsd will generate the forward-zones file
# the list and keys() are required as get returns a dict, not list
hc.delete_forward_zones(list(hc.get_forward_zones().keys()))
diff --git a/src/conf_mode/system_login.py b/src/conf_mode/system_login.py
index 3fed6d273..4febb6494 100755
--- a/src/conf_mode/system_login.py
+++ b/src/conf_mode/system_login.py
@@ -15,7 +15,6 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
-import warnings
from passlib.hosts import linux_context
from psutil import users
@@ -30,12 +29,9 @@ from vyos.config import Config
from vyos.configverify import verify_vrf
from vyos.template import render
from vyos.template import is_ipv4
-from vyos.utils.auth import (
- DEFAULT_PASSWORD,
- EPasswdStrength,
- evaluate_strength,
- get_current_user
-)
+from vyos.utils.auth import EPasswdStrength
+from vyos.utils.auth import evaluate_strength
+from vyos.utils.auth import get_current_user
from vyos.utils.configfs import delete_cli_node
from vyos.utils.configfs import add_cli_node
from vyos.utils.dict import dict_search
diff --git a/src/etc/netplug/vyos-netplug-dhcp-client b/src/etc/netplug/vyos-netplug-dhcp-client
index 4cc824afd..7fe6cda75 100755
--- a/src/etc/netplug/vyos-netplug-dhcp-client
+++ b/src/etc/netplug/vyos-netplug-dhcp-client
@@ -54,4 +54,5 @@ interface_path = ['interfaces'] + Section.get_config_path(interface).split()
_, interface_config = get_interface_dict(
config, interface_path[:-1], ifname=interface, with_pki=True
)
-Interface(interface).update(interface_config)
+if 'deleted' not in interface_config:
+ Interface(interface).update(interface_config)
diff --git a/src/init/vyos-router b/src/init/vyos-router
index ab3cc42cb..565b778e6 100755
--- a/src/init/vyos-router
+++ b/src/init/vyos-router
@@ -417,6 +417,7 @@ gen_duid ()
start ()
{
+ echo -e "Initializing VyOS router\033[0m"
# reset and clean config files
security_reset || log_failure_msg "security reset failed"
@@ -517,7 +518,6 @@ start ()
cleanup_post_commit_hooks
- log_daemon_msg "Starting VyOS router"
disabled migrate || migrate_bootfile
restore_if_missing_preconfig_script
diff --git a/src/op_mode/image_installer.py b/src/op_mode/image_installer.py
index 9c17d0229..179913f15 100755
--- a/src/op_mode/image_installer.py
+++ b/src/op_mode/image_installer.py
@@ -74,6 +74,7 @@ MSG_INPUT_CONFIG_FOUND: str = 'An active configuration was found. Would you like
MSG_INPUT_CONFIG_CHOICE: str = 'The following config files are available for boot:'
MSG_INPUT_CONFIG_CHOOSE: str = 'Which file would you like as boot config?'
MSG_INPUT_IMAGE_NAME: str = 'What would you like to name this image?'
+MSG_INPUT_IMAGE_NAME_TAKEN: str = 'There is already an installed image by that name; please choose again'
MSG_INPUT_IMAGE_DEFAULT: str = 'Would you like to set the new image as the default one for boot?'
MSG_INPUT_PASSWORD: str = 'Please enter a password for the "vyos" user:'
MSG_INPUT_PASSWORD_CONFIRM: str = 'Please confirm password for the "vyos" user:'
@@ -984,8 +985,12 @@ def add_image(image_path: str, vrf: str = None, username: str = '',
f'Adding image would downgrade image tools to v.{cfg_ver}; disallowed')
if not no_prompt:
+ versions = grub.version_list()
while True:
image_name: str = ask_input(MSG_INPUT_IMAGE_NAME, version_name)
+ if image_name in versions:
+ print(MSG_INPUT_IMAGE_NAME_TAKEN)
+ continue
if image.validate_name(image_name):
break
print(MSG_WARN_IMAGE_NAME_WRONG)
diff --git a/src/op_mode/stp.py b/src/op_mode/stp.py
new file mode 100755
index 000000000..fb57bd7ee
--- /dev/null
+++ b/src/op_mode/stp.py
@@ -0,0 +1,185 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2025 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 typing
+import json
+from tabulate import tabulate
+
+import vyos.opmode
+from vyos.utils.process import cmd
+from vyos.utils.network import interface_exists
+
+def detailed_output(dataset, headers):
+ for data in dataset:
+ adjusted_rule = data + [""] * (len(headers) - len(data)) # account for different header length, like default-action
+ transformed_rule = [[header, adjusted_rule[i]] for i, header in enumerate(headers) if i < len(adjusted_rule)] # create key-pair list from headers and rules lists; wrap at 100 char
+
+ print(tabulate(transformed_rule, tablefmt="presto"))
+ print()
+
+def _get_bridge_vlan_data(iface):
+ allowed_vlans = []
+ native_vlan = None
+ vlanData = json.loads(cmd(f"bridge -j -d vlan show"))
+ for vlans in vlanData:
+ if vlans['ifname'] == iface:
+ for allowed in vlans['vlans']:
+ if "flags" in allowed and "PVID" in allowed["flags"]:
+ native_vlan = allowed['vlan']
+ elif allowed.get('vlanEnd', None):
+ allowed_vlans.append(f"{allowed['vlan']}-{allowed['vlanEnd']}")
+ else:
+ allowed_vlans.append(str(allowed['vlan']))
+
+ if not allowed_vlans:
+ allowed_vlans = ["none"]
+ if not native_vlan:
+ native_vlan = "none"
+
+ return ",".join(allowed_vlans), native_vlan
+
+def _get_stp_data(ifname, brInfo, brStatus):
+ tmpInfo = {}
+
+ tmpInfo['bridge_name'] = brInfo.get('ifname')
+ tmpInfo['up_state'] = brInfo.get('operstate')
+ tmpInfo['priority'] = brInfo.get('linkinfo').get('info_data').get('priority')
+ tmpInfo['vlan_filtering'] = "Enabled" if brInfo.get('linkinfo').get('info_data').get('vlan_filtering') == 1 else "Disabled"
+ tmpInfo['vlan_protocol'] = brInfo.get('linkinfo').get('info_data').get('vlan_protocol')
+
+ # The version of VyOS I tested had am issue with the "ip -d link show type bridge"
+ # output. The root_id was always the local bridge, even though the underlying system
+ # understood when it wasn't. Could be an upstream Bug. I pull from the "/sys/class/net"
+ # structure instead. This can be changed later if the "ip link" behavior is corrected.
+
+ #tmpInfo['bridge_id'] = brInfo.get('linkinfo').get('info_data').get('bridge_id')
+ #tmpInfo['root_id'] = brInfo.get('linkinfo').get('info_data').get('root_id')
+
+ tmpInfo['bridge_id'] = cmd(f"cat /sys/class/net/{brInfo.get('ifname')}/bridge/bridge_id").split('.')
+ tmpInfo['root_id'] = cmd(f"cat /sys/class/net/{brInfo.get('ifname')}/bridge/root_id").split('.')
+
+ # The "/sys/class/net" structure stores the IDs without seperators like ':' or '.'
+ # This adds a ':' after every 2 characters to make it resemble a MAC Address
+ tmpInfo['bridge_id'][1] = ':'.join(tmpInfo['bridge_id'][1][i:i+2] for i in range(0, len(tmpInfo['bridge_id'][1]), 2))
+ tmpInfo['root_id'][1] = ':'.join(tmpInfo['root_id'][1][i:i+2] for i in range(0, len(tmpInfo['root_id'][1]), 2))
+
+ tmpInfo['stp_state'] = "Enabled" if brInfo.get('linkinfo', {}).get('info_data', {}).get('stp_state') == 1 else "Disabled"
+
+ # I don't call any of these values, but I created them to be called within raw output if desired
+
+ tmpInfo['mcast_snooping'] = "Enabled" if brInfo.get('linkinfo').get('info_data').get('mcast_snooping') == 1 else "Disabled"
+ tmpInfo['rxbytes'] = brInfo.get('stats64').get('rx').get('bytes')
+ tmpInfo['rxpackets'] = brInfo.get('stats64').get('rx').get('packets')
+ tmpInfo['rxerrors'] = brInfo.get('stats64').get('rx').get('errors')
+ tmpInfo['rxdropped'] = brInfo.get('stats64').get('rx').get('dropped')
+ tmpInfo['rxover_errors'] = brInfo.get('stats64').get('rx').get('over_errors')
+ tmpInfo['rxmulticast'] = brInfo.get('stats64').get('rx').get('multicast')
+ tmpInfo['txbytes'] = brInfo.get('stats64').get('tx').get('bytes')
+ tmpInfo['txpackets'] = brInfo.get('stats64').get('tx').get('packets')
+ tmpInfo['txerrors'] = brInfo.get('stats64').get('tx').get('errors')
+ tmpInfo['txdropped'] = brInfo.get('stats64').get('tx').get('dropped')
+ tmpInfo['txcarrier_errors'] = brInfo.get('stats64').get('tx').get('carrier_errors')
+ tmpInfo['txcollosions'] = brInfo.get('stats64').get('tx').get('collisions')
+
+ tmpStatus = []
+ for members in brStatus:
+ if members.get('master') == brInfo.get('ifname'):
+ allowed_vlans, native_vlan = _get_bridge_vlan_data(members['ifname'])
+ tmpStatus.append({'interface': members.get('ifname'),
+ 'state': members.get('state').capitalize(),
+ 'mtu': members.get('mtu'),
+ 'pathcost': members.get('cost'),
+ 'bpduguard': "Enabled" if members.get('guard') == True else "Disabled",
+ 'rootguard': "Enabled" if members.get('root_block') == True else "Disabled",
+ 'mac_learning': "Enabled" if members.get('learning') == True else "Disabled",
+ 'neigh_suppress': "Enabled" if members.get('neigh_suppress') == True else "Disabled",
+ 'vlan_tunnel': "Enabled" if members.get('vlan_tunnel') == True else "Disabled",
+ 'isolated': "Enabled" if members.get('isolated') == True else "Disabled",
+ **({'allowed_vlans': allowed_vlans} if allowed_vlans else {}),
+ **({'native_vlan': native_vlan} if native_vlan else {})})
+
+ tmpInfo['members'] = tmpStatus
+ return tmpInfo
+
+def show_stp(raw: bool, ifname: typing.Optional[str], detail: bool):
+ rawList = []
+ rawDict = {'stp': []}
+
+ if ifname:
+ if not interface_exists(ifname):
+ raise vyos.opmode.Error(f"{ifname} does not exist!")
+ else:
+ ifname = ""
+
+ bridgeInfo = json.loads(cmd(f"ip -j -d -s link show type bridge {ifname}"))
+
+ if not bridgeInfo:
+ raise vyos.opmode.Error(f"No Bridges configured!")
+
+ bridgeStatus = json.loads(cmd(f"bridge -j -s -d link show"))
+
+ for bridges in bridgeInfo:
+ output_list = []
+ amRoot = ""
+ bridgeDict = _get_stp_data(ifname, bridges, bridgeStatus)
+
+ if bridgeDict['bridge_id'][1] == bridgeDict['root_id'][1]:
+ amRoot = " (This bridge is the root)"
+
+ print('-' * 80)
+ print(f"Bridge interface {bridgeDict['bridge_name']} ({bridgeDict['up_state']}):\n")
+ print(f"Spanning Tree is {bridgeDict['stp_state']}")
+ print(f"Bridge ID {bridgeDict['bridge_id'][1]}, Priority {int(bridgeDict['bridge_id'][0], 16)}")
+ print(f"Root ID {bridgeDict['root_id'][1]}, Priority {int(bridgeDict['root_id'][0], 16)}{amRoot}")
+ print(f"VLANs {bridgeDict['vlan_filtering'].capitalize()}, Protocol {bridgeDict['vlan_protocol']}")
+ print()
+
+ for members in bridgeDict['members']:
+ output_list.append([members['interface'],
+ members['state'],
+ *([members['pathcost']] if detail else []),
+ members['bpduguard'],
+ members['rootguard'],
+ members['mac_learning'],
+ *([members['neigh_suppress']] if detail else []),
+ *([members['vlan_tunnel']] if detail else []),
+ *([members['isolated']] if detail else []),
+ *([members['allowed_vlans']] if detail else []),
+ *([members['native_vlan']] if detail else [])])
+
+ if raw:
+ rawList.append(bridgeDict)
+ elif detail:
+ headers = ['Interface', 'State', 'Pathcost', 'BPDU_Guard', 'Root_Guard', 'Learning', 'Neighbor_Suppression', 'Q-in-Q', 'Port_Isolation', 'Allowed VLANs', 'Native VLAN']
+ detailed_output(output_list, headers)
+ else:
+ headers = ['Interface', 'State', 'BPDU_Guard', 'Root_Guard', 'Learning']
+ print(tabulate(output_list, headers))
+ print()
+
+ if raw:
+ rawDict['stp'] = rawList
+ return rawDict
+
+if __name__ == '__main__':
+ try:
+ res = vyos.opmode.run(sys.modules[__name__])
+ if res:
+ print(res)
+ except (ValueError, vyos.opmode.Error) as e:
+ print(e)
+ sys.exit(1)
diff --git a/src/services/vyos-commitd b/src/services/vyos-commitd
index 55f0c8741..e7f2d82c7 100755
--- a/src/services/vyos-commitd
+++ b/src/services/vyos-commitd
@@ -233,8 +233,9 @@ def initialization(session: Session) -> Session:
scripts_called = []
setattr(config, 'scripts_called', scripts_called)
- dry_run = False
- setattr(config, 'dry_run', dry_run)
+ dry_run = session.dry_run
+ config.set_bool_attr('dry_run', dry_run)
+ logger.debug(f'commit dry_run is {dry_run}')
session.config = config
@@ -247,11 +248,16 @@ def run_script(script_name: str, config: Config, args: list) -> tuple[bool, str]
script = conf_mode_scripts[script_name]
script.argv = args
config.set_level([])
+ dry_run = config.get_bool_attr('dry_run')
try:
c = script.get_config(config)
script.verify(c)
- script.generate(c)
- script.apply(c)
+ if not dry_run:
+ script.generate(c)
+ script.apply(c)
+ else:
+ if hasattr(script, 'call_dependents'):
+ script.call_dependents()
except ConfigError as e:
logger.error(e)
return False, str(e)
diff --git a/src/services/vyos-conntrack-logger b/src/services/vyos-conntrack-logger
index 9c31b465f..ec0e1f717 100755
--- a/src/services/vyos-conntrack-logger
+++ b/src/services/vyos-conntrack-logger
@@ -15,10 +15,8 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import argparse
-import grp
import logging
import multiprocessing
-import os
import queue
import signal
import socket
diff --git a/src/services/vyos-hostsd b/src/services/vyos-hostsd
index 1ba90471e..44f03586c 100755
--- a/src/services/vyos-hostsd
+++ b/src/services/vyos-hostsd
@@ -233,10 +233,7 @@
# }
import os
-import sys
-import time
import json
-import signal
import traceback
import re
import logging
@@ -245,7 +242,6 @@ import zmq
from voluptuous import Schema, MultipleInvalid, Required, Any
from collections import OrderedDict
from vyos.utils.file import makedir
-from vyos.utils.permission import chown
from vyos.utils.permission import chmod_755
from vyos.utils.process import popen
from vyos.utils.process import process_named_running