| Age | Commit message (Collapse) | Author |
|
The tunnel-type teb check ran after the member loop instead of inside
it, so only the last member was validated. The check now runs for each
member.
Bridge members are now also checked against the list of existing VPP
interfaces. Previously a member with an allowed prefix but no matching
VPP interface was committed but never added to the bridge in VPP; it is
now rejected at commit.
|
|
frrender: T9454: render FRR after a DHCP lease only once the commit completed
|
|
The renderer (vyos.template.kea_client_class_json()) already skips
classes with 'disable' set, so they never reach Kea and don't need a
match condition. verify() didn't know about this and rejected them
regardless, breaking configs that committed fine before this feature:
a disabled class with no relay-agent-information/hostname/vendor-class-id
now failed to commit, and on a fresh boot that took the whole
service dhcp-server subtree down with it (reported by alexk37).
|
|
A client-class with an empty "relay-agent-information" node (neither
circuit-id nor remote-id set) passed the "at least one match
condition" guard added for the empty-class-config gap, since that
guard only checked key presence, not that the node actually carries a
match condition - reproducing the same empty Kea "test" expression bug
via a different path.
Flagged by coderabbitai in review of PR #5436.
|
|
The Mikrotik configuration referenced by T9267 uses
matching-type=substring, documented to match the value anywhere within
the option string. This PR's "substring" match instead compared a
fixed-length slice at a fixed byte offset (default 0) for exact
equality - effectively an anchored prefix match, not a substring
search - which does not reliably reproduce the ticket's own use case
of picking a device model string (e.g. "T42S") out of a longer,
variably-formatted hostname.
Rebuild "hostname substring"/"vendor-class-id substring" on Kea's
match()+lcase() instead of substring()==, so a configured value now
matches anywhere in the option content and case-insensitively (options
like vendor-class-id are not guaranteed to arrive in a fixed case).
Drop the "offset" leaf together with it, since it has no remaining
purpose once matching is no longer anchored to a fixed position, and
there is no released behavior to preserve.
Raw hex input and values containing a literal single quote are
rejected for substring matching in verify(), since neither can be
safely embedded into the generated Kea regular expression; exact
"value" matching is unaffected and still accepts both.
Reported by alexk37 in review of PR #5436.
|
|
A client-class with options but no relay-agent-information, hostname,
or vendor-class-id passed verify() and produced an empty Kea "test"
expression, which Kea's config parser then rejected with an opaque
syntax error at commit time instead of a VyOS ConfigError.
Likewise, a bare "hostname"/"vendor-class-id" node with neither
"value" nor "substring value" set passed verify() and crashed with an
unhandled KeyError while rendering the Kea class test string.
Reported by alexk37 in review of PR #5436.
|
|
Client classes could previously only match on relay agent information
(Option 82). Add matching on the client-sent hostname (Option 12) and
vendor class identifier (Option 60), each with an exact-value or
substring form, so clients sharing a subnet can be told apart by e.g.
device model without splitting the subnet into per-model pools.
Also let a client-class deliver its own options (reusing the existing
subnet/range option syntax), so a match can directly hand out a
model-specific value such as a provisioning URL, independent of which
pool the client's lease is drawn from.
|
|
dhcp: T9108: restart dhclient when unicast RENEW is overdue
|
|
http-api: T9453: wait for the API server to be ready after a reload
|
|
vyos-router: T9447: stop copying a directory when restoring the bootup hooks
|
|
container: T9456: use kernel overlayfs unless storage sits on overlayfs
|
|
vpp: T9161: Fix smoketests failing on NICs capped at 1500 MTU
|
|
pseudo-ethernet: T9253: fix anycast-gateway with shared MAC on bridge VLANs
|
|
Options rejected or overridden on a bond member were reported with their
internal names, e.g. "vif_s 10 vif_c 100 address". Messages now use the CLI
spelling: "vif-s 10 vif-c 100 address".
|
|
container: T9401: add chown option to tmpfs mounts
|
|
firewall: T9332: fix GeoIP source/destination nftables set name colliā¦
|
|
Since T5003 every system was configured to mount container storage via
fuse-overlayfs. This is only needed on live boot, where the storage sits
on the root overlayfs and podman refuses native overlay. Installed
systems keep it on the persistence partition and paid for a userspace
FUSE process per container plus a round trip on every file operation.
The mount program is now only configured when the storage is backed by
overlayfs, otherwise the kernel overlay driver is used.
Existing storage keeps using fuse-overlayfs: podman records that a mount
program was used, as its layers store whiteouts in a format the kernel
driver does not understand. Moving such a system to kernel overlayfs
requires resetting the container storage and re-pulling all images.
|
|
A lease event during a commit rendered FRR from the active configuration, which
the commit has not replaced yet. When the lease arrived after the commit's own
FRR render but before the commit finished, the stale render was applied and
nothing corrected it: moving a DHCP interface into a VRF left the VRF without
its default route.
The lease hook now starts the render detached and the render waits for the
running commit to complete. Detaching is required, as a commit stopping the
DHCP client waits for the release hook. Waiting is opt-in, as the commit itself
uses the same helper when it cannot reach the configuration daemon.
|
|
A commit that changes an already running HTTP API only signals the server
and returns at once. The server then restarts uvicorn asynchronously, and
until it listens again requests through nginx fail. A fixed one-second
sleep was meant to cover this but is too short on slow systems, making
the https smoketest fail intermittently and API clients see errors right
after a commit.
The server now creates a readiness marker once it accepts requests. The
commit clears the marker before reloading and waits for it to reappear,
warning if that takes longer than 30 seconds.
|
|
Static key mode only supports CBC, so OpenVPN refuses to start with an
AEAD "data-ciphers-fallback" just like with an AEAD "encryption cipher".
Reject it at commit time.
|
|
config-management: T6304: Rewrite commit-archive location into a structured CLI
|
|
VPP now rejects an MTU above the NIC limit, but the CI NICs are capped
at 1500, so tests using MTU 2500 on eth1 failed. The rejected commit
also left a queued initial VPP dependency in the commit daemon, which
the next commit ran with the old config, so every following test failed
too. Pending initial dependents are now cleared before each script run
in vyos-configd and vyos-commitd, and the tests use MTUs that fit any
NIC.
|
|
Several anycast-gateway pseudo-ethernets with the same MAC on different
VLANs of one bridge (the usual EVPN layout) failed to commit with
"bridge fdb add ... File exists". The local FDB entry was always installed
without a VLAN, so every interface competed for the same entry. A failing
commit at boot left only one interface configured and dropped the rest of
the config.
The local FDB entry is now bound to the VLAN of the bridge sub-interface
when the bridge is VLAN aware, and it is installed with replace so a
re-commit over an existing entry no longer fails. Two anycast-gateways
with the same MAC on the same source-interface are rejected.
|
|
A boot whose configuration directory carries no pre/post-config hook scripts
copies them out of the running image. That copy named the image root twice,
because the image's squashfs is mounted at two paths and the variable holding
it kept both. One extra operand reached cp as a bare directory:
cp: -r not specified; omitting directory '/run/live/rootfs/<image>.squashfs'
The hook itself still landed, so nothing broke, but the copy reported failure
and was one word-split away from restoring the wrong file. It shows up where
the encrypted configuration volume stays shut, leaving the directory beneath
it empty.
The image root is now a single path, the two identical restore paths share one
implementation, and a copy that fails is logged rather than passing silently.
A missing hook is not escalated - on a first boot that would hand the system to
the upgrade-failure rollback.
|
|
On a VPP-bound interface the MTU limit is the NIC's, which only VPP knows
(the kernel side is an LCP tap reporting a meaningless larger max). Reject at
commit an MTU larger than that limit, read from VPP's 'show hardware-interfaces'
(max mtu + driver frame overhead), so the kernel and dataplane cannot silently
end up with different MTUs.
Also apply a VLAN sub-interface's MTU to its VPP dataplane sub-interface and its
linux-cp tap (created with MTU 0), not just the parent; a sub-interface without
its own MTU inherits the parent's. Covers ethernet (vif/vif-s) and VPP
bond/loopback (vif).
|
|
configd: T9368: reconcile FRR after a DHCP lease without the commit socket
|
|
openvpn: T9370: add chacha20poly1305 data cipher
|
|
A PPPoE session is restarted from within the commit that changes it and comes
back up milliseconds later, while that commit is still running. The hook which
then configures the interface reads the running configuration, which until the
commit finishes is still the one from before it. Everything the commit adds is
missing at that point: for an interface newly set to IPv6 autoconf the hook
disabled router advertisements and autoconfiguration on the link, and nothing
turned them back on. The link kept its link-local address and never received a
global one, until the next commit or reconnect.
Which interface is hit varies with the order the commit happens to process
them, so this surfaced as an intermittent failure.
The hook now waits for the commit to finish before reading the configuration.
|
|
Reconciling the FRR configuration after a DHCP lease event was requested from
the configuration daemon over the socket the commit pipeline uses. The daemon
serves one client at a time and assumes it is the running commit, so
the request either landed in the middle of the handshake which hands over the
configuration, or kept the daemon busy past the 10ms a commit waits for it.
Either way the commit fell back to running the conf-mode scripts directly.
Those never render FRR, only the daemon does, so the commit succeeded while FRR
kept the configuration rendered before it, until the next lease event.
A lease event now renders FRR in its own process, and a commit which could not
use the daemon renders FRR itself instead of skipping the reload. Both take the
same lock. A commit post-hook would remove the second case, for a full render
on every commit.
|
|
Replace the free-form 'commit-archive location <url>' leafNode with a
structured, per-destination tagNode:
`set system config-management commit-archive location <name> <protocol> \
authentication { username | password } | server | port | path`
Each location selects exactly one transport protocol (scp, sftp, ssh, ftp,
ftps, http, https, git, tftp). 'git' additionally accepts a 'transport'
(https/http/ssh, default https). 'source-address' and 'vrf' stay under
'commit-archive' and apply to every location, as before.
|
|
Since T9024 (Podman 5.8.4, crun replaced by runc 1.1.5), a tmpfs mounted
over a directory that already exists in the image is owned by root:root
0755, whatever the image prepared. A container running as a non-root
user (image USER or uid/gid) can no longer write its pid file or control
socket there and fails to start. With crun 1.8.1 every tmpfs was 1777,
so the same configuration used to work.
runc 1.1.5 ignores tmpfs-mode; the Podman mount option `U` (chown the
mount to the container user) is the only one that works on the runtime
VyOS ships. Expose it as a valueless `chown` node:
set container name <name> tmpfs <tag> chown
Without the option the generated Quadlet line is unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
"show secure-boot" only reported whether Secure Boot is enabled, not who
signed the running Linux Kernel. An image signed by the VyOS CA could not be
told apart from one signed with a custom Machine Owner Key.
"show secure-boot detail" now lists issuer and subject of the Kernel image
signature certificates. The same information is added to the raw
"show version" data as "secure_boot_detail", issuer and subject delimited by
",". The key is only present when Secure Boot is enabled and a signature
could be read.
|
|
verify() looked up each prefix-list rule in a list of the rules seen
so far, which is quadratic in the size of the list and runs on every
policy commit. verify() alone, run from the source on a workstation,
took 41.8 s for a 40,000-rule list; on a 1.5.1 VM the check cost 0.08 s
at 2,000 rules.
Keep a set of the rules' sorted items instead. Every value under a
prefix-list rule is a single leaf, so the key is hashable, and two keys
are equal exactly when the rule dicts are: the same rules are flagged,
with the same message. The workstation benchmark took 0.11 s.
|
|
Offer chacha20poly1305 in "encryption data-ciphers" and
"encryption data-ciphers-fallback", rendered as CHACHA20-POLY1305 and
allowed with DCO.
|
|
T9364: openvpn: default the MTU to 1420 when DCO is enabled
|
|
wwan: T7487: identify modem by port ownership, not interface number
|
|
The ovpn Kernel module does no MSS clamping, so with a 1500 bytes MTU
full sized packets get fragmented on the underlay.
Add an "mtu" node, rendered as "tun-mtu". With "offload dco" it
defaults to 1420, unless a raw tun-mtu/link-mtu/udp-mtu option is
present. Reject "mtu" together with such an option, below 100, and
below 1280 when IPv6 runs inside the tunnel.
|
|
http-api: T8989: Hotfix to enforce audience validation if OIDC is configured
|
|
"failure-count" counts missed intervals, so the timeout it describes is
interval * failure-count. Server mode renders and verifies it that way;
site-to-site passed the bare count to "ping-restart", where it lands as
seconds - 60s instead of 600s with the defaults.
Render the product. That puts a timeout past the 86400 "ping-restart"
accepts within reach, so verify() rejects it and the 5-to-6 migration
clamps configurations already beyond it.
This changes behaviour on upgrade: site-to-site tunnels now tolerate a
longer silence, 600 seconds instead of 60 with the defaults.
|
|
openvpn: T8999: improve shared-secret reference errors
|
|
modem_index() in python/vyos/utils/wwan.py derived the ModemManager modem index straight from the interface name (wwan0 -> 0). The kernel-assigned WWAN interface number and ModemManager's own modem index are two independently enumerated values and are not guaranteed to match - on a box with more than one modem, they can enumerate in different orders, so modem index 0 does not necessarily own wwan0. Every function in this module funnels through modem_index() (start_modem_manager, modem_disconnect, modem_connect, and both admin-disconnect marker helpers), and is_wwan_connected() in vyos.utils.network had its own separate copy of the same assumption - so a single reversed enumeration order silently commands the wrong physical modem for every one of them.
modem_index() now lists every modem ModemManager currently knows about and returns whichever one actually has ifname in its own port list, instead of assuming the correspondence. A modem that has not shown up on the bus yet looks the same as one that will never exist, so this waits up to the same modem_wait_timeout budget start_modem_manager() already gives a modem to become dialable, then returns None if nothing claimed the interface. is_wwan_connected() now calls the same resolver instead of keeping its own copy of the old assumption.
None is a real, expected return now, not just a theoretical one - the three callers that previously assumed modem_index() always produced *a* string (right or wrong) are updated: start_modem_manager() bails out early (matching the tolerance its own caller's w.exists() check already has for hardware that isn't detected yet), modem_disconnect() and modem_connect() treat it as nothing to disconnect / a failed dial, matching each function's own existing return contract. show_wwan.py's modem_info() raises a clear, specific error instead, which its own top-level exception handler already reports cleanly. set_admin_disconnected()/clear_admin_disconnected() only ever used modem_index() to validate the interface name looks like a WWAN interface in the first place, so they're unaffected.
|
|
wwan: T9350: possible dead interface after boot, disconnect does not stick
|
|
|
|
op-mode: T9354: replace "reset connection" with "reconnect interface"
|
|
pim: T9362: prevent killing an already dead/non-existing PID
|
|
|
|
T8977: Fix regression with is_addr_assigned and is_listen_port_bind_service
|
|
The daemon is not guaranteed to be running when PIM is removed - it may have
never started, or already died.
|
|
create_private_key() took one "size" for every key type, but the number
means entirely different things per type: for RSA and DSA it is a modulus
size, for EC it selects a curve. CodeQL is not path sensitive across the
key_type comparison, so it follows the 256 an EC caller passes into the
RSA and DSA branches that caller can never reach, and reports pki.py as
generating 256 bit RSA and DSA keys.
Build elliptic curve keys in create_ec_private_key() instead and route the
op mode generator and the OpenVPN smoketest there, so no curve size ever
enters the function that also builds RSA and DSA keys.
create_private_key() now refuses a key type it does not build rather than
returning None, so a caller cannot drift back into the old shape
unnoticed.
|
|
ipsec: T9303: use ipsec-acceleration for VPP algo check
|