Compare commits

...

139 commits

Author SHA1 Message Date
Beniamino Galvani
a31a644f8b merge: branch 'bg/deprecate-wext'
build: deprecate Wireless Extensions

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2309
2025-12-18 15:14:45 +00:00
Beniamino Galvani
a45163b131 rpm: disable wireless extensions on Fedora
The Fedora kernel is built without WEXT since many years:

https://fedoraproject.org/wiki/Changes/RemoveWirelessExtensions
2025-12-18 16:06:44 +01:00
Beniamino Galvani
de1fcdcc72 build: deprecate Wireless Extensions
Wireless Extensions is the legacy, ioctl-based kernel interface used
to configure Wi-Fi cards. It has been deprecated and replaced by the
cfg80211/nl80211 API since 2007, as it doesn't support modern Wi-Fi
encryption and technologies. Mark it as deprecated, so that we can get
rid of some unmaintained and untested code in a future release.
2025-12-18 16:06:42 +01:00
Beniamino Galvani
a2d147366c Merge branch 'bg/issue1688'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2323
2025-12-17 11:59:20 +01:00
Beniamino Galvani
427a7cf257 nmcli: start the agent only after updating the connection
When connecting to a wifi network and providing the password on the
command line, nmcli first looks if there is a compatible connection to
reuse. If there is not, it creates and activates a new one via a
single call to AddAndActivate().

If there is a compatible connection, nmcli first calls Update() on it
to set the new password and then Activate() to bring it up. Before
that, it registers a secret agent that can prompt for a new password
in case of authentication failure.

However, as soon as nmcli registers a secret agent, NM tries to
activate again the connection if it was blocked due to a previous
authentication failure. This connection attempt is going to fail
because it still uses the old password, as new one hasn't been set via
Update().

Change the order of operations to register the agent after Update()
and before Activate().

Reproducer:

 nmcli device wifi connect SSID password BAD_PASSWORD
 nmcli device wifi connect SSID password GOOD_PASSWORD

Fixes: c8ff1b30fb ('nmcli/dev: use secret agent for nmcli d [wifi] connect')
2025-12-17 10:55:51 +01:00
Beniamino Galvani
3a4e18e302 nmcli: fix "device wifi connect" command with existing connection
Executing this command twice, or when a connection profile already
exists for the SSID:

  nmcli device wifi connect $SSID password $PASSWORD

returns error:

  Error: 802-11-wireless-security.key-mgmt: property is missing.

When setting the password nmcli was wiping the existing wireless
security setting.

Fixes: c8ff1b30fb ('nmcli/dev: use secret agent for nmcli d [wifi] connect')

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/1688
2025-12-17 10:55:50 +01:00
Íñigo Huguet
8e0825f9cd release: bump version to 1.57.1 (development) 2025-12-12 16:01:44 +01:00
Íñigo Huguet
df8288de7f merge: branch 'ih/strerror_r'
Fix two compilation issues

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2330
2025-12-12 14:36:58 +00:00
Íñigo Huguet
118475d571 ci: build with -D systemdsystemgeneratordir=no
Avoid build failures in some distros.
  ERROR: Assert failed: systemd required but not found, please provide a valid systemd user generator dir or disable it

Fixes: 636fb5ef24 ('systemd: install initrd services using a generator')
2025-12-12 15:24:09 +01:00
Íñigo Huguet
599cc1ed1d std-aux: use _nm_strerror_r
The function strerror_r returns an int per POSIX spec, but GNU version
returns char *. Using it fails the compilation in Alpine, so use
_nm_strerror_r instead that handles both cases.

Fixes: 41e28b900f ('daemon-helper: add read-file-as-user')
2025-12-12 15:07:53 +01:00
Íñigo Huguet
1756ec54e3 merge: branch 'issue1809'
CVE-2025-9615: avoid that non-admin user using other users' certificates.

Closes #1809

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2324
2025-12-12 12:29:41 +00:00
Beniamino Galvani
1a52bbe7c9 libnm: add function to copy a certificate or key as user
Add a new public function nm_utils_copy_cert_as_user() to libnm. It
reads a certificate or key file on behalf of the given user and writes
it to a directory in /run/NetworkManager. It is useful for VPN plugins
that run as root and need to verify that the user owning the
connection (the one listed in the connection.permissions property) can
access the file.
2025-12-12 12:43:15 +01:00
Beniamino Galvani
57eb4a5bc6 vpn: check that plugin supports private connections
Only allow private VPN connections if the VPN plugin declares the
supports-safe-private-file-access capability. Also check that the
private connection doesn't have more than one owner.
2025-12-12 12:42:01 +01:00
Beniamino Galvani
10db4baeb6 vpn: add nm_vpn_plugin_info_supports_safe_private_file_access()
The new API indicates that the VPN plugin supports reading files
(certificates, keys) of private connections in a safe way
(i.e. checking user permissions), or that it doesn't need to read any
file from disk.
2025-12-12 12:41:28 +01:00
Beniamino Galvani
8d8edda3f4 core,libnm-core: introduce property flag for certificate and keys
If we add a new property in the future and it references a certificate
or key stored on disk, we need to also implement the logic to verify
the access to the file for private connections.

Add a new property flag NM_SETTING_PARAM_CERT_KEY_FILE to existing
certificate and key properties, so that it's easier to see that they
need special treatment. Also add some assertions to verify that the
properties with the flag are handled properly.

While at it, move the enumeration of private-files to the settings.
2025-12-12 12:38:50 +01:00
Beniamino Galvani
e85cc46d0b core: pass certificates as blobs to supplicant for private connections
In case of private connections, the device has already read the
certificates and keys content from disk, validating that the owner of
the connection has access to them. Pass those files as blobs to the
supplicant so that it doesn't have to read them again from the
filesystem, creating the opportunity for TOCTOU bugs.
2025-12-12 12:38:50 +01:00
Beniamino Galvani
a1928b4459 device: read private files in stage2
During stage2 (prepare) of an activation, check if the connection is
private and if it contains any certificate/key path. If so, start
reading the files and delay stage2. Once done, store the files'
content into priv->private_files.table and continue the activation.
2025-12-12 12:38:49 +01:00
Beniamino Galvani
9703305122 core: add functions to read private files of connections
Add function nm_utils_read_private_files(). It can be used to read a
list of paths as the given user. It spawns the daemon-helper to read
each path and returns asynchronously a hash table containing the files
content.

Also add nm_utils_get_connection_private_files_paths() to return a
list of file paths referenced in a connection. The function currently
returns only 802.1x file paths for certificates and keys.
2025-12-12 12:38:49 +01:00
Beniamino Galvani
932b85f7e7 supplicant: rename variables
Rename uid to to blob_id, and con_uid to con_uuid.
2025-12-12 12:38:49 +01:00
Beniamino Galvani
4e26403c4a core: support returning binary output from the daemon helper
The full output of the daemon helper is added to a NMStrBuf, without
interpreting it as a string (that is, without stopping at the first
NUL character).

However, when we retrieve the content from the NMStrBuf we assume it's
a string. This is fine for certain commands that expect a string
output, but it's not for other commands as the read-file-as-user one.

Add a new argument to nm_utils_spawn_helper() to specify whether the
output is binary or not. Also have different finish functions
depending on the return type.
2025-12-12 12:38:49 +01:00
Beniamino Galvani
bd2484d1a9 supplicant: remove blobs before adding new ones
When connecting, we add the blobs to the Interface object of the
supplicant. Those blobs are not removed on disconnect and so when we
try to add blobs with the same id, the supplicant returns an error.

Make sure we start from a clean slate on each connection attempt, by
deleting all existing blobs. Probably we should also delete the added
blobs on disconnect, but that's left for a future improvement.
2025-12-12 12:38:48 +01:00
Beniamino Galvani
41e28b900f daemon-helper: add read-file-as-user
Add a new command to read the content of a file after switching to the
given user. This command can be used to enforce Unix filesystem
permissions when accessing a file on behalf of a user.
2025-12-12 12:38:48 +01:00
Beniamino Galvani
6c1e04fc61 helpers: move helper programs to the same directory
Create a new 'nm-helpers' directory for all the helper programs, to
avoid having too many subdirs in the src directory.
2025-12-12 12:38:48 +01:00
Beniamino Galvani
2739850b78 libnm-core, core: add permission helpers
Add utility functions to get the number of users and the first user
from the connection.permissions property of a connection.
2025-12-12 12:38:48 +01:00
Íñigo Huguet
d8f143f601 spec: enable polkit_noauth_group for Fedora <= 43 and RHEL <= 10
In Fedora 44 and RHEL 11, admin users will need to type their password
even on local consoles.
2025-12-12 12:38:48 +01:00
Íñigo Huguet
39143f8bdd polkit: add build option to allow admin users not to type their password
Add a build option to allow installing a Polkit rule that will grant
permissions for admin users without asking for their password if they're
in a local console.

This shouldn't be encouraged, though. It's common practice that admin
users has to introduce their password to make system-wide changes. The
standard polkit policy, without this rule, is auth_admin_keep. This
policy will ask for the password once and won't ask for it again for
~5 minutes, so it is not too unconvenient.

Different distros use different group names for users with admin rights,
typically 'sudo' or 'wheel'. The build option allows to define the
desired group, or to leave it empty to not install the rule.

However, until the previous commit it was allowed that local users (even
non-admin) could do system-wide changes without introducing a password.
This option allows to maintain the same behavior for admin users,
keeping backwards compatibility so we avoid breaking existing scripts,
for example. We cannot achieve the same for non-admin users because
allowing them to create system-wide connection causes security
vulnerabilities that cannot be fixed in any other way.
2025-12-12 12:38:48 +01:00
Íñigo Huguet
0b75d905e5 polkit: remove the modify_system build option
This build option allowed non-admin users to create system-wide
connections. Generally, this is not a good idea as system-wide changes
should be done by administrators.

However, the main reason for the change is that this can be used to
bypass filesystem permissions, among possibly other attacks. As the
daemon runs as root, a user can create a system-wide connection that
uses a certificate from a different user to authenticate in a WiFi
network protected with 802.1X or a VPN, because as root user the daemon
can access to the file.

This patch does not completely fix the issue, as users can still create
private connections specifying a path to another user's connection. This
will be addressed in other patch. However, this patch is needed too,
because in system-wide connections we don't store which user created the
connection, so there woudn't be any way to check his/her permissions.

This is part of the fix for CVE-2025-9615

See: https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/1809
2025-12-12 12:38:48 +01:00
Íñigo Huguet
13bfa44ceb nm-version: set API_VERSION with MICRO+1 (temporary)
In the past, stable branches used odd micro numbers as development micro
version. Because of that, NM_API_VERSION was defined with MICRO+1 so we
don't get warnings during development.

As we stopped using odd micro=devel it is wrong to set MICRO+1 on odd
releases. Final users of 1.52.3 has NM_API_VERSION 1.52.4.

However, during development we need to have MICRO+1. For example, if we
are working on top of 1.52.3 towards the next 1.52.4, we define new
symbols with NM_AVAILABLE_IN_1_52_4. Because of that, we get compilation
failures until we finally bump to 1.52.4, just before the release. The
CI remains red until then, potentially missing many bugs.

For now, just set MICRO+1 all the time. It is wrong, but it was wrong
half of the time anyway, and at least we'll have a green CI until we
implement a definitive solution.
2025-12-12 12:17:58 +01:00
Beniamino Galvani
dad4da06b1 libnm-core: fix the documentation of the gateway IP property
The D-Bus API documentation of the IPv4 and IPv6 settings say:

* addresses
 	Deprecated in favor of the 'address-data' and 'gateway'
 	properties, but this can be used for backward-compatibility
 	with older daemons. Note that if you send this property the
 	daemon will ignore 'address-data' and 'gateway'.

* gateway
       The gateway associated with this configuration. This is only
       meaningful if "addresses" is also set.

This documentation wrongly suggests that at D-Bus level "gateway"
requires "addresses", while it actually requires "address-data". The
reason for the inconsistency is that the gateway documentation is
common between nmcli and D-Bus and it refers to the "address" GObject
property, not to the D-Bus property.

Fix this inconsistency by not explicitly mentioning the property name.

Fixes: 36156b70dc ('libnm: Override parts of nm-setting-docs.xml')

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2319
2025-12-04 16:40:07 +01:00
Jan Vaclav
0b61924048 merge: branch 'jv/fix-rawhide-build'
all: fix NM compilation on rawhide

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2321
2025-12-04 12:01:18 +00:00
Jan Vaclav
d40e88fd02 test-link: test bond with use_carrier=1
`use_carrier` is removed from kernel since 6.18 [1], and returns
the following error if set to 0:
> option obsolete, use_carrier cannot be disabled

This causes a failure of test-link-linux, so let's set it to 1.

[1] https://lore.kernel.org/all/2029487.1756512517@famine/
2025-12-04 11:51:28 +00:00
Jan Vaclav
8e72e6b4fb aux-intern: add explicit cast for strchr()
`addr` is always reallocated in this branch, so it
is safe to cast the result of strchr to char* here
to silence the const-qualifier warning.
2025-12-04 11:51:28 +00:00
Jan Vaclav
9e70f31c8c initrd: remove const qualifier from temporary variable
`argument` is not const, but `tmp` is. We use `tmp`
for reading arguments one by one, but we cannot add
a null byte to separate the key and value if it is const.

Make it non-const, so that `val[0] = '\0';` does not fail.
2025-12-04 11:51:28 +00:00
Jan Vaclav
ac427b25fb core, impl: drop const qualifier from split outputs
We write into the buffer returned by nm_strsplit_set_full(), even
though it is returned as `const char**`. The function description
claims this is fine:

> *   It is however safe and allowed to modify the individual strings in-place,
> *   like "g_strstrip((char *) iter[0])".

Remove the const qualifier via cast so that it does not raise errors.
2025-12-04 11:51:28 +00:00
Jan Vaclav
754b87e1c4 supplicant: separate input and local value
We reallocate this value in the function, which is necessary
because we write into it, and the input is const.

Move the allocation into a local variable instead of overwriting
the input pointer, because we are also pointing to it via
`char* s`, which is not const.
2025-12-04 11:51:28 +00:00
Jan Vaclav
5f6beb0e57 nm-udev-utils: constify strstr-output variable
`subsystem_full` is const, so `s` needs to be const too.
Reorder the NULL-byte write so that we are not writing
into a const char* (the underlying memory is the same).
2025-12-04 11:51:28 +00:00
Jan Vaclav
487ca30256 all: const-ify str(r)chr output variables where possible 2025-12-04 11:51:28 +00:00
Jan Vaclav
a07961cfbe systemd: selectively backport "Fix constness issues with newer glibc"
NetworkManager is failing to build on Rawhide with the following errors:
../src/libnm-systemd-shared/src/basic/string-util.h:33:16: error: return discards ‘const’ qualifier from pointer target type [-Werror=discarded-qualifiers]
   33 |         return strstr(haystack, needle);
      |                ^~~~~~
In file included from ../src/libnm-systemd-shared/src/basic/fd-util.c:30:
../src/libnm-systemd-shared/src/basic/sort-util.h: In function ‘bsearch_safe’:
../src/libnm-systemd-shared/src/basic/sort-util.h:34:16: error: return discards ‘const’ qualifier from pointer target type [-Werror=discarded-qualifiers]
   34 |         return bsearch(key, base, nmemb, size, compar);
      |                ^~~~~~~

This is fixed in systemd by commit 0bac1ed2422f15308414dd1e9d09812a966b0348:
> Latest glibc uses _Generic to have strstr() and other functions return
> const char* or char* based on whether the input is a const char* or a
> char*. This causes build failures as we previously always expected a char*.
>
> Let's fix the compilation failures and add our own macros similar to glibc's
> to have string functions that return a mutable or const pointer depending on
> the input.

Selectively backport the changes we need to fix building.
2025-12-04 11:51:28 +00:00
Jan Vaclav
4e7e159224 merge: branch 'jv/unifcfg-scripts'
build/configure_for_system: stop building with ifcfg_rh support

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2320
2025-12-04 11:50:02 +00:00
Jan Vaclav
ae134ca9f4 build/configure_for_system: stop building with ifcfg_rh support
It has been deprecated for a long time, so it would be probably
fine to stop building with it enabled. RHEL 9 is excluded since
it still supports the ifcfg-rh format.
2025-12-04 11:33:13 +00:00
Jan Vaclav
55f96057c6 build/configure_for_system: disable building with team on rhel10+ 2025-12-04 11:33:13 +00:00
Jan Vaclav
de0a37b248 build: fix rhel version detection in configure_for_system 2025-12-04 11:33:13 +00:00
Beniamino Galvani
7315e7e0ee merge: branch 'saemismatch-signal-handlers'
core: add handlers for SaePasswordMismatch signal

Closes #904

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2293
2025-12-03 16:08:41 +00:00
Mitchell Augustin
bcb96a1b19 core: add handlers for SaePasswordMismatch signal
Trigger a new auth request to the user when the SaePasswordMismatch
signal is received from wpa_supplicant.

Closes #904
2025-12-02 14:25:12 +00:00
Beniamino Galvani
561fff3c8d merge: branch 'main'
connectivity: add per-device check-connectivity setting

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2316
2025-12-02 09:55:34 +00:00
Popax21
a9f2c15663 connectivity: add per-device check-connectivity setting
Adds a new `check-connectivity` setting to the `device` section which can be
used to disable the connectivity check for a particular device.
2025-12-02 10:04:20 +01:00
Beniamino Galvani
8a9b17071b version: add 1.58 macros 2025-11-28 19:05:59 +01:00
Till Maas
c1519bd514 merge: branch 'update_pt_BR'
Update Brazilian translation

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2307
2025-11-26 22:16:53 +01:00
Rafael Fontenelle
8b5a61458b Update Brazilian Portuguese translation
Co-authored-by: Matheus Barbosa <mdpb.matheus@gmail.com>
Co-authored-by: Samuel Schlemper <samuelschlemper2006@gmail.com>
Co-authored-by: Juliano de Souza Camargo <julianosc@pm.me>
2025-11-26 22:16:25 +01:00
Beniamino Galvani
9e01443b14 man: describe the allowed boolean values in NetworkManager.conf
The NetworkManager.conf man page is describing some options as
"whether X is enabled", without explicitly saying that it's a
boolean. Also, the allowed values are not mentioned. Clarify those
aspects.
2025-11-26 09:03:11 +01:00
Beniamino Galvani
78519589b9 NEWS: update 2025-11-26 09:03:08 +01:00
Till Maas
771f86105e merge: branch 'patch-2'
Updated Slovenian translation

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2317
2025-11-24 21:31:56 +01:00
filmsi
b3f9f52505 Updated Slovenian translation 2025-11-24 21:31:55 +01:00
Beniamino Galvani
b41a5ec2d4 merge: branch 'initrd-services-dbus-fix'
systemd: install initrd services using a generator

Closes #1814

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2312
2025-11-20 17:41:45 +00:00
Antonio Alvarez Feijoo
636fb5ef24 systemd: install initrd services using a generator
Since both `NetworkManager.service` and `NetworkManager-initrd.service` are
allocated for the same bus name (`org.freedesktop.NetworkManager`) and this is
not allowed, the best option is to use a systemd generator to install them only
in the initrd, instead of setting fixed Install sections.

Fixes #1814
2025-11-20 13:26:15 +00:00
Beniamino Galvani
d006d61aa1 merge: branch 'main'
core: restrict connectivity check lookups to per-link DNS if available

Closes #1836

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2313
2025-11-20 08:24:08 +00:00
Popax21
6e2de1d2b3 core: restrict connectivity check lookups to per-link DNS if available
Restrict connectivity check DNS lookups to just the relevant link if the link
has a per-link DNS resolver configured. This change was previously discussed as
part of issue
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/1836, and
brings NM's behavior back in line with the behavior documented in the man page.

The connectivity check checks for a per-link DNS resolver by querying
systemd-resolved's `ScopeMask` for the link; this involves a small D-Bus
roundtrip, but is ultimately the more flexible solution since it is also capable
of dealing with per-link DNS configuration stemming from other sources.

Fixes: e6dac4f0b6 ('core: don't restrict DNS interface when performing connectivity check')
2025-11-19 14:54:40 +00:00
Beniamino Galvani
4afa00874f merge: branch 'mptcp-laminar'
mptcp: add `laminar` endpoint support and set it by default

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2314
2025-11-19 14:01:05 +00:00
Matthieu Baerts (NGI0)
3ce1da1fd2 NEWS: new MPTCP 'laminar' endpoint & default
A summary linked to the last two commits.

Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
2025-11-19 12:54:09 +00:00
Matthieu Baerts (NGI0)
8caa781270 mptcp: set the laminar flag by default
By default, the MPTCP limits have 'add_addr_accepted' set to 0. It means
that when the other peer announces an additional address it can be
reached from, the receiver will not try to establish any new subflows to
this address. If this limit is increased, and without the new 'laminar'
flag, the MPTCP in-kernel path-manager will select the source address by
looking at the routing tables to establish this new subflow.

This is not ideal: very likely, the source address will be the one
linked to the default route and a new subflow from the same interface as
the initial one will be created instead of using another path.

This is especially problematic when the other peer has set the 'C-flag'
in the MPTCP connection request (MP_CAPABLE). This flag can be set to
tell the other side that the peer will not accept extra subflows
requests sent to its initial IP address and port: typically set by a
server using an anycast address, behind a legacy Layer 4 load balancer.

It sounds better to add the 'laminar' flag by default to pick the source
address from well-defined MPTCP endpoints, rather than relying on
routing rules which will likely not pick the most interesting solution.

Note that older kernels will accept unsupported flags, and ignore them.
So it is fine to have the new flag added by default even if it is not
supported.

Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
2025-11-19 12:54:09 +00:00
Matthieu Baerts (NGI0)
2b03057de0 mptcp: add 'laminar' endpoint support
This new endpoint type has been recently added to the kernel in v6.18
[1]. It will be used to create new subflows from the associated address
to additional addresses announced by the other peer. This will be done
if allowed by the MPTCP limits, and if the associated address is not
already being used by another subflow from the same MPTCP connection.

Note that the fullmesh flag takes precedence over the laminar one.
Without any of these two flags, the path-manager will create new
subflows to additional addresses announced by the other peer by
selecting the source address from the routing tables, which is harder to
configure if the announced address is not known in advance.

The support of the new flag is easy: simply by declaring a new flag for
NM, and adding it in the related helpers and existing checks looking at
the different MPTCP endpoint. The documentation now references the new
endpoint type.

Note that only the new 'define' has been added in the Linux header file:
this file has changed a bit since the last sync, now split in two files.
Only this new line is needed, so the minimum has been modified here.

Link: https://git.kernel.org/torvalds/c/539f6b9de39e [1]
Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
2025-11-19 12:54:09 +00:00
Beniamino Galvani
3b10b88290 core: fix rate-limit test failures
It's possible that the first timeout gets delayed; therefore the
interval between the first and the second callback can be less than
one second, and the budget doesn't refill completely.

Schedule the second timeout from the first callback to guarantee that
at least one second passes between the callbacks.

Fixes: ff0c4346fc ('core: add rate-limiting helper')
2025-11-18 15:02:05 +01:00
Íñigo Huguet
d687768c61 libnm: move hsr symbols to the right version
These symbols has been added to the 1.54.2 stable branch, so they are
actually available since then.
2025-11-18 10:39:49 +01:00
Íñigo Huguet
239b0fbbc9 release: bump version to 1.57.0 (development) 2025-11-17 16:42:05 +01:00
Íñigo Huguet
29d523391a release: bump version to 1.55.90 (1.56-rc1) 2025-11-17 16:35:34 +01:00
Beniamino Galvani
f4bf54ca93 merge: branch 'bg/ndisc-ratelimit-warns'
ndisc: rate limit messages about invalid RAs

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2294
2025-11-12 13:12:25 +00:00
Beniamino Galvani
22631d557a ndisc: rate limit messages about invalid RAs
Sending and receiving RA is repeated periodically. Don't spam logs
with the same message again and again. Rate limit the message to 6
every 12 hours per type and per ndisc instance.
2025-11-12 14:05:30 +01:00
Beniamino Galvani
ff0c4346fc core: add rate-limiting helper
It can be used to perform an action like logging a message with
simple rate limiting.
2025-11-12 11:48:59 +01:00
Jan Vaclav
5f85b55f7f NEWS: update
Fixes: 04ddd72ce9 ('merge: branch 'jv/import-nacd'')
2025-10-30 12:34:16 +01:00
Beniamino Galvani
461c9edfb4 merge: branch 'main'
Correctly apply some connection properties to vpn connections

Closes #1109

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2279
2025-10-27 09:46:41 +00:00
Robin Ebert
306f9c490b vpn: Use nm_device_create_l3_config_data_from_connection if possible
Using nm_device_create_l3_config_data_from_connection in favor of
nm_l3_config_data_new_from_connection allows the connection
properties: connection.mdns, connection.llmnr,
connection.dns-over-tls, connection.dnssec, connection.mptcp-flags,
and ipv6.ip6-privacy to be read from the vpn's connection settings
allowing them to be applied to vpn connections.
2025-10-27 10:31:16 +01:00
Robin Ebert
441e77a44c core: Make nm_device_create_l3_config_data_from_connection behave as expected
Currently nm_device_create_l3_config_data_from_connection uses the
connection applied to the given device for some properties.  Altough
this currently works since all users of
nm_device_create_l3_config_data_from_connection provide the applied
connection as parameter, it behaves unexpectedly when another
connection is given.
2025-10-27 09:58:07 +01:00
Íñigo Huguet
caf156b2ac merge: branch 'ih/fix-ci-pages'
ci: fix pages job

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2303
2025-10-24 11:58:18 +00:00
Íñigo Huguet
ed43e4b602 ci: fix pages job
Fix the rule that triggers this job so it is run each time that a commit
is pushed/merged to main. The incorrect rule was doing that it only ran
when the *source* branch (or a MR) was called "main". Therefore, it was
(almost) never running.

Fixes: 69efb4660c ('CI: periodically clean image's registry')
2025-10-24 12:48:20 +02:00
Íñigo Huguet
384dd7d5f2 merge: branch 'ih/forwarding'
core: ip forwarding: improve performance setting IPv4 forwarding for method=shared and forwarding=auto

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2201
2025-10-24 05:27:36 +00:00
Íñigo Huguet
e06aaba1ca core: mark as managed-type=removed when unrealize
This is needed to ensure that the right CleanupType is chosen when
calling to nm_device_state_changed() a bit later. With this change
CLEANUP_TYPE_REMOVED will be used instead of CLEANUP_TYPE_DECONFIGURE,
which is wrong because the device has already disappeared.
2025-10-24 05:27:18 +00:00
Íñigo Huguet
32cbf4c629 ip: shared: stop using the global forwarding
As we introduced the ipv4.forwarding property in a8a2e6d727 ('ip-config:
Support configuring per-device IPv4 sysctl forwarding option'), we must
not enable or disable the global forwarding setting in the kernel, as it
affects to all the devices, maybe forcing them to behave in a way
different to what the user requested in ipv4.forwarding.

Instead, we need to selectively enable or disable the per-device forwarding
settings. Specifically, only devices activated with ipv4.forwarding=auto
must have their forwarding enabled or disabled depending on shared
connections. Devices with yes/no must not be affected by shared connections.

Also, devices with ipv4.forwarding=auto must get the proper forwarding value
on activation, but also change it when shared connections appear or
disappear dynamically. Use the new sharing-ipv4-change signal from
nm_manager to achieve it.

Fixes: a8a2e6d727 ('ip-config: Support configuring per-device IPv4 sysctl forwarding option')
2025-10-24 05:27:18 +00:00
Íñigo Huguet
8faa33b9d4 manager: add sharing-ipv4-changed signal
This signal notifies about the "sharing state", that's it, when there
is at least one shared connection active or not. Each device informs
to nm_manager when a shared connection is activated or deactivated
and nm_manager emits this signal when the first shared connection is
activated or the last one is deactivated.

For now we're only interested in IPv4 forwarding as it's the only one
that we need to track from nm_device (in following commits).

Fixes: a8a2e6d727 ('ip-config: Support configuring per-device IPv4 sysctl forwarding option')
2025-10-24 05:27:18 +00:00
Íñigo Huguet
d58d0a793e ip: restore IP forwarding on device deconfiguration
With the ipv4.forwarding property we may modify the forwarding sysctl of
the device on activation. In next commits, we will also modify it if the
connection is shared, instead of modifying the global forwarding.

Restore the forwarding value to the default one when the device is
deconfigured for any reason.

Fixes: a8a2e6d727 ('ip-config: Support configuring per-device IPv4 sysctl forwarding option')
2025-10-24 05:27:18 +00:00
Íñigo Huguet
f2a2e49d07 Revert "policy: refresh IPv4 forwarding after connection activation and disconnection"
This reverts commit 2ad5fbf025.

It is actually a partial revert. The changes to documentation don't need
to be reverted.

Fixes: 2ad5fbf025 ('policy: refresh IPv4 forwarding after connection activation and disconnection')
2025-10-24 05:27:18 +00:00
Beniamino Galvani
b4e8edbc8a merge: branch 'pskmismatch-signal-handlers'
core: add handlers for PskMismatch signal

Closes #904

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2287
2025-10-23 14:38:43 +00:00
Mitchell Augustin
6dd07a80e5 core: add handlers for PskMismatch signal
Trigger a new PSK request to the user when the PskMismatch
signal is received from wpa_supplicant.

Closes #904
2025-10-23 14:36:54 +00:00
Jan Vaclav
04ddd72ce9 merge: branch 'jv/import-nacd'
n-acd: detect eBPF capability at runtime

Closes #1049

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2300
2025-10-23 13:33:30 +00:00
Íñigo Huguet
58f46a6d11 merge: branch 'localhost'
core: nm-dns-dnsmasq: listen on ipv6 localhost too

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1504
2025-10-23 05:42:34 +00:00
Jan Vaclav
427137d6da service: add CAP_BPF capability to NetworkManager
Since we are now always building n-acd with eBPF, and
are able to detect eBPF support at runtime, we can
reflect this in the unit as well.

Add CAP_BPF to CapabilityBoundingSet, so that NM can
request to create a BPF map when setting up n-acd.
2025-10-22 21:49:56 +02:00
Jan Vaclav
b1614ffb90 l3cfg: add info about n-acd eBPF state to log messages 2025-10-22 21:49:56 +02:00
Jan Vaclav
8d33aaa5b6 build: drop "ebpf" configuration for n-acd compilation
Since we now check whether the user's machine supports
eBPF at runtime, we can drop all of this build machinery.
2025-10-22 21:48:39 +02:00
Jan Vaclav
191ebb439a n-dhcp4: re-import git-subtree for 'src/n-dhcp4'
git subtree pull --prefix src/n-dhcp4 git@github.com:nettools/n-dhcp4.git master --squash
2025-10-22 20:09:41 +02:00
Jan Vaclav
2f35c94628 Squashed 'src/n-dhcp4/' changes from 2707213e3e..0d4dcc9bb4
0d4dcc9bb4 n-dhcp4: introduce n_dhcp4_c_connection_clear_client_ip() helper
433c57ab2e n-dhcp4: Do not set ciaddr in DISCOVER state.
feacc2cccd n-dhcp4: change the default DSCP value to 0
b64e2c62e8 n-dhcp4: support setting the DSCP value
6cfa9d84d0 n-dhcp4: set xid of the DHCP header for RELEASE and DECLINE message

git-subtree-dir: src/n-dhcp4
git-subtree-split: 0d4dcc9bb45d5a63d53a787289ad79823343e624
2025-10-22 20:09:23 +02:00
Jan Vaclav
3a769bca67 n-acd: re-import git-subtree for 'src/n-acd'
git subtree pull --prefix src/n-acd git@github.com:nettools/n-acd.git master --squash
2025-10-22 20:09:16 +02:00
Jan Vaclav
0530af60b3 Squashed 'src/n-acd/' changes from a600afc870..6ac6f7e105
6ac6f7e105 n-acd: runtime eBPF support detection

git-subtree-dir: src/n-acd
git-subtree-split: 6ac6f7e105c06e0c352b78b5a136f87fcb5c7432
2025-10-22 20:09:16 +02:00
Jiri Slaby (SUSE)
a0482a4e35 core: nm-dns-dnsmasq: listen on ipv6 localhost too
Trying to resolve hosts using localhost errors out for ipv6 attempts:
  $ host www.seznam.cz localhost
  ;; communications error to ::1#53: connection refused
  ;; communications error to ::1#53: connection refused
  Using domain server:
  Name: localhost
  Address: 127.0.0.1#53
  Aliases:

  www.seznam.cz has address 77.75.77.222
  www.seznam.cz has address 77.75.79.222
  ;; communications error to ::1#53: connection refused
  ;; communications error to ::1#53: connection refused
  www.seznam.cz has IPv6 address 2a02:598:a::79:222
  www.seznam.cz has IPv6 address 2a02:598:2::1222
  ;; communications error to ::1#53: connection refused
  ;; communications error to ::1#53: connection refused

It's because on some distros (like openSUSE), localhost is defined both
as 127.0.0.1 and ::1.

So listen on ::1 too. This makes ipv4-switchoff easier.
/etc/resolv.conf should likely be updated to contain ::1 eventually too
(see update_dns()).

Fixes https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/1188
2025-10-22 15:42:57 +02:00
Beniamino Galvani
0e121f5658 merge: branch 'bg/dns-no-stub'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2298
2025-10-22 10:01:46 +02:00
Beniamino Galvani
2d438ebef8 dns: specify a temporary file name when writing no-stub-resolv.conf
Using g_file_set_contents() makes it impossible to write a proper
SELinux policy because the function creates a file with a random
suffix, and SELinux file transitions can't match on wildcards.

Use a fixed temporary file name. In this case it's fine because
/run/NetworkManager is only writable by root and NetworkManager is the
only process writing into it.
2025-10-22 09:56:39 +02:00
Beniamino Galvani
c312390932 libnm-glib-aux: add temp name argument to nm_utils_file_set_contents()
In some cases it's useful to specify the name of the temporary file to
be used.
2025-10-22 09:56:39 +02:00
Íñigo Huguet
d06fd85e57 merge: branch 'ih/ovsdb-update-log'
ovs: print clearer logs of the ovsdb "update" event

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2297
2025-10-22 06:07:32 +00:00
Íñigo Huguet
2a63c33712 ovs: print clearer logs of the ovsdb "update" event
These lines says things like "changed a bridge", what seems to mean that
NM is doing the change. Actually, these logs indicate changes that NM is
being notified of, and they may even be external changes.

- Add the "monitor:" prefix to show that it's something that NM is
  monitoring, not doing.
- Say "bridge changed" instead of "changed a bridge", which sounds an
  action that we're doing.
- Print the bridge/port/iface name first, instead of the uuid-like key which
  is not useful for a quick look by a human.
- Print `connection=conn-uuid` instead of just `conn-uuid`, as it's not
  obvious that the uuid refers to the connection.

Before:
  ovsdb: obj[bridge:8c975244-cb0a-4add-8901-c398dcbc27d6]: changed a bridge: br-int, b1ef934d...

After:
  ovsdb: monitor: br-int: bridge changed: obj[bridge:8c975244-cb0a-4add-8901-c398dcbc27d6], connection=b1ef934d...
2025-10-22 06:07:25 +00:00
Beniamino Galvani
ce26d85ad1 merge: branch 'bg/reject-unsupported-conns'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2299
2025-10-21 15:34:19 +02:00
Beniamino Galvani
1e81aaa153 settings: document some data structures 2025-10-21 15:31:58 +02:00
Beniamino Galvani
c1baf09bf9 settings: ignore unsupported connections when they are loaded
In addition to rejecting new connections added via D-Bus when they are
unsupported, also ignore the existing on-disk ones.
2025-10-21 15:31:58 +02:00
Beniamino Galvani
247000deed core: reject new connections if the feature is disabled or removed
If a feature like Wi-Fi, OVS, team, etc. is disabled or no longer
supported, it is better to report an error when the connection is
added via nmcli than accepting the connection and complaining later
about a "missing plugin"; there is no plugin and the connection will
never be able to activate.

Example errors now:
  # nmcli connection add type team
  Error: Failed to add 'team-nm-team' connection: team support is disabled in this build

  # nmcli connection add type gsm
  Error: Failed to add 'gsm' connection: WWAN support is disabled in this build

  # nmcli connection add type wimax nsp 00:99:88:77:66:55
  Error: Failed to add 'wimax' connection: WiMAX is no longer supported

Note that we don't touch libnm-core (the part defining the settings
and properties), as that defines the API of NetworkManager. The API
should not change according to compile flags.
2025-10-21 15:31:58 +02:00
Íñigo Huguet
e5ae988603 merge: branch 'fix-autoreconnection'
Fix: unblock autoreconnect when a previously failed connection is now successful

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2295
2025-10-21 09:43:05 +00:00
Antoine Lassagne
03791e8b2d Fix: unblock autoreconnect when a previously failed connection is now successful 2025-10-21 09:39:52 +00:00
Beniamino Galvani
965aa81027 device: set bridge in supplicant for 802.1X ethernet and macsec
When authenticating via 802.1X, the supplicant must be made aware of
the bridge the interface is attached to. This was already done for
wifi in commit ae31b4bf4e ('wifi: set the BridgeIfname supplicant
property when needed'). When setting the BridgeIfname property, the
supplicant opens an additional socket to listen on the bridge, to
ensure that all incoming EAPOL packets are received.

Without this patch, the initial authentication usually works because
it is started during stage2 (prepare), when the device is not yet
attached to the bridge, but then the re-authentication fails.

Note: I could reproduce the problem only when the bridge is configured
with bridge.group-forward-mask 8.

Resolves: https://issues.redhat.com/browse/RHEL-121153
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2301
2025-10-21 11:26:08 +02:00
Jan Vaclav
86b67233bf merge: branch 'jv/hsr-interlink'
libnm: introduce `hsr.interlink` property

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2285
2025-10-13 10:42:51 +00:00
Beniamino Galvani
a148232789 merge: branch 'dnssec'
Add support for systemd-resolved's DNSSEC option

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2278
2025-10-13 10:10:34 +00:00
Robin Ebert
2bc895c0e9
NEWS: add new connection.dnssec feature to NEWS 2025-10-13 11:58:11 +02:00
Robin Ebert
c6a6801b1e
ifcfg-rh: throw error if connection.dnssec is used 2025-10-13 11:57:54 +02:00
Robin Ebert
46306c1be0
cli: add support for connection.dnssec 2025-10-13 11:57:53 +02:00
Robin Ebert
1dcd63ab5d
core: add support for connection.dnssec 2025-10-13 11:57:53 +02:00
Robin Ebert
029f8be4c1
libnm-core: Add connection.dnssec property 2025-10-13 11:57:34 +02:00
Íñigo Huguet
e6a31264c1 merge: branch 'ih/ovs-external-ports'
ovs: don't remove unrelated external ports

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2296
2025-10-13 06:58:30 +00:00
Íñigo Huguet
86ea2c5963 man: ovs: document known limitation when removing ifaces and ports
Document a known limitation that we delete bridges and ports from ovsdb
when we remove their last NM-owned attached port or interface, even if
other externally added ports or interfaces exist.
2025-10-13 06:58:23 +00:00
Íñigo Huguet
93491d76ec ovs: don't remove unrelated external ports
The commit linked below introduced a bug that caused that OVS ports
added externally to NM are always deleted when we delete any OVS
interface. It affects to all externally added ports, including those
that are not related to the deleted interface and even those in
different OVS bridges.

Fix it by only modifying ports and bridges that are ascendants of the
deleted interface, leaving everything else untouched.

Note that bridges and ports still need to have at least one NM-managed
interface, otherwise they will also be purged. For example, an NM-owned
OVS bridge with 2 ports+iface, one NM-owned and one external: if we
delete the NM-owned iface, both ports and the bridge will be deleted.
For now, this is a known limitation that is not being fixed here.

Fixes: 476c89b6f2 ('ovs: only keep bridges and ports with NM interfaces attached')
2025-10-13 06:58:23 +00:00
Íñigo Huguet
b271e0a051 merge: branch 'filmsi/update-po'
Update Slovenian translation

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2292
2025-10-10 14:51:37 +00:00
filmsi
f0f4d0dba0 Update Slovenian translation 2025-10-10 14:51:16 +00:00
Íñigo Huguet
4e10b1e6ab merge: branch 'hotfix/mstrodl/no-operator-code-retry'
wwan: retry after no operator code

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2270
2025-10-10 12:21:23 +00:00
Mary Strodl
52d08008b7
wwan: retry after no operator code
We've had a few rare instances where a modem stopped retrying
to autoconnect because it briefly didn't have an operator code.

This isn't a permanent failure, so we shouldn't abort completely
for it.
2025-10-10 08:16:57 -04:00
Íñigo Huguet
92aeed1f5c merge: branch 'patch-1'
Fix the exit test condition on modem state when creating the connection properties

Closes #1741

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2247
2025-10-09 06:42:22 +00:00
Christian Müller
018c5722ee Fix the exit test condition on modem state when creating the connection properties 2025-10-09 06:42:22 +00:00
Jan Vaclav
bf8b38618a NEWS: update 2025-10-08 22:52:14 +02:00
Jan Vaclav
17efec8b06 platform: configure HSR interlink from property
Uses the `hsr.interlink` property defined in the previous
commit to configure the property in the kernel.
2025-10-08 22:52:03 +02:00
Jan Vaclav
69d0fb161e libnm: introduce hsr.interlink property
This property allows the user to optionally configure
an interlink name on a HSR interface, so that it could
serve as RedBox (Redundant Box) by connecting DAN (dual
attachment node) to SAN (single attachment node).
2025-10-08 22:52:03 +02:00
Jan Vaclav
59c65bc859 merge: branch 'sktranslation_update'
Update Slovak translation

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2286
2025-10-07 10:31:27 +02:00
Jan Vaclav
a46827f899 merge: branch 'jv/hsr-version'
libnm: introduce `hsr.protocol-version` property

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2283
2025-10-06 09:02:04 +00:00
Íñigo Huguet
6801ce4927 merge: branch 'catalan_fixes'
Fixes to Catalan translation

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2289
2025-10-03 11:21:26 +00:00
Jordi Mas
6e32a8e821 Fixes to Catalan translation 2025-10-03 11:21:15 +00:00
Íñigo Huguet
13d7469ba0 merge: branch 'wwan-device-name-restriction'
add gsm device-uid setting to restrict the devices the connection applies to

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2176
2025-10-03 11:03:13 +00:00
Michael Mokricky
820e56c5df add gsm device-uid setting to restrict the devices the connection applies to 2025-10-03 11:02:21 +00:00
Jan Vaclav
c27caec33d NEWS: update 2025-09-30 14:29:00 +02:00
Jan Vaclav
0b99629278 platform: configure HSR protocol version from property
Uses the `hsr.protocol-version` property defined in the previous
commit to configure the property in the kernel.
2025-09-30 14:28:49 +02:00
Jan Vaclav
9a2395c779 libnm: introduce hsr.protocol-version property
This property allows the user to set the protocol
version when using HSR. Currently, the property
supports two values - `2010` (referred to as HSRv0
in the kernel), and `2012` (HSRv1).
2025-09-30 14:28:48 +02:00
Jose Riha
ddb31034f9 Update Slovak translation 2025-09-26 17:34:34 +02:00
Íñigo Huguet
9e0551aefd core: document CleanupType
We must do different cleanups depending on the CleanupType. Document the
meaning of the different types as it was very confusing to work on new
code without having very clear what do they mean.
2025-09-24 11:30:59 +02:00
Íñigo Huguet
dbec15eb8d merge: branch 'ih/net-off-logging'
Improve logging of `networking off`

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2284
2025-09-24 05:21:21 +00:00
Íñigo Huguet
48fc40e1ca core: rename unmanaged flag SLEEPING->MANAGER_DISABLED
The flag is used for both sleeping and networking disabled conditions.
This is because internally they share logic, but it's not obvious for
users and it has caused confusion in the past when investigating why
devices didn't become managed. Make it explicit that it can be because
of either reason.

It would be better to create two separate flags, actually, and it
doesn't seem complex, but better not to risk introducing bugs for that
little benefit.

Logs before:
  device (enp4s0): state change: disconnected -> unmanaged (reason 'unmanaged-sleeping' ...

Logs before:
  device (enp4s0): state change: disconnected -> unmanaged (reason 'unmanaged-nm-disabled' ...
2025-09-23 09:17:07 +02:00
Íñigo Huguet
f6d6a7e2eb core, libnm: add the "networking off" reason
When we disable networking with `nmcli networking off` the reason that
is logged is "sleeping". Explain instead that networking is disabled.

Before:
  device (lo): state change: activated -> deactivating (reason 'sleeping' ...

After:
  device (lo): state change: activated -> deactivating (reason 'networking-off' ...
2025-09-23 09:17:07 +02:00
Íñigo Huguet
3355ba9380 core: rename NM_STATE_ASLEEP to NM_STATE_DISABLED
When we do `nmcli networking off` it's shown as state "sleeping". This
is confusing, and the only reason is that we share internally code to
handle both situations in a similar way.

Rename the state to the more generic name "disabled", situation that can
happen either because of sleeping or networking off.

Clients cannot differentiate the exact reason only with the NMState value,
but better that they show "network off" as this is the most common reason
that they will be able to display. If the system is suspending, there will
be only a short period of time that they can show the state, and showing
"network off" is not wrong because that's what NM has done as a response
to suspend.

In the logs, let's make explicit the exact reason why state is changing
to DISABLED: sleeping or networking off.

Logs before:
  manager: disable requested (sleeping: no  enabled: yes)
  manager: NetworkManager state is now ASLEEP

Logs after:
  manager: disable requested (sleeping: no  enabled: yes)
  manager: NetworkManager state is now DISABLED (NEWORKING OFF)

State before:
  $ nmcli general
  STATE  ...
  asleep ...

State after:
  $ nmcli general
  STATE       ...
  network off ...
2025-09-23 09:17:03 +02:00
Íñigo Huguet
c36e0bedeb NEWS: update 2025-09-12 15:11:56 +02:00
157 changed files with 13260 additions and 9142 deletions

1
.gitignore vendored
View file

@ -81,7 +81,6 @@ test-*.trs
/data/org.freedesktop.NetworkManager.service
/data/server.conf
/data/org.freedesktop.NetworkManager.policy
/data/org.freedesktop.NetworkManager.policy.in
/data/nm-sudo.service
/data/nm-priv-helper.service
/data/NetworkManager-config-initrd.service

View file

@ -60,11 +60,11 @@ variables:
#
# This is done by running `ci-fairy generate-template` and possibly bumping
# ".default_tag".
ALPINE_TAG: 'tag-722dacf5c4be'
CENTOS_TAG: 'tag-1387a813d200'
DEBIAN_TAG: 'tag-447ddf898453'
FEDORA_TAG: 'tag-1387a813d200'
UBUNTU_TAG: 'tag-447ddf898453'
ALPINE_TAG: 'tag-0c3a6f855fb8'
CENTOS_TAG: 'tag-c1c23df75dda'
DEBIAN_TAG: 'tag-d4bf5db9e214'
FEDORA_TAG: 'tag-c1c23df75dda'
UBUNTU_TAG: 'tag-d4bf5db9e214'
ALPINE_EXEC: 'bash .gitlab-ci/alpine-install.sh'
CENTOS_EXEC: 'bash .gitlab-ci/fedora-install.sh'
@ -713,7 +713,7 @@ pages:
rules:
- if: $CI_PIPELINE_SOURCE == 'schedule'
when: never
- if: $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME == 'main'
- if: $CI_PIPELINE_SOURCE == 'push' && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
dependencies:
- "t_fedora:42: [meson+gcc+docs+valgrind]"
needs:

View file

@ -240,7 +240,7 @@ pages:
rules:
- if: $CI_PIPELINE_SOURCE == 'schedule'
when: never
- if: $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME == 'main'
- if: $CI_PIPELINE_SOURCE == 'push' && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
dependencies:
- "t_{{default_distro.name}}:{{default_distro.versions[0]}}: [meson+gcc+docs+valgrind]"
needs:

View file

@ -155,12 +155,7 @@ test_subtree() {
do_clean
pushd ./src/$d
ARGS=()
if [ "$d" = n-acd ]; then
ARGS+=('-Debpf=false')
fi
CC="$cc" CFLAGS="-Werror -Wall" meson build "${ARGS[@]}"
CC="$cc" CFLAGS="-Werror -Wall" meson build
ninja -v -C build test
popd

53
NEWS
View file

@ -1,6 +1,6 @@
=============================================
NetworkManager-1.56
Overview of changes since NetworkManager-1.54
NetworkManager-1.58
Overview of changes since NetworkManager-1.56
=============================================
This is a snapshot of NetworkManager development. The API is
@ -8,9 +8,58 @@ subject to change and not guaranteed to be compatible with
the later release.
USE AT YOUR OWN RISK. NOT RECOMMENDED FOR PRODUCTION USE!
* Restrict the connectivity check to use the DNS servers defined on the
same link. If the link has no DNS servers, the connectivity check will
use any servers available in the system.
* Install the systemd units in the initramfs using a systemd generator.
* A new "check-connectivity" configuration option is available to disable the
connectivity check for selected interfaces.
* Remove the modify_system build option that allowed setting up the
polkit permissions to allow non-admin users to create system-wide
connection. That configuration is discouraged because it can be used
to bypass filesystem permissions.
* For private connections (the ones that specify a user in the
"connection.permissions" property), verify that the user can access
the 802.1X certificates and keys set in the connection.
* Introduce a libnm function that can be used by VPN plugins to check
user permissions on certificate and keys.
* The support for Wireless Extensions is deprecated and will be
removed in a future release. Wireless Extensions are now disabled by
default.
=============================================
NetworkManager-1.56
Overview of changes since NetworkManager-1.54
=============================================
* nmcli now supports viewing and managing WireGuard peers.
* Support reapplying the "sriov.vfs" property as long as
"sriov.total-vfs" is not changed.
* Support reapplying "bond-port.vlans".
* Accept hostnames longer than 64 characters from DNS lookup.
* Make that global-dns configuration overwrites DNS searches and
options from connections, instead of merging all together.
* Add support for a new rd.net.dhcp.client-id option in
nm-initrd-generator.
* Add gsm device-uid setting to restrict the devices the connection applies to.
* Support configuring the HSR protocol version via the
"hsr.protocol-version" property.
* Fix a bug that makes broadband connections auto-connect getting
blocked if the connection tries to reconnect when modem status is
"disconnecting" / "disconnected".
* Treat modem connection not having an operator code available
as a recoverable error.
* Add support for configuring systemd-resolved's DNSSEC option
per-connection via the "connection.dnssec" connection property.
* Support configuring the HSR interlink port via the
"hsr.interlink" property.
* Fix some connection properties not being applied to vpn connections
(connection.mdns, connection.llmnr, connection.dns-over-tls,
connection.mptcp-flags, ipv6.ip6-privacy)
* Update n-acd to always compile with eBPF enabled, as support
for eBPF is now detected at run time.
* Add new MPTCP 'laminar' endpoint type, and set it by default alongside
the 'subflow' one.
=============================================
NetworkManager-1.54

View file

@ -239,6 +239,15 @@
/* Whether we build with OVS plugin */
#mesondefine WITH_OPENVSWITCH
/* Whether we build with team support */
#mesondefine WITH_TEAMDCTL
/* Whether we build with Wi-Fi support */
#mesondefine WITH_WIFI
/* Whether we build with WWAN support */
#mesondefine WITH_WWAN
/* Define if you have PPP support */
#mesondefine WITH_PPP

View file

@ -107,6 +107,11 @@
%else
%bcond_without iwd
%endif
%if 0%{?fedora} <= 43 || 0%{?rhel} <= 10
%bcond_without polkit_noauth_group
%else
%bcond_with polkit_noauth_group
%endif
###############################################################################
@ -154,17 +159,6 @@
%bcond_with ifcfg_migrate
%endif
%if 0%{?fedora}
# Although eBPF would be available on Fedora's kernel, it seems
# we often get SELinux denials (rh#1651654). But even aside them,
# bpf(BPF_MAP_CREATE, ...) randomly fails with EPERM. That might
# be related to `ulimit -l`. Anyway, this is not usable at the
# moment.
%global ebpf_enabled "no"
%else
%global ebpf_enabled "no"
%endif
# Fedora 33 enables LTO by default by setting CFLAGS="-flto -ffat-lto-objects".
# However, we also require "-flto -flto-partition=none", so disable Fedora's
# default and use our configure option --with-lto instead.
@ -627,14 +621,10 @@ Preferably use nmcli instead.
%endif
%if %{with wifi}
-Dwifi=true \
%if 0%{?fedora}
-Dwext=true \
%else
-Dwext=false \
%endif
%else
-Dwifi=false \
%endif
-Dwext=false \
%if %{with iwd}
-Diwd=true \
%else
@ -676,21 +666,19 @@ Preferably use nmcli instead.
-Dselinux=true \
-Dpolkit=true \
-Dconfig_auth_polkit_default=true \
-Dmodify_system=true \
%if %{with polkit_noauth_group}
-Dpolkit_noauth_group=wheel \
%endif
-Dconcheck=true \
%if 0%{?fedora}
-Dlibpsl=true \
%else
-Dlibpsl=false \
%endif
%if %{ebpf_enabled} != "yes"
-Debpf=false \
%else
-Debpf=true \
%endif
-Dsession_tracking=systemd \
-Dsuspend_resume=systemd \
-Dsystemdsystemunitdir=%{_unitdir} \
-Dsystemdsystemgeneratordir=%{_systemdgeneratordir} \
-Dsystem_ca_path=/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem \
-Ddbus_conf_dir=%{dbus_sys_dir} \
-Dtests=yes \
@ -763,6 +751,7 @@ rm -f %{buildroot}%{_libdir}/pppd/%{ppp_version}/*.la
rm -f %{buildroot}%{nmplugindir}/*.la
# Don't use the *-initrd.service files yet, wait dracut to support them
rm -f %{buildroot}%{_systemdgeneratordir}/nm-initrd-generator.sh
rm -f %{buildroot}%{_unitdir}/NetworkManager-config-initrd.service
rm -f %{buildroot}%{_unitdir}/NetworkManager-initrd.service
rm -f %{buildroot}%{_unitdir}/NetworkManager-wait-online-initrd.service
@ -896,6 +885,7 @@ fi
%{_libexecdir}/nm-dispatcher
%{_libexecdir}/nm-initrd-generator
%{_libexecdir}/nm-daemon-helper
%{_libexecdir}/nm-libnm-helper
%{_libexecdir}/nm-priv-helper
%dir %{_libdir}/%{name}
%dir %{nmplugindir}
@ -927,6 +917,9 @@ fi
%{_datadir}/dbus-1/system-services/org.freedesktop.nm_dispatcher.service
%{_datadir}/dbus-1/system-services/org.freedesktop.nm_priv_helper.service
%{_datadir}/polkit-1/actions/*.policy
%if %{with polkit_noauth_group}
%{_datadir}/polkit-1/rules.d/org.freedesktop.NetworkManager.rules
%endif
%{_prefix}/lib/udev/rules.d/*.rules
%{_prefix}/lib/firewalld/zones/nm-shared.xml
# systemd stuff

View file

@ -155,7 +155,6 @@ P_CRYPTO="${CRYPTO-}"
P_DBUS_SYS_DIR="${DBUS_SYS_DIR-}"
P_DHCP_DEFAULT="${DHCP_DEFAULT-}"
P_DNS_RC_MANAGER_DEFAULT="${DNS_RC_MANAGER_DEFAULT-}"
P_EBPF_ENABLED="${EBPF_ENABLED-no}"
P_FIREWALLD_ZONE="${FIREWALLD_ZONE-}"
P_IWD="${IWD-}"
P_LOGGING_BACKEND_DEFAULT="${LOGGING_BACKEND_DEFAULT-}"
@ -174,6 +173,7 @@ P_WIFI="${WIFI-1}"
P_WWAN="${WWAN-1}"
P_TEAM="${TEAM-1}"
P_BLUETOOTH="${BLUETOOTH-1}"
P_IFCFG_RH="${IFCFG_RH-0}"
P_NMTUI="${NMTUI-1}"
P_NM_CLOUD_SETUP="${NM_CLOUD_SETUP-1}"
P_OVS="${OVS-1}"
@ -203,7 +203,7 @@ if [ -z "$P_FEDORA" -a -z "$P_RHEL" ] ; then
P_FEDORA="$x"
P_RHEL=0
else
x="$(grep -q "ID=fedora" /etc/os-release && sed -n 's/VERSION_ID=//p' /etc/os-release)"
x="$(grep -q 'ID="rhel"' /etc/os-release && sed -n 's/^VERSION_ID="*\([0-9]*\).*/\1/p' /etc/os-release)"
if test "$x" -gt 0 ; then
P_FEDORA=0
P_RHEL="$x"
@ -294,6 +294,14 @@ if [ -z "$P_MODEM_MANAGER_1" ] ; then
fi
fi
if [ -z "$TEAM" ] && [ "${P_RHEL-0}" -ge 10 ] ; then
P_TEAM=0
fi
if [ -z "$IFCFG_RH" ] && [ -n "$P_RHEL" ] && [ "$P_RHEL" -le 9 ] ; then
P_IFCFG_RH=1
fi
if bool "$P_DEBUG" ; then
P_CFLAGS="-g -Og -fexceptions${P_CFLAGS:+ }$P_CFLAGS"
else
@ -379,7 +387,7 @@ meson setup\
-Db_lto="$(bool_true "$P_LTO")" \
-Dlibaudit=yes-disabled-by-default \
-Dmodem_manager="$(bool_true "$P_MODEM_MANAGER_1")" \
$(args_enable "$P_WIFI" -Dwifi=true -Dwext="$(bool_true "$P_FEDORA")") \
$(args_enable "$P_WIFI" -Dwifi=true -Dwext=false) \
$(args_enable "$(bool_not_true "$P_WIFI")" -Dwifi=false ) \
-Diwd="$(bool_true "$P_IWD")" \
-Dbluez5_dun="$(bool_true "$P_BLUETOOTH")" \
@ -393,18 +401,17 @@ meson setup\
-Dselinux=true \
-Dpolkit=true \
-Dconfig_auth_polkit_default=true \
-Dmodify_system=true \
-Dconcheck=true \
-Dlibpsl="$(bool_true "$P_FEDORA")" \
-Debpf="$(bool_true "$P_EBPF_ENABLED")" \
-Dsession_tracking=systemd \
-Dsuspend_resume=systemd \
-Dsystemdsystemunitdir=/usr/lib/systemd/system \
-Dsystemdsystemgeneratordir=/usr/lib/systemd/system-generators \
-Dsystem_ca_path=/etc/pki/tls/cert.pem \
-Ddbus_conf_dir="$P_DBUS_SYS_DIR" \
-Dtests=yes \
-Dvalgrind=no \
-Difcfg_rh=true \
-Difcfg_rh="$(bool_true "$P_IFCFG_RH")" \
-Difupdown=false \
$(args_enable "$P_PPP" -Dppp=true -Dpppd="$D_SBINDIR/pppd" -Dpppd_plugin_dir="$D_LIBDIR/pppd/$P_PPP_VERSION") \
$(args_enable "$(bool_not_true "$P_PPP")" -Dppp=false ) \

View file

@ -169,6 +169,7 @@ meson setup build \
-D ld_gc=false \
-D session_tracking=no \
-D systemdsystemunitdir=no \
-D systemdsystemgeneratordir=no \
-D systemd_journal=false \
-D selinux=false \
-D libaudit=no \
@ -180,8 +181,6 @@ meson setup build \
-D crypto=$_WITH_CRYPTO \
-D docs=$_WITH_DOCS \
\
-D ebpf=false \
\
-D iwd=true \
-D ofono=true \
-D teamdctl=$_WITH_LIBTEAM \

View file

@ -1,10 +1,10 @@
[Unit]
Description=NetworkManager Configuration (initrd)
AssertPathExists=/etc/initrd-release
DefaultDependencies=no
Wants=systemd-journald.socket
After=systemd-journald.socket
Before=systemd-udevd.service systemd-udev-trigger.service
ConditionPathExists=/etc/initrd-release
[Service]
Type=oneshot
@ -22,6 +22,3 @@ ExecStartPost=/bin/sh -c ' \
fi \
'
RemainAfterExit=yes
[Install]
WantedBy=initrd.target

View file

@ -1,11 +1,11 @@
[Unit]
Description=NetworkManager (initrd)
AssertPathExists=/etc/initrd-release
DefaultDependencies=no
Wants=systemd-udev-trigger.service network.target
After=systemd-udev-trigger.service network-pre.target dbus.service NetworkManager-config-initrd.service
Before=network.target
BindsTo=dbus.service
ConditionPathExists=/etc/initrd-release
ConditionPathExists=/run/NetworkManager/initrd/neednet
ConditionPathExistsGlob=|/usr/lib/NetworkManager/system-connections/*
ConditionPathExistsGlob=|/run/NetworkManager/system-connections/*
@ -22,11 +22,3 @@ Environment=NM_CONFIG_ENABLE_TAG=initrd
Restart=on-failure
ProtectSystem=true
ProtectHome=read-only
[Install]
WantedBy=initrd.target
# We want to enable NetworkManager-wait-online-initrd.service whenever this
# service is enabled. NetworkManager-wait-online-initrd.service has
# WantedBy=network-online.target, so enabling it only has an effect if
# network-online.target itself is enabled or pulled in by some other unit.
Also=NetworkManager-config-initrd.service NetworkManager-wait-online-initrd.service

View file

@ -1,10 +1,10 @@
[Unit]
Description=NetworkManager Wait Online (initrd)
AssertPathExists=/etc/initrd-release
DefaultDependencies=no
Requires=NetworkManager-initrd.service
After=NetworkManager-initrd.service
Before=network-online.target
ConditionPathExists=/etc/initrd-release
ConditionPathExists=/run/NetworkManager/initrd/neednet
[Service]
@ -21,6 +21,3 @@ Type=oneshot
ExecStart=@bindir@/nm-online -s -q
RemainAfterExit=yes
Environment=NM_ONLINE_TIMEOUT=3600
[Install]
WantedBy=initrd.target network-online.target

View file

@ -19,7 +19,7 @@ KillMode=process
# With a huge number of interfaces, starting can take a long time.
TimeoutStartSec=600
CapabilityBoundingSet=CAP_NET_ADMIN CAP_DAC_OVERRIDE CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SETGID CAP_SETUID CAP_SYS_MODULE CAP_AUDIT_WRITE CAP_KILL CAP_SYS_CHROOT
CapabilityBoundingSet=CAP_NET_ADMIN CAP_DAC_OVERRIDE CAP_NET_RAW CAP_BPF CAP_NET_BIND_SERVICE CAP_SETGID CAP_SETUID CAP_SYS_MODULE CAP_AUDIT_WRITE CAP_KILL CAP_SYS_CHROOT
ProtectSystem=true
ProtectHome=read-only

View file

@ -55,21 +55,22 @@ if install_udevdir
endif
if enable_polkit
policy = 'org.freedesktop.NetworkManager.policy'
policy_in = configure_file(
input: policy + '.in.in',
output: '@BASENAME@',
configuration: data_conf,
)
i18n.merge_file(
input: policy_in,
input: 'org.freedesktop.NetworkManager.policy.in',
output: '@BASENAME@',
po_dir: po_dir,
install: true,
install_dir: polkit_gobject_policydir,
install_dir: polkit_policydir,
)
if polkit_noauth_group != ''
configure_file(
input: 'org.freedesktop.NetworkManager.rules.in',
output: '@BASENAME@',
install_dir: polkit_rulesdir,
configuration: {'NM_POLKIT_NOAUTH_GROUP': polkit_noauth_group},
)
endif
endif
if enable_firewalld_zone

View file

@ -117,8 +117,8 @@
<message>System policy prevents modification of network settings for all users</message>
<defaults>
<allow_any>auth_admin_keep</allow_any>
<allow_inactive>@NM_MODIFY_SYSTEM_POLICY@</allow_inactive>
<allow_active>@NM_MODIFY_SYSTEM_POLICY@</allow_active>
<allow_inactive>auth_admin_keep</allow_inactive>
<allow_active>auth_admin_keep</allow_active>
</defaults>
</action>

View file

@ -0,0 +1,17 @@
// NetworkManager authorizations/policy for the @NM_POLKIT_NOAUTH_GROUP@ group.
//
// DO NOT EDIT THIS FILE, it will be overwritten on update.
//
// Allow users in the @NM_POLKIT_NOAUTH_GROUP@ group to create system-wide connections without being
// prompted for a password if they are in a local console.
// This is optional and is only recommended to maintain backwards compatibility
// in systems where it was already working in this way. It is discouraged
// otherwise.
polkit.addRule(function(action, subject) {
if (action.id == "org.freedesktop.NetworkManager.settings.modify.system" &&
subject.isInGroup("@NM_POLKIT_NOAUTH_GROUP@") &&
subject.local) {
return polkit.Result.YES;
}
});

View file

@ -23,8 +23,8 @@ static const char *
nm_state_to_string(NMState state)
{
switch (state) {
case NM_STATE_ASLEEP:
return "asleep";
case NM_STATE_DISABLED:
return "network off";
case NM_STATE_CONNECTING:
return "connecting";
case NM_STATE_CONNECTED_LOCAL:

View file

@ -83,6 +83,11 @@
note that your distribution or other packages may drop configuration snippets for NetworkManager, such
that they are part of the factory default.
</para>
<para>
The options that are indicated as boolean can be set to one of these values:
<literal>yes</literal>, <literal>true</literal>, <literal>on</literal>, <literal>1</literal>,
<literal>no</literal>, <literal>false</literal>, <literal>off</literal>, <literal>0</literal>.
</para>
</refsect1>
@ -895,11 +900,15 @@ ipv6.ip6-privacy=0
</varlistentry>
<varlistentry>
<term><varname>connection.mptcp-flags</varname></term>
<listitem><para>If unspecified, the fallback is 0x22 (<literal>"enabled,subflow"</literal>). Note that if sysctl <literal>/proc/sys/net/mptcp/enabled</literal> is disabled, NetworkManager will still not configure endpoints.</para></listitem>
<listitem><para>If unspecified, the fallback is 0x122 (<literal>"enabled,subflow,laminar"</literal>). Note that if sysctl <literal>/proc/sys/net/mptcp/enabled</literal> is disabled, NetworkManager will still not configure endpoints.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>connection.dns-over-tls</varname></term>
<listitem><para>If unspecified, the ultimate default values depends on the DNS plugin. With systemd-resolved the default currently is global setting and for all other plugins "no" (0).</para></listitem>
<listitem><para>If unspecified, the ultimate default values depends on the DNS plugin. With systemd-resolved the default currently is its global setting and for all other plugins "no" (0).</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>connection.dnssec</varname></term>
<listitem><para>If unspecified, the ultimate default values depends on the DNS plugin. With systemd-resolved the default currently is its global setting and for all other plugins "no" (0).</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>connection.stable-id</varname></term>
@ -1245,12 +1254,13 @@ managed=1
<term><varname>managed</varname></term>
<listitem>
<para>
Whether the device is managed or not. A device can be
marked as managed via udev rules (ENV{NM_UNMANAGED}),
or via setting plugins (keyfile.unmanaged-devices).
This is yet another way. Note that this configuration
can be overruled at runtime via D-Bus. Also, it has
higher priority then udev rules.
A boolean value specifying whether the device is
managed or not. A device can be marked as managed via
udev rules (ENV{NM_UNMANAGED}), or via setting plugins
(keyfile.unmanaged-devices). This is yet another
way. Note that this configuration can be overruled at
runtime via D-Bus. Also, it has higher priority than
udev rules.
</para>
</listitem>
</varlistentry>
@ -1319,9 +1329,27 @@ managed=1
</para>
</listitem>
</varlistentry>
<varlistentry id="keep-configuration">
<term><varname>keep-configuration</varname></term>
<varlistentry id="check-connectivity">
<term><varname>check-connectivity</varname></term>
<listitem>
<para>
A boolean value specifying whether NetworkManager will perform a connectivity check
for this device. Defaults to <literal>yes</literal>.
</para>
<para>
This setting does nothing if the connectivity check has been
disabled globally using the
<literal>connectivity.enabled</literal> setting.
</para>
</listitem>
</varlistentry>
<varlistentry id="keep-configuration">
<term><varname>keep-configuration</varname></term>
<listitem>
<para>
A boolean value indicating whether the existing device
configuration is kept at startup.
</para>
<para>
On startup, NetworkManager tries to not interfere with
interfaces that are already configured. It does so by
@ -1418,16 +1446,16 @@ managed=1
<term><varname>wifi.iwd.autoconnect</varname></term>
<listitem>
<para>
If <literal>wifi.backend</literal> is <literal>iwd</literal>, setting this to
<literal>false</literal> forces IWD's autoconnect mechanism to be disabled for
this device and connections will only be initiated by NetworkManager whether
commanded by a client or automatically. Leaving it <literal>true</literal> (default)
stops NetworkManager from automatically initiating connections and allows
IWD to use its network ranking and scanning logic to decide the best networks
to autoconnect to next. Connections' <literal>autoconnect-priority</literal>,
<literal>autoconnect-retries</literal> settings will be ignored. Other settings
like <literal>permissions</literal> or <literal>multi-connect</literal> may interfere
with IWD connection attempts.
A boolean value. If <literal>wifi.backend</literal> is <literal>iwd</literal>,
setting this to <literal>false</literal> forces IWD's autoconnect mechanism to be
disabled for this device and connections will only be initiated by NetworkManager
whether commanded by a client or automatically. Leaving it <literal>true</literal>
(default) stops NetworkManager from automatically initiating connections and allows
IWD to use its network ranking and scanning logic to decide the best networks to
autoconnect to next. Connections' <literal>autoconnect-priority</literal>,
<literal>autoconnect-retries</literal> settings will be ignored. Other settings like
<literal>permissions</literal> or <literal>multi-connect</literal> may interfere with
IWD connection attempts.
</para>
</listitem>
</varlistentry>
@ -1486,7 +1514,7 @@ managed=1
<variablelist>
<varlistentry>
<term><varname>enabled</varname></term>
<listitem><para>Whether connectivity check is enabled.
<listitem><para>A boolean indicating whether connectivity check is enabled.
Note that to enable connectivity check, a valid uri must
also be configured. The value defaults to true, but since
the uri is unset by default, connectivity check may be disabled.

View file

@ -91,6 +91,10 @@
NetworkManager inserts the records for Bridges into OVSDB when a Port is
attached.
</para>
<para>Known limitation: when the last NetworkManager's owned port is removed,
the bridge is removed too, even if there are other externally attached ports.
</para>
</refsect2>
<refsect2>
@ -102,6 +106,10 @@
exist. Ports can also be configured to do VLAN tagging or Bonding.
NetworkManager inserts the records for Ports into OVSDB when an Interface is
attached. Ports must be attached to a Bridge.</para>
<para>Known limitation: when the last NetworkManager's owned interface is removed,
the port is removed too, even if there are other externally attached interfaces.
</para>
</refsect2>
<refsect2>

View file

@ -5,7 +5,7 @@ project(
# NOTE: When incrementing version also add corresponding
# NM_VERSION_x_y_z macros in
# "src/libnm-core-public/nm-version-macros.h.in"
version: '1.55.4',
version: '1.57.1',
license: 'GPL2+',
default_options: [
'buildtype=debugoptimized',
@ -327,12 +327,17 @@ config_h.set10('WITH_CONFIG_PLUGIN_IFUPDOWN', enable_ifupdown)
config_h.set_quoted('NM_DIST_VERSION', dist_version)
enable_wifi = get_option('wifi')
config_h.set10('WITH_WIFI', enable_wifi)
enable_iwd = get_option('iwd')
assert((not enable_iwd) or enable_wifi, 'Enabling iwd support requires Wi-Fi support as well')
config_h.set10('WITH_IWD', enable_iwd)
enable_wext = get_option('wext')
wext = get_option('wext')
if wext == 'true'
error('Wireless Extensions support is deprecated and will be removed in the future. Use -Dwext=force to keep using it')
endif
enable_wext = (wext == 'force')
config_h.set10('HAVE_WEXT', enable_wext)
# Checks for libdl - on certain platforms its part of libc
@ -382,6 +387,14 @@ if install_systemdunitdir and systemd_systemdsystemunitdir == ''
systemd_systemdsystemunitdir = systemd_dep.get_variable(pkgconfig: 'systemdsystemunitdir', pkgconfig_define: ['rootprefix', nm_prefix])
endif
systemd_systemdsystemgeneratordir = get_option('systemdsystemgeneratordir')
install_systemdgeneratordir = (systemd_systemdsystemgeneratordir != 'no')
if install_systemdgeneratordir and systemd_systemdsystemgeneratordir == ''
assert(systemd_dep.found(), 'systemd required but not found, please provide a valid systemd user generator dir or disable it')
systemd_systemdsystemgeneratordir = systemd_dep.get_variable(pkgconfig: 'systemdsystemgeneratordir', pkgconfig_define: ['rootprefix', nm_prefix])
endif
enable_systemd_journal = get_option('systemd_journal')
if enable_systemd_journal
assert(libsystemd_dep.found(), 'Missing systemd-journald support')
@ -476,19 +489,6 @@ if enable_selinux
endif
config_h.set10('HAVE_SELINUX', enable_selinux)
# eBPF support
ebpf_opt = get_option('ebpf')
# 'auto' means 'false', because there are still issues.
if ebpf_opt != 'true'
enable_ebpf = false
else
enable_ebpf = true
if not cc.has_header('linux/bpf.h')
assert(ebpf_opt != 'true', 'eBPF requires kernel support')
enable_ebpf = false
endif
endif
# libaudit support
libaudit = get_option('libaudit')
enable_libaudit = libaudit.contains('yes')
@ -507,12 +507,14 @@ if enable_teamdctl
libteamdctl_dep = dependency('libteamdctl', version: '>= 1.9')
assert(libteamdctl_dep.found(), 'You must have libteamdctl installed to build. Use -Dteamdctl=false to disable it')
endif
config_h.set10('WITH_TEAMDCTL', enable_teamdctl)
# polkit
enable_polkit = get_option('polkit')
if enable_polkit
# FIXME: policydir should be relative to `datadir`, not `prefix`. Fixed in https://gitlab.freedesktop.org/polkit/polkit/merge_requests/2
polkit_gobject_policydir = dependency('polkit-gobject-1').get_variable(pkgconfig: 'policydir', pkgconfig_define: ['prefix', nm_prefix])
polkit_policydir = dependency('polkit-gobject-1').get_variable(pkgconfig: 'policydir', pkgconfig_define: ['prefix', nm_prefix])
polkit_rulesdir = join_paths(fs.parent(polkit_policydir), 'rules.d')
endif
config_auth_polkit_default = get_option('config_auth_polkit_default')
@ -522,6 +524,12 @@ endif
config_h.set_quoted('NM_CONFIG_DEFAULT_MAIN_AUTH_POLKIT', config_auth_polkit_default)
enable_modify_system = get_option('modify_system')
if enable_modify_system
# FIXME: remove this after everyone has stopped using modify_system
error('modify_system=true is no longer allowed due to security reasons')
endif
polkit_noauth_group = get_option('polkit_noauth_group')
polkit_agent_helper_1_path = get_option('polkit_agent_helper_1')
foreach p : [ '/usr/libexec/polkit-agent-helper-1',
@ -616,6 +624,7 @@ if enable_modem_manager
endif
config_h.set_quoted('MOBILE_BROADBAND_PROVIDER_INFO_DATABASE', mobile_broadband_provider_info_database)
endif
config_h.set10('WITH_WWAN', enable_modem_manager)
# Bluez5 DUN support
enable_bluez5_dun = get_option('bluez5_dun')
@ -953,7 +962,6 @@ data_conf.set('NM_DHCP_CLIENTS_ENABLED', ', '.join(config_dhcp_c
data_conf.set('NM_MAJOR_VERSION', nm_major_version)
data_conf.set('NM_MICRO_VERSION', nm_micro_version)
data_conf.set('NM_MINOR_VERSION', nm_minor_version)
data_conf.set('NM_MODIFY_SYSTEM_POLICY', (enable_modify_system ? 'yes' : 'auth_admin_keep'))
data_conf.set('NM_VERSION', nm_version)
data_conf.set('VERSION', nm_version)
data_conf.set('bindir', nm_bindir)
@ -1069,6 +1077,7 @@ output = '\nSystem paths:\n'
output += ' prefix: ' + nm_prefix + '\n'
output += ' exec_prefix: ' + nm_prefix + '\n'
output += ' systemdunitdir: ' + systemd_systemdsystemunitdir + '\n'
output += ' systemdgeneratordir: ' + systemd_systemdsystemgeneratordir + '\n'
output += ' udev_dir: ' + udev_udevdir + '\n'
output += ' nmbinary: ' + nm_pkgsbindir + '\n'
output += ' nmconfdir: ' + nm_pkgconfdir + '\n'
@ -1083,17 +1092,7 @@ output += ' dbus_conf_dir: ' + dbus_conf_dir + '\n'
output += '\nPlatform:\n'
output += ' session tracking: ' + ','.join(session_trackers) + '\n'
output += ' suspend/resume: ' + suspend_resume + '\n'
output += ' policykit: ' + enable_polkit.to_string() + ' (default: ' + config_auth_polkit_default + ')'
if enable_polkit
output += ' ('
if enable_modify_system
output += 'permissive'
else
output += 'restrictive'
endif
output += ' modify.system)'
endif
output += '\n'
output += ' policykit: ' + enable_polkit.to_string() + ' (default: ' + config_auth_polkit_default + ', noauth_group: "' + polkit_noauth_group + '")\n'
output += ' polkit-agent-helper-1: ' + polkit_agent_helper_1_path + '\n'
output += ' selinux: ' + enable_selinux.to_string() + '\n'
output += ' systemd-journald: ' + enable_systemd_journal.to_string() + ' (default: logging.backend=' + config_logging_backend_default + ')\n'
@ -1157,6 +1156,5 @@ output += 'have-nss: ' + crypto_nss_dep.found().to_string() + ')\n'
output += ' sanitizers: ' + get_option('b_sanitize') + '\n'
output += ' Mozilla Public Suffix List: ' + enable_libpsl.to_string() + '\n'
output += ' vapi: ' + enable_vapi.to_string() + '\n'
output += ' ebpf: ' + enable_ebpf.to_string() + '\n'
output += ' readline: ' + with_readline + '\n'
message(output)

View file

@ -1,5 +1,6 @@
# system paths
option('systemdsystemunitdir', type: 'string', value: '', description: 'Directory for systemd service files')
option('systemdsystemgeneratordir', type: 'string', value: '', description: 'Directory for systemd generator files')
option('system_ca_path', type: 'string', value: '/etc/ssl/certs', description: 'path to system CA certificates')
option('udev_dir', type: 'string', value: '', description: 'Absolute path of the udev base directory. Set to \'no\' not to install the udev rule')
option('dbus_conf_dir', type: 'string', value: '', description: 'where D-Bus system.d directory is')
@ -18,7 +19,8 @@ option('session_tracking', type: 'combo', choices: ['systemd', 'elogind', 'no'],
option('suspend_resume', type: 'combo', choices: ['systemd', 'elogind', 'consolekit', 'auto'], value: 'auto', description: 'Build NetworkManager with specific suspend/resume support')
option('polkit', type: 'boolean', value: true, description: 'User auth-polkit configuration option.')
option('config_auth_polkit_default', type: 'combo', choices: ['default', 'true', 'false', 'root-only'], value: 'default', description: 'Default value for configuration main.auth-polkit.')
option('modify_system', type: 'boolean', value: false, description: 'Allow users to modify system connections')
option('modify_system', type: 'boolean', value: false, description: 'Allow users to modify system connections (option no longer supported, don\'t use)')
option('polkit_noauth_group', type: 'string', value: '', description: 'Allow users of the selected group, typically sudo or wheel, to modify system connections without introducing a password (discouraged)')
option('polkit_agent_helper_1', type: 'string', value: '', description: 'Path name to the polkit-agent-helper-1 binary from polkit')
option('selinux', type: 'boolean', value: true, description: 'Build with SELinux')
option('systemd_journal', type: 'boolean', value: true, description: 'Use systemd journal for logging')
@ -28,7 +30,7 @@ option('hostname_persist', type: 'combo', choices: ['default', 'suse', 'gentoo',
option('libaudit', type: 'combo', choices: ['yes', 'yes-disabled-by-default', 'no'], value: 'yes', description: 'Build with audit daemon support. yes-disabled-by-default enables support, but disables it unless explicitly configured via NetworkManager.conf')
# features
option('wext', type: 'boolean', value: true, description: 'Enable or disable Linux Wireless Extensions')
option('wext', type: 'combo', choices: ['true', 'false', 'force' ], value: 'false', description: 'Enable or disable Linux Wireless Extensions (deprecated). wext support will be removed in a future release, don\'t rely on this.')
option('wifi', type: 'boolean', value: true, description: 'enable Wi-Fi support')
option('iwd', type: 'boolean', value: false, description: 'enable iwd support (experimental)')
option('ppp', type: 'boolean', value: true, description: 'enable PPP/PPPoE support')
@ -44,7 +46,7 @@ option('nmcli', type: 'boolean', value: true, description: 'Build nmcli')
option('nmtui', type: 'boolean', value: true, description: 'Build nmtui')
option('nm_cloud_setup', type: 'boolean', value: true, description: 'Build nm-cloud-setup, a tool for automatically configuring networking in cloud')
option('bluez5_dun', type: 'boolean', value: false, description: 'enable Bluez5 DUN support')
option('ebpf', type: 'combo', choices: ['auto', 'true', 'false'], description: 'Enable eBPF support')
option('ebpf', type: 'combo', choices: ['auto', 'true', 'false'], description: 'Enable eBPF support (deprecated)')
option('nbft', type: 'boolean', value: true, description: 'Enable NBFT support in the initrd generator')
# configuration plugins

View file

@ -1,6 +1,6 @@
# List of source files containing translatable strings.
# Please keep this file sorted alphabetically.
data/org.freedesktop.NetworkManager.policy.in.in
data/org.freedesktop.NetworkManager.policy.in
src/core/NetworkManagerUtils.c
src/core/devices/adsl/nm-device-adsl.c
src/core/devices/bluetooth/nm-bluez-manager.c

View file

@ -8,14 +8,15 @@
# Lubomir Rintel <lkundrak@v3.sk>, 2016. #zanata
# Lubomir Rintel <lkundrak@v3.sk>, 2017. #zanata
# Thomas Haller <thaller@redhat.com>, 2017. #zanata
# Jordi Mas i Hernàndez <jmas@softcatala.org>, 2025
msgid ""
msgstr ""
"Project-Id-Version: NetworkManager\n"
"Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/NetworkManager/"
"NetworkManager/issues\n"
"POT-Creation-Date: 2023-06-16 15:26+0000\n"
"PO-Revision-Date: 2023-06-17 00:07+0200\n"
"Last-Translator: Copied by Zanata <copied-by-zanata@zanata.org>\n"
"PO-Revision-Date: 2025-09-28 00:07+0200\n"
"Last-Translator: Jordi Mas i Hernàndez <jmas@softcatala.org>\n"
"Language-Team: Catalan <tradgnome@softcatala.org>\n"
"Language: ca\n"
"MIME-Version: 1.0\n"
@ -355,7 +356,7 @@ msgstr "Connexió WPAN"
#: src/core/devices/team/nm-device-team.c:131
msgid "Team connection"
msgstr "Connexió equip"
msgstr "Connexió d'equip"
#: src/core/devices/wifi/nm-device-olpc-mesh.c:112 src/nmcli/devices.c:1400
msgid "Mesh"
@ -648,7 +649,7 @@ msgstr "Surt després de la configuració inicial"
#: src/core/nm-config.c:639
msgid "Don't become a daemon, and log to stderr"
msgstr ""
"No et converteixis en un dimoni, i envia el registre a la sortida estàndard"
"No et converteixis en un dimoni, i envia el registre a la sortida d'error"
#: src/core/nm-config.c:648
msgid "An http(s) address for checking internet connectivity"
@ -795,7 +796,7 @@ msgstr "La connexió no era una connexió Ethernet o PPPoE."
#: src/libnm-client-impl/nm-device-ethernet.c:206
msgid "The connection and device differ in S390 subchannels."
msgstr "La connexió i el dispositiu difereixen als subcanals 5930."
msgstr "La connexió i el dispositiu difereixen als subcanals S390."
#: src/libnm-client-impl/nm-device-ethernet.c:223
#, c-format
@ -881,7 +882,7 @@ msgstr "La connexió no era una connexió tun."
#: src/libnm-client-impl/nm-device-team.c:124
msgid "The connection was not a team connection."
msgstr "La connexió no era una connexió equip."
msgstr "La connexió no era una connexió d'equip."
#: src/libnm-client-impl/nm-device-tun.c:204
msgid "The connection was not a tun connection."
@ -1325,27 +1326,27 @@ msgstr ""
#: src/libnm-core-impl/nm-keyfile.c:333
msgid "ignoring missing number"
msgstr "s'ignora el número faltant"
msgstr "s'ignora el número faltant"
#: src/libnm-core-impl/nm-keyfile.c:345
#, c-format
msgid "ignoring invalid number '%s'"
msgstr "s'ignora el número «%s» no vàlid"
msgstr "s'ignora el número «%s» no vàlid"
#: src/libnm-core-impl/nm-keyfile.c:374
#, c-format
msgid "ignoring invalid %s address: %s"
msgstr "s'ignora l'adreça %s no vàlida: %s"
msgstr "s'ignora l'adreça %s no vàlida: %s"
#: src/libnm-core-impl/nm-keyfile.c:420
#, c-format
msgid "ignoring invalid gateway '%s' for %s route"
msgstr "s'ignora la passarel·la «%s» no vàlida per a la ruta %s"
msgstr "s'ignora la passarel·la «%s» no vàlida per a la ruta %s"
#: src/libnm-core-impl/nm-keyfile.c:442
#, c-format
msgid "ignoring invalid %s route: %s"
msgstr "s'ignora la ruta %s no vàlida: %s"
msgstr "s'ignora la ruta %s no vàlida: %s"
#: src/libnm-core-impl/nm-keyfile.c:620
#, c-format
@ -1361,7 +1362,7 @@ msgstr "caràcter «%c» inesperat per a %s: «%s» (posició %td)"
#, c-format
msgid "unexpected character '%c' in prefix length for %s: '%s' (position %td)"
msgstr ""
"caràcter «%c» inesperat a la longitud de prefix %s: «%s» (posició %td)<"
"caràcter «%c» inesperat a la longitud de prefix %s: «%s» (posició %td)"
#: src/libnm-core-impl/nm-keyfile.c:669
#, c-format
@ -1413,11 +1414,11 @@ msgstr "s'ignorarà l'adreça %s no vàlida: %s"
#: src/libnm-core-impl/nm-keyfile.c:1518
msgid "ignoring invalid SSID"
msgstr "s'ignora l'SSID no vàlida"
msgstr "s'ignora l'SSID no vàlida"
#: src/libnm-core-impl/nm-keyfile.c:1536
msgid "ignoring invalid raw password"
msgstr "s'ignora la contrasenya sense processar no vàlida"
msgstr "s'ignora la contrasenya sense processar no vàlida"
#: src/libnm-core-impl/nm-keyfile.c:1681
msgid "invalid key/cert value"
@ -1458,7 +1459,7 @@ msgstr "valor de paritat «%s» no vàlid"
#: src/libnm-core-impl/nm-keyfile.c:1958 src/libnm-core-impl/nm-keyfile.c:3540
#, c-format
msgid "invalid setting: %s"
msgstr "el paràmetre no és vàlid: «%s»"
msgstr "el paràmetre no és vàlid: %s"
#: src/libnm-core-impl/nm-keyfile.c:1978
#, fuzzy, c-format
@ -1973,7 +1974,7 @@ msgstr "file:// URI no és UTF-8 vàlida"
#: src/libnm-core-impl/nm-setting-connection.c:1501
msgid "invalid permissions not in format \"user:$UNAME[:]\""
msgstr "els permisos no són vàlids, no estan en el format «user:$UNANE[:]"
msgstr "els permisos no són vàlids, no estan en el format «user:$UNAME[:]"
#: src/libnm-core-impl/nm-setting-connection.c:1530
#, c-format
@ -2086,7 +2087,7 @@ msgstr "«%s» no és un número"
#: src/libnm-core-impl/nm-setting-gsm.c:479
msgid "property is empty or wrong size"
msgstr "la propietat és buda o de mida incorrecta"
msgstr "la propietat és buida o de mida incorrecta"
#: src/libnm-core-impl/nm-setting-gsm.c:492
msgid "property must contain only digits"
@ -2098,12 +2099,12 @@ msgstr "no es pot activar quan hi ha una configuració manual"
#: src/libnm-core-impl/nm-setting-infiniband.c:215
msgid "Must specify a P_Key if specifying parent"
msgstr "S'ha d'especificar una P-Key si s'especifica el pare"
msgstr "S'ha d'especificar una P_Key si s'especifica el pare"
#: src/libnm-core-impl/nm-setting-infiniband.c:226
msgid "InfiniBand P_Key connection did not specify parent interface name"
msgstr ""
"La connexió InfiniBand P_Key no ha especificat el nom de l'interfície pare"
"La connexió InfiniBand P_Key no ha especificat el nom de la interfície pare"
#: src/libnm-core-impl/nm-setting-infiniband.c:234
msgid "the values 0 and 0x8000 are not allowed"
@ -2156,12 +2157,12 @@ msgstr "Adreça IPv4 «%s» no és vàlida"
#: src/libnm-core-impl/nm-setting-ip-config.c:106
#, c-format
msgid "Invalid IPv4 address prefix '%u'"
msgstr "Prefix «%u» d'adreça IPv4 no vàlida"
msgstr "Prefix «%u» d'adreça IPv4 no vàlid"
#: src/libnm-core-impl/nm-setting-ip-config.c:107
#, c-format
msgid "Invalid IPv6 address prefix '%u'"
msgstr "Prefix «%u» d'adreça IPv6 no vàlida<"
msgstr "Prefix «%u» d'adreça IPv6 no vàlid"
#: src/libnm-core-impl/nm-setting-ip-config.c:124
#, c-format
@ -2208,7 +2209,7 @@ msgstr "el prefix %s no és vàlid"
#: src/libnm-core-impl/nm-setting-ip-config.c:1423
#, c-format
msgid "%s is not a valid route type"
msgstr "%s no és un nom de ruta vàlid"
msgstr "%s no és un tipus de ruta vàlid"
#: src/libnm-core-impl/nm-setting-ip-config.c:1442
#, fuzzy
@ -2432,7 +2433,7 @@ msgstr "La ruta %d. no és vàlida"
#: src/libnm-core-impl/nm-setting-ip-config.c:5638
#, c-format
msgid "invalid attribute: %s"
msgstr "atribut no vàlid: «%s»"
msgstr "atribut no vàlid: %s"
#: src/libnm-core-impl/nm-setting-ip-config.c:5658
#, c-format
@ -4105,7 +4106,7 @@ msgstr "«%s» no és vàlid; useu [%s] or [%s]"
#: src/libnmc-base/nm-client-utils.c:176
#, c-format
msgid "'%s' is not valid; use [%s], [%s] or [%s]"
msgstr "«%s» no és vàld, useu [%s], [%s] o [%s]"
msgstr "«%s» no és vàlid, useu [%s], [%s] o [%s]"
#: src/libnmc-base/nm-client-utils.c:230
#, c-format
@ -4676,7 +4677,7 @@ msgstr "clau privada no vàlida"
#, fuzzy, c-format
msgid "Secrets are required to connect WireGuard VPN '%s'"
msgstr ""
"Es requereixen contrasenyes o claus d'encriptació per accedir la xarxa sens "
"Es requereixen contrasenyes o claus d'encriptació per accedir la xarxa sense "
"fil «%s»."
#: src/libnmc-base/nm-secret-agent-simple.c:620
@ -4698,7 +4699,7 @@ msgid ""
"Passwords or encryption keys are required to access the wireless network "
"'%s'."
msgstr ""
"Es requereixen contrasenyes o claus d'encriptació per accedir la xarxa sens "
"Es requereixen contrasenyes o claus d'encriptació per accedir la xarxa sense "
"fil «%s»."
#: src/libnmc-base/nm-secret-agent-simple.c:886
@ -4709,7 +4710,7 @@ msgstr "Autenticació 802.1X de xarxa amb fil"
#, fuzzy, c-format
msgid "Secrets are required to access the wired network '%s'"
msgstr ""
"Es requereixen contrasenyes o claus d'encriptació per accedir la xarxa sens "
"Es requereixen contrasenyes o claus d'encriptació per accedir la xarxa sense "
"fil «%s»."
#: src/libnmc-base/nm-secret-agent-simple.c:893
@ -5418,10 +5419,10 @@ msgid ""
msgstr ""
"Entreu els bytes com una llista de valors hexadecimals.\n"
"S'accepten dos formats:\n"
"(a) una cadena de dígits exadecimals, on cada dos dígits representen un "
"(a) una cadena de dígits hexadecimals, on cada dos dígits representen un "
"byte\n"
"(b) una llista separada per espais de bytes escrits com a dígits hexadecimas "
"(amb prefix opcional 0x/0X,i un 0 inicial opcional). \n"
"(b) una llista separada per espais de bytes escrits com a dígits hexadecimals "
"(amb prefix opcional 0x/0X,i un 0 inicial opcional).\n"
"\n"
"Exemples: ab0455a6ea3a74C2\n"
" ab 4 55 0xa6 ea 3a 74 C2\n"
@ -5493,7 +5494,7 @@ msgstr "Demora cap endavant"
#: src/libnmc-setting/nm-meta-setting-desc.c:5280
#: src/nmtui/nmt-page-bridge.c:134
msgid "Hello time"
msgstr "Temps de benviguda"
msgstr "Temps de benvinguda"
#: src/libnmc-setting/nm-meta-setting-desc.c:5286
#: src/nmtui/nmt-page-bridge.c:148
@ -5567,7 +5568,7 @@ msgid ""
msgstr ""
"Entreu les connexions secundàries que s'haurien d'activar quan s'activa "
"aquesta connexió. Les connexions es poden especificar o bé per UUID o per ID "
"(nom). L'nmcli tradueix transparentment els noms a UUID. Noteu que el "
"(nom). nmcli tradueix transparentment els noms a UUID. Noteu que el "
"NetworkManager actualment sols dóna suport els VPN com a connexions "
"secundàries.\n"
"Els elements es poden separar per comes o espais.\n"
@ -5676,7 +5677,7 @@ msgid ""
" priority [prio] [from [src]] [to [dst]], ,...\n"
"\n"
msgstr ""
"Introduïu una llista de regles d'encaminanent IPv4 amb el següent format:\n"
"Introduïu una llista de regles d'encaminament IPv4 amb el següent format:\n"
" priority [prioritat] [from [origen]] [to [destí]], ,...\n"
"\n"
"\n"
@ -5696,7 +5697,7 @@ msgstr ""
"configuració IPv6 \n"
"és «auto» aquests servidors DNS s'annexen als que retorna (si retorna cap) "
"la \n"
"configuració automatica. Els servidors DNS no es poden usar amb els métodes "
"configuració automàtica. Els servidors DNS no es poden usar amb els mètodes "
"de \n"
"configuracó DNS «shared» o «link-local», atès que no hi una xarxa superior. "
"A tots\n"
@ -8151,12 +8152,12 @@ msgstr ""
"canonada (|) o un ampersand (&). El primer indica que l'element és opcional "
"i el segon significa que és obligatori. Si hi ha algun element opcional, "
"llavors la coincidència avalua a cert si almenys un dels elements opcionals "
"coincideix (O lògicà). Si hi ha elements obligatoris, llavors tots han de "
"coincideix (O lògica). Si hi ha elements obligatoris, llavors tots han de "
"coincidir (I lògica). Per defecte, un element és opcional. Això significa "
"que un element «foo» es comporta igual que «|foo». Un element també es pot "
"invertir amb el símbol d'exclamació (!) entre el símbol de la canonada (o de "
"l'ampersand) i abans del patró. Tingueu en compte que «!foo» és una drecera "
"per al patró obligatòri «&!foo». Finalment, es pot utilitzar una barra "
"per al patró obligatori «&!foo». Finalment, es pot utilitzar una barra "
"inversa al començament de l'element (després dels caràcters especials "
"opcionals) per no considerar-lo inici del patró. Per exemple, «\\!a» és una "
"coincidència obligatòria per literalment «!a»."
@ -10722,7 +10723,7 @@ msgstr "Error: «%s» no és una connexió activa.\n"
#: src/nmcli/connections.c:3436
msgid "Error: not all active connections found."
msgstr "Error: No s'han trobar totes les connexions actives."
msgstr "Error: No s'han trobat totes les connexions actives."
#: src/nmcli/connections.c:3444
msgid "Error: no active connection provided."
@ -11041,7 +11042,7 @@ msgstr ""
"Verifica si el paràmetre o la connexió és vàlida i es pot desar més tard.\n"
"Indica valors no vàlids quan hi ha un error. Alguns errors es poden "
"corregir\n"
"automàticaent amb l'opció «fix».\n"
"automàticament amb l'opció «fix».\n"
"\n"
"Exemples: nmcli> verify\n"
" nmcli> verify fix\n"
@ -11063,7 +11064,7 @@ msgid ""
msgstr ""
"save [persistent|temporary] :: desa la connexió\n"
"\n"
"Envia el perfil de la connexió al NetworManager que o bé la desarà de forma\n"
"Envia el perfil de la connexió al NetworkManager que o bé la desarà de forma\n"
"persistent o bé sols la mantindrà a la memòria. «desa» sense cap argument\n"
"significa «desa de forma persistent».\n"
"Noteu que un cop que deseu el perfile de forma persistent aquestes "
@ -11485,7 +11486,7 @@ msgstr "Opció no vàlida de verificació: %s\n"
#: src/nmcli/connections.c:8486
#, c-format
msgid "Verify setting '%s': %s\n"
msgstr "Verifica el paràmere «%s»: %s\n"
msgstr "Verifica el paràmetre «%s»: %s\n"
#: src/nmcli/connections.c:8501
#, c-format
@ -11552,12 +11553,12 @@ msgstr "Error: no es pot activar la connexió: %s.\n"
#: src/nmcli/connections.c:8679
#, c-format
msgid "Error: Failed to activate '%s' (%s) connection: %s\n"
msgstr "Error: no s'ha pogut desconnectar la connexió «%s» (%s): %s\n"
msgstr "Error: no s'ha pogut activar la connexió «%s» (%s): %s\n"
#: src/nmcli/connections.c:8686
msgid "Monitoring connection activation (press any key to continue)\n"
msgstr ""
"S'està supervisant l'activació de la connexio (premeu qualsevol teclar per "
"S'està supervisant l'activació de la connexió (premeu qualsevol tecla per "
"continuar)\n"
#: src/nmcli/connections.c:8721
@ -11582,7 +11583,7 @@ msgstr "Configuració actual del nmcli:\n"
#: src/nmcli/connections.c:8753
#, c-format
msgid "Invalid configuration option '%s'; allowed [%s]\n"
msgstr "Opció de configuració no vàida: «%s»; es permet [%s]\n"
msgstr "Opció de configuració no vàlida: «%s»; es permet [%s]\n"
#: src/nmcli/connections.c:8985
#, fuzzy
@ -12396,7 +12397,7 @@ msgstr "Error: no s'ha pogut afegir/activar la connexió nova: %s"
#: src/nmcli/devices.c:2266
#, c-format
msgid "Error: Device activation failed: %s"
msgstr "Error: no s'ha pogut activar el dispositu: %s"
msgstr "Error: no s'ha pogut activar el dispositiu: %s"
#: src/nmcli/devices.c:2322
#, c-format
@ -12603,7 +12604,7 @@ msgstr "Contrasenya: "
#: src/nmcli/devices.c:4172
#, c-format
msgid "'%s' is not valid WPA PSK"
msgstr "«%s» no és una WPS PSK vàlida"
msgstr "«%s» no és una WPA PSK vàlida"
#: src/nmcli/devices.c:4193
#, c-format
@ -13538,7 +13539,7 @@ msgstr "Error: s'esperava l'argument «%s», però s'ha proporcionat «%s»."
#: src/nmcli/utils.c:315
#, c-format
msgid "Error: Unexpected argument '%s'"
msgstr "Error: argument inesperat «%s»."
msgstr "Error: argument inesperat «%s»"
#: src/nmcli/utils.c:702
#, fuzzy, c-format
@ -13897,7 +13898,7 @@ msgstr "«%s» <"
#. NB: the ordering/numbering here corresponds to NmtPageBondMonitoringMode
#: src/nmtui/nmt-page-bond.c:92
msgid "MII (recommended)"
msgstr "MII (recomendat)"
msgstr "MII (recomanat)"
#: src/nmtui/nmt-page-bond.c:93
msgid "ARP"
@ -14543,7 +14544,7 @@ msgstr ""
#: src/nmtui/nmtui-edit.c:394 src/nmtui/nmtui-edit.c:410
msgid "New Connection"
msgstr "Connexions nova"
msgstr "Connexió nova"
#: src/nmtui/nmtui-edit.c:452
#, c-format

File diff suppressed because it is too large Load diff

368
po/sk.po

File diff suppressed because it is too large Load diff

6787
po/sl.po

File diff suppressed because it is too large Load diff

View file

@ -629,10 +629,17 @@ build_supplicant_config(NMDeviceEthernet *self, GError **error)
mtu = nm_platform_link_get_mtu(nm_device_get_platform(NM_DEVICE(self)),
nm_device_get_ifindex(NM_DEVICE(self)));
config = nm_supplicant_config_new(NM_SUPPL_CAP_MASK_NONE);
config = nm_supplicant_config_new(NM_SUPPL_CAP_MASK_NONE,
nm_utils_get_connection_first_permissions_user(connection));
security = nm_connection_get_setting_802_1x(connection);
if (!nm_supplicant_config_add_setting_8021x(config, security, con_uuid, mtu, TRUE, error)) {
if (!nm_supplicant_config_add_setting_8021x(config,
security,
con_uuid,
mtu,
TRUE,
nm_device_get_private_files(NM_DEVICE(self)),
error)) {
g_prefix_error(error, "802-1x-setting: ");
g_clear_object(&config);
}
@ -700,6 +707,9 @@ supplicant_iface_start(NMDeviceEthernet *self)
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE(self);
gs_unref_object NMSupplicantConfig *config = NULL;
gs_free_error GError *error = NULL;
NMActRequest *request;
NMActiveConnection *controller_ac;
NMDevice *controller;
config = build_supplicant_config(self, &error);
if (!config) {
@ -714,6 +724,16 @@ supplicant_iface_start(NMDeviceEthernet *self)
}
nm_supplicant_interface_disconnect(priv->supplicant.iface);
/* Tell the supplicant in which bridge the interface is */
if ((request = nm_device_get_act_request(NM_DEVICE(self)))
&& (controller_ac = nm_active_connection_get_controller(NM_ACTIVE_CONNECTION(request)))
&& (controller = nm_active_connection_get_device(controller_ac))
&& nm_device_get_device_type(controller) == NM_DEVICE_TYPE_BRIDGE) {
nm_supplicant_interface_set_bridge(priv->supplicant.iface, nm_device_get_iface(controller));
} else
nm_supplicant_interface_set_bridge(priv->supplicant.iface, NULL);
nm_supplicant_interface_assoc(priv->supplicant.iface, config, supplicant_iface_assoc_cb, self);
return TRUE;
}

View file

@ -116,29 +116,51 @@ create_and_realize(NMDevice *device,
const NMPlatformLink **out_plink,
GError **error)
{
const char *iface = nm_device_get_iface(device);
NMSettingHsr *s_hsr;
NMPlatformLnkHsr lnk = {};
int r;
const char *iface = nm_device_get_iface(device);
nm_auto_free char *err_msg = NULL;
NMSettingHsr *s_hsr;
NMPlatformLnkHsr lnk = {};
int r = 0;
s_hsr = _nm_connection_get_setting(connection, NM_TYPE_SETTING_HSR);
nm_assert(s_hsr);
if (nm_setting_hsr_get_port1(s_hsr) != NULL)
lnk.port1 = nm_platform_link_get_ifindex(NM_PLATFORM_GET, nm_setting_hsr_get_port1(s_hsr));
if (nm_setting_hsr_get_port2(s_hsr) != NULL)
lnk.port2 = nm_platform_link_get_ifindex(NM_PLATFORM_GET, nm_setting_hsr_get_port2(s_hsr));
lnk.multicast_spec = nm_setting_hsr_get_multicast_spec(s_hsr);
lnk.prp = nm_setting_hsr_get_prp(s_hsr);
if (nm_setting_hsr_get_interlink(s_hsr) != NULL) {
const char *ifname = nm_setting_hsr_get_interlink(s_hsr);
int ifindex = nm_platform_link_get_ifindex(NM_PLATFORM_GET, ifname);
if (ifindex <= 0) {
err_msg = g_strdup_printf("interlink port '%s' does not exist", ifname);
goto out;
}
lnk.interlink = ifindex;
}
lnk.multicast_spec = nm_setting_hsr_get_multicast_spec(s_hsr);
lnk.prp = nm_setting_hsr_get_prp(s_hsr);
lnk.protocol_version = nm_setting_hsr_get_protocol_version(s_hsr);
r = nm_platform_link_hsr_add(nm_device_get_platform(device), iface, &lnk, out_plink);
if (r < 0) {
err_msg = g_strdup(nm_strerror(r) ?: "unknown");
}
out:
if (err_msg) {
g_set_error(error,
NM_DEVICE_ERROR,
NM_DEVICE_ERROR_CREATION_FAILED,
"Failed to create HSR interface '%s' for '%s': %s",
iface,
nm_connection_get_id(connection),
nm_strerror(r));
err_msg);
return FALSE;
}

View file

@ -201,7 +201,8 @@ build_supplicant_config(NMDeviceMacsec *self, GError **error)
mtu = nm_platform_link_get_mtu(nm_device_get_platform(NM_DEVICE(self)),
nm_device_get_ifindex(NM_DEVICE(self)));
config = nm_supplicant_config_new(NM_SUPPL_CAP_MASK_NONE);
config = nm_supplicant_config_new(NM_SUPPL_CAP_MASK_NONE,
nm_utils_get_connection_first_permissions_user(connection));
s_macsec = nm_device_get_applied_setting(NM_DEVICE(self), NM_TYPE_SETTING_MACSEC);
@ -227,7 +228,13 @@ build_supplicant_config(NMDeviceMacsec *self, GError **error)
if (nm_setting_macsec_get_mode(s_macsec) == NM_SETTING_MACSEC_MODE_EAP) {
s_8021x = nm_connection_get_setting_802_1x(connection);
if (!nm_supplicant_config_add_setting_8021x(config, s_8021x, con_uuid, mtu, TRUE, error)) {
if (!nm_supplicant_config_add_setting_8021x(config,
s_8021x,
con_uuid,
mtu,
TRUE,
nm_device_get_private_files(NM_DEVICE(self)),
error)) {
g_prefix_error(error, "802-1x-setting: ");
return NULL;
}
@ -433,6 +440,9 @@ supplicant_iface_start(NMDeviceMacsec *self)
NMDeviceMacsecPrivate *priv = NM_DEVICE_MACSEC_GET_PRIVATE(self);
gs_unref_object NMSupplicantConfig *config = NULL;
gs_free_error GError *error = NULL;
NMActRequest *request;
NMActiveConnection *controller_ac;
NMDevice *controller;
config = build_supplicant_config(self, &error);
if (!config) {
@ -445,6 +455,16 @@ supplicant_iface_start(NMDeviceMacsec *self)
}
nm_supplicant_interface_disconnect(priv->supplicant.iface);
/* Tell the supplicant in which bridge the interface is */
if ((request = nm_device_get_act_request(NM_DEVICE(self)))
&& (controller_ac = nm_active_connection_get_controller(NM_ACTIVE_CONNECTION(request)))
&& (controller = nm_active_connection_get_device(controller_ac))
&& nm_device_get_device_type(controller) == NM_DEVICE_TYPE_BRIDGE) {
nm_supplicant_interface_set_bridge(priv->supplicant.iface, nm_device_get_iface(controller));
} else
nm_supplicant_interface_set_bridge(priv->supplicant.iface, NULL);
nm_supplicant_interface_assoc(priv->supplicant.iface, config, supplicant_iface_assoc_cb, self);
return TRUE;
}

View file

@ -115,9 +115,6 @@ gboolean nm_device_sysctl_ip_conf_set(NMDevice *self,
NML3ConfigData *nm_device_create_l3_config_data(NMDevice *self, NMIPConfigSource source);
NML3ConfigData *nm_device_create_l3_config_data_from_connection(NMDevice *self,
NMConnection *connection);
void nm_device_ip_method_dhcp4_start(NMDevice *self);
void nm_device_ip_method_autoconf6_start(NMDevice *self);
@ -179,4 +176,6 @@ void nm_device_auth_request(NMDevice *self,
void nm_device_link_properties_set(NMDevice *self, gboolean reapply);
GHashTable *nm_device_get_private_files(NMDevice *self);
#endif /* NM_DEVICE_PRIVATE_H */

View file

@ -135,13 +135,17 @@ NM_UTILS_LOOKUP_STR_DEFINE(
NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_UNMANAGED_LINK_NOT_INIT,
"unmanaged-link-not-init"),
NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_UNMANAGED_QUITTING, "unmanaged-quitting"),
NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_UNMANAGED_SLEEPING, "unmanaged-sleeping"),
NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_UNMANAGED_MANAGER_DISABLED,
"unmanaged-nm-disabled"),
NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_UNMANAGED_USER_CONF, "unmanaged-user-conf"),
NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_UNMANAGED_USER_EXPLICIT,
"unmanaged-user-explicit"),
NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_UNMANAGED_USER_SETTINGS,
"unmanaged-user-settings"),
NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_UNMANAGED_USER_UDEV, "unmanaged-user-udev"), );
NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_UNMANAGED_USER_UDEV, "unmanaged-user-udev"),
NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_NETWORKING_OFF, "networking-off"),
NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_MODEM_NO_OPERATOR_CODE,
"modem-no-operator-code"), );
NM_UTILS_LOOKUP_STR_DEFINE(nm_device_mtu_source_to_string,
NMDeviceMtuSource,
@ -235,7 +239,7 @@ resolve_addr_helper_cb(GObject *source, GAsyncResult *result, gpointer user_data
gs_free_error GError *error = NULL;
gs_free char *output = NULL;
output = nm_utils_spawn_helper_finish(result, &error);
output = nm_utils_spawn_helper_finish_string(result, &error);
if (nm_utils_error_is_cancelled(error))
return;
@ -274,6 +278,7 @@ resolve_addr_spawn_helper(ResolveAddrInfo *info, ResolveAddrService services)
nm_inet_ntop(info->addr_family, &info->address, addr_str);
_LOG2D(info, "start lookup via nm-daemon-helper using services: %s", str);
nm_utils_spawn_helper(NM_MAKE_STRV("resolve-address", addr_str, str),
FALSE,
g_task_get_cancellable(info->task),
resolve_addr_helper_cb,
info);

View file

@ -113,6 +113,19 @@ typedef enum {
RELEASE_PORT_TYPE_CONFIG_FORCE,
} ReleasePortType;
/**
* CleanupType:
* @CLEANUP_TYPE_KEEP: Cleanup internally but keep the real device's config. This is
* often used when moving a partially managed device to "unmanaged" (but not only).
* @CLEANUP_TYPE_REMOVED: The device suddently disappeared. Cleanup internally but don't
* make any action on the real device at all, as it no longer exists.
* @CLEANUP_TYPE_DECONFIGURE: Also deconfigure the real device. This is the typical
* action when a connection or device is set to "down", or fully managed devices
* moved to "unmanaged".
* @CLEANUP_TYPE_KEEP_REAPPLY: Like %CLEANUP_TYPE_KEEP, but indicating that it's a
* reapply. Some special actions can be done if we're doing a reapply, like keeping
* the existing DHCP lease, for example.
*/
typedef enum {
CLEANUP_TYPE_KEEP,
CLEANUP_TYPE_REMOVED,
@ -335,6 +348,12 @@ typedef struct {
int addr_family;
} HostnameResolver;
typedef enum {
PRIVATE_FILES_STATE_UNKNOWN = 0,
PRIVATE_FILES_STATE_READING,
PRIVATE_FILES_STATE_DONE,
} PrivateFilesState;
/*****************************************************************************/
enum {
@ -692,6 +711,8 @@ typedef struct _NMDevicePrivate {
IPDevStateData ipdev_data_unspec;
gulong sharing_ipv4_changed_id;
struct {
/* If we set the addrgenmode6, this records the previously set value. */
guint8 previous_mode_val;
@ -769,6 +790,13 @@ typedef struct _NMDevicePrivate {
guint64 rx_bytes;
} stats;
struct {
GHashTable *table;
GCancellable *cancellable;
char *user;
PrivateFilesState state;
} private_files;
bool mtu_force_set_done : 1;
bool needs_ip6_subnet : 1;
@ -779,7 +807,6 @@ typedef struct _NMDevicePrivate {
char *prop_ip_iface; /* IP interface D-Bus property */
GList *ping_operations;
GSource *ping_timeout;
bool refresh_forwarding_done : 1;
} NMDevicePrivate;
G_DEFINE_ABSTRACT_TYPE(NMDevice, nm_device, NM_TYPE_DBUS_OBJECT)
@ -867,6 +894,8 @@ static void _dev_ipshared4_spawn_dnsmasq(NMDevice *self);
static void _dev_ipshared6_start(NMDevice *self);
static void _dev_ipforwarding4_start(NMDevice *self, int addr_family);
static void
_cleanup_ip_pre(NMDevice *self, int addr_family, CleanupType cleanup_type, gboolean preserve_dhcp);
@ -1395,14 +1424,12 @@ _prop_get_ipvx_routed_dns(NMDevice *self, int addr_family)
}
static NMSettingConnectionMdns
_prop_get_connection_mdns(NMDevice *self)
_prop_get_connection_mdns(NMDevice *self, NMConnection *connection)
{
NMConnection *connection;
NMSettingConnectionMdns mdns = NM_SETTING_CONNECTION_MDNS_DEFAULT;
g_return_val_if_fail(NM_IS_DEVICE(self), NM_SETTING_CONNECTION_MDNS_DEFAULT);
connection = nm_device_get_applied_connection(self);
if (connection)
mdns = nm_setting_connection_get_mdns(nm_connection_get_setting_connection(connection));
if (mdns != NM_SETTING_CONNECTION_MDNS_DEFAULT)
@ -1437,14 +1464,12 @@ _prop_get_sriov_preserve_on_down(NMDevice *self, NMSettingSriov *s_sriov)
}
static NMSettingConnectionLlmnr
_prop_get_connection_llmnr(NMDevice *self)
_prop_get_connection_llmnr(NMDevice *self, NMConnection *connection)
{
NMConnection *connection;
NMSettingConnectionLlmnr llmnr = NM_SETTING_CONNECTION_LLMNR_DEFAULT;
g_return_val_if_fail(NM_IS_DEVICE(self), NM_SETTING_CONNECTION_LLMNR_DEFAULT);
connection = nm_device_get_applied_connection(self);
if (connection)
llmnr = nm_setting_connection_get_llmnr(nm_connection_get_setting_connection(connection));
if (llmnr != NM_SETTING_CONNECTION_LLMNR_DEFAULT)
@ -1459,14 +1484,12 @@ _prop_get_connection_llmnr(NMDevice *self)
}
static NMSettingConnectionDnsOverTls
_prop_get_connection_dns_over_tls(NMDevice *self)
_prop_get_connection_dns_over_tls(NMDevice *self, NMConnection *connection)
{
NMConnection *connection;
NMSettingConnectionDnsOverTls dns_over_tls = NM_SETTING_CONNECTION_DNS_OVER_TLS_DEFAULT;
g_return_val_if_fail(NM_IS_DEVICE(self), NM_SETTING_CONNECTION_DNS_OVER_TLS_DEFAULT);
connection = nm_device_get_applied_connection(self);
if (connection)
dns_over_tls = nm_setting_connection_get_dns_over_tls(
nm_connection_get_setting_connection(connection));
@ -1481,15 +1504,33 @@ _prop_get_connection_dns_over_tls(NMDevice *self)
NM_SETTING_CONNECTION_DNS_OVER_TLS_DEFAULT);
}
static NMMptcpFlags
_prop_get_connection_mptcp_flags(NMDevice *self)
static NMSettingConnectionDnssec
_prop_get_connection_dnssec(NMDevice *self, NMConnection *connection)
{
NMConnection *connection;
NMMptcpFlags mptcp_flags = NM_MPTCP_FLAGS_NONE;
NMSettingConnectionDnssec dnssec = NM_SETTING_CONNECTION_DNSSEC_DEFAULT;
g_return_val_if_fail(NM_IS_DEVICE(self), NM_SETTING_CONNECTION_DNSSEC_DEFAULT);
if (connection)
dnssec = nm_setting_connection_get_dnssec(nm_connection_get_setting_connection(connection));
if (dnssec != NM_SETTING_CONNECTION_DNSSEC_DEFAULT)
return dnssec;
return nm_config_data_get_connection_default_int64(NM_CONFIG_GET_DATA,
NM_CON_DEFAULT("connection.dnssec"),
self,
NM_SETTING_CONNECTION_DNSSEC_NO,
NM_SETTING_CONNECTION_DNSSEC_YES,
NM_SETTING_CONNECTION_DNSSEC_DEFAULT);
}
static NMMptcpFlags
_prop_get_connection_mptcp_flags(NMDevice *self, NMConnection *connection)
{
NMMptcpFlags mptcp_flags = NM_MPTCP_FLAGS_NONE;
g_return_val_if_fail(NM_IS_DEVICE(self), NM_MPTCP_FLAGS_DISABLED);
connection = nm_device_get_applied_connection(self);
if (connection) {
mptcp_flags =
nm_setting_connection_get_mptcp_flags(nm_connection_get_setting_connection(connection));
@ -2131,8 +2172,8 @@ _prop_get_ipvx_dhcp_send_hostname(NMDevice *self, int addr_family)
return send_hostname_v2;
}
NMSettingIPConfigForwarding
nm_device_get_ipv4_forwarding(NMDevice *self)
static NMSettingIPConfigForwarding
_prop_get_ipv4_forwarding(NMDevice *self)
{
NMSettingIPConfig *s_ip;
NMSettingIPConfigForwarding forwarding;
@ -2455,16 +2496,14 @@ _prop_get_ipv4_dhcp_vendor_class_identifier(NMDevice *self, NMSettingIP4Config *
}
static NMSettingIP6ConfigPrivacy
_prop_get_ipv6_ip6_privacy(NMDevice *self)
_prop_get_ipv6_ip6_privacy(NMDevice *self, NMConnection *connection)
{
NMSettingIP6ConfigPrivacy ip6_privacy;
NMConnection *connection;
g_return_val_if_fail(self, NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN);
/* 1.) First look at the per-connection setting. If it is not -1 (unknown),
* use it. */
connection = nm_device_get_applied_connection(self);
if (connection) {
NMSettingIPConfig *s_ip6 = nm_connection_get_setting_ip6_config(connection);
@ -3597,11 +3636,12 @@ nm_device_create_l3_config_data_from_connection(NMDevice *self, NMConnection *co
l3cd =
nm_l3_config_data_new_from_connection(nm_device_get_multi_index(self), ifindex, connection);
nm_l3_config_data_set_mdns(l3cd, _prop_get_connection_mdns(self));
nm_l3_config_data_set_llmnr(l3cd, _prop_get_connection_llmnr(self));
nm_l3_config_data_set_dns_over_tls(l3cd, _prop_get_connection_dns_over_tls(self));
nm_l3_config_data_set_ip6_privacy(l3cd, _prop_get_ipv6_ip6_privacy(self));
nm_l3_config_data_set_mptcp_flags(l3cd, _prop_get_connection_mptcp_flags(self));
nm_l3_config_data_set_mdns(l3cd, _prop_get_connection_mdns(self, connection));
nm_l3_config_data_set_llmnr(l3cd, _prop_get_connection_llmnr(self, connection));
nm_l3_config_data_set_dns_over_tls(l3cd, _prop_get_connection_dns_over_tls(self, connection));
nm_l3_config_data_set_dnssec(l3cd, _prop_get_connection_dnssec(self, connection));
nm_l3_config_data_set_ip6_privacy(l3cd, _prop_get_ipv6_ip6_privacy(self, connection));
nm_l3_config_data_set_mptcp_flags(l3cd, _prop_get_connection_mptcp_flags(self, connection));
return l3cd;
}
@ -3778,7 +3818,7 @@ nm_device_assume_state_reset(NMDevice *self)
/*****************************************************************************/
char *
static char *
nm_device_sysctl_ip_conf_get(NMDevice *self, int addr_family, const char *property)
{
const char *ifname;
@ -6304,6 +6344,14 @@ concheck_is_possible(NMDevice *self)
if (priv->state == NM_DEVICE_STATE_UNKNOWN)
return FALSE;
if (!nm_config_data_get_device_config_boolean_by_device(
NM_CONFIG_GET_DATA,
NM_CONFIG_KEYFILE_KEY_DEVICE_CHECK_CONNECTIVITY,
self,
TRUE,
TRUE))
return FALSE;
return TRUE;
}
@ -6324,8 +6372,10 @@ concheck_periodic_schedule_do(NMDevice *self, int addr_family, gint64 now_ns)
goto out;
}
if (!concheck_is_possible(self))
if (!concheck_is_possible(self)) {
concheck_update_state(self, addr_family, NM_CONNECTIVITY_UNKNOWN, FALSE);
goto out;
}
nm_assert(now_ns > 0);
nm_assert(priv->concheck_x[IS_IPv4].p_cur_interval > 0);
@ -6548,7 +6598,11 @@ concheck_update_interval(NMDevice *self, int addr_family, gboolean check_now)
concheck_periodic_schedule_do(self, addr_family, 0);
/* also update the fake connectivity state. */
concheck_update_state(self, addr_family, NM_CONNECTIVITY_FAKE, TRUE);
if (concheck_is_possible(self))
concheck_update_state(self, addr_family, NM_CONNECTIVITY_FAKE, TRUE);
else
concheck_update_state(self, addr_family, NM_CONNECTIVITY_UNKNOWN, FALSE);
return;
}
@ -6577,6 +6631,7 @@ concheck_update_state(NMDevice *self,
/* @state is a result of the connectivity check. We only expect a precise
* number of possible values. */
nm_assert(NM_IN_SET(state,
NM_CONNECTIVITY_UNKNOWN,
NM_CONNECTIVITY_LIMITED,
NM_CONNECTIVITY_PORTAL,
NM_CONNECTIVITY_FULL,
@ -6645,7 +6700,7 @@ concheck_update_state(NMDevice *self,
}
}
const char *
static const char *
nm_device_get_effective_ip_config_method(NMDevice *self, int addr_family)
{
NMDeviceClass *klass;
@ -6900,8 +6955,11 @@ nm_device_check_connectivity(NMDevice *self,
NMDeviceConnectivityCallback callback,
gpointer user_data)
{
if (!concheck_is_possible(self))
if (!concheck_is_possible(self)) {
concheck_update_state(self, AF_INET, NM_CONNECTIVITY_UNKNOWN, FALSE);
concheck_update_state(self, AF_INET6, NM_CONNECTIVITY_UNKNOWN, FALSE);
return NULL;
}
concheck_periodic_schedule_set(self, addr_family, CONCHECK_SCHEDULE_CHECK_EXTERNAL);
return concheck_start(self, addr_family, callback, user_data, FALSE);
@ -8289,6 +8347,17 @@ config_changed(NMConfig *config,
&& !nm_device_get_applied_setting(self, NM_TYPE_SETTING_SRIOV))
device_init_static_sriov_num_vfs(self);
}
if (NM_FLAGS_HAS(changes, NM_CONFIG_CHANGE_VALUES) && concheck_is_possible(self)) {
/* restart (periodic) connectivity checks if they were previously disabled */
if (!nm_config_data_get_device_config_boolean_by_device(
old_data,
NM_CONFIG_KEYFILE_KEY_DEVICE_CHECK_CONNECTIVITY,
self,
TRUE,
TRUE))
nm_device_check_connectivity_update_interval(self);
}
}
static void
@ -8639,6 +8708,8 @@ nm_device_unrealize(NMDevice *self, gboolean remove_resources, GError **error)
g_object_thaw_notify(G_OBJECT(self));
nm_device_managed_type_set(self, NM_DEVICE_MANAGED_TYPE_REMOVED);
nm_device_set_unmanaged_flags(self, NM_UNMANAGED_PLATFORM_INIT, TRUE);
nm_device_set_unmanaged_flags(self,
@ -10802,6 +10873,49 @@ tc_commit(NMDevice *self)
return TRUE;
}
static void
read_private_files_cb(GObject *source_object, GAsyncResult *result, gpointer data)
{
gs_unref_hashtable GHashTable *table = NULL;
gs_free_error GError *error = NULL;
NMDevice *self;
NMDevicePrivate *priv;
table = nm_utils_read_private_files_finish(result, &error);
if (nm_utils_error_is_cancelled(error))
return;
self = NM_DEVICE(data);
priv = NM_DEVICE_GET_PRIVATE(self);
if (error) {
NMConnection *connection = nm_device_get_applied_connection(self);
_LOGW(LOGD_DEVICE,
"could not read files for private connection %s owned by user '%s': %s",
connection ? nm_connection_get_uuid(connection) : NULL,
priv->private_files.user,
error->message);
nm_device_state_changed(self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_CONFIG_FAILED);
return;
}
_LOGD(LOGD_DEVICE, "private files successfully read");
priv->private_files.state = PRIVATE_FILES_STATE_DONE;
priv->private_files.table = g_steal_pointer(&table);
g_clear_pointer(&priv->private_files.user, g_free);
g_clear_object(&priv->private_files.cancellable);
nm_device_activate_schedule_stage2_device_config(self, FALSE);
}
GHashTable *
nm_device_get_private_files(NMDevice *self)
{
return NM_DEVICE_GET_PRIVATE(self)->private_files.table;
}
/*
* activate_stage2_device_config
*
@ -10814,6 +10928,7 @@ activate_stage2_device_config(NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
NMDeviceClass *klass = NM_DEVICE_GET_CLASS(self);
NMConnection *applied;
NMActStageReturn ret;
NMSettingWired *s_wired;
gboolean no_firmware = FALSE;
@ -10822,6 +10937,68 @@ activate_stage2_device_config(NMDevice *self)
nm_device_state_changed(self, NM_DEVICE_STATE_CONFIG, NM_DEVICE_STATE_REASON_NONE);
applied = nm_device_get_applied_connection(self);
/* If the connection is private (owned by a specific user), we need to
* verify that the user has permission to access any files specified in
* the connection, such as certificates and keys. We do that by calling
* nm_utils_read_private_files() and saving the file contents in a hash
* table that can be accessed later during the activation. It is important
* to never access the files again to avoid TOCTOU bugs.
*/
switch (priv->private_files.state) {
case PRIVATE_FILES_STATE_UNKNOWN:
{
gs_free const char **paths = NULL;
NMSettingConnection *s_con;
const char *user;
s_con = nm_connection_get_setting_connection(applied);
nm_assert(s_con);
user = _nm_setting_connection_get_first_permissions_user(s_con);
priv->private_files.user = g_strdup(user);
if (!priv->private_files.user) {
priv->private_files.state = PRIVATE_FILES_STATE_DONE;
break;
}
paths = nm_utils_get_connection_private_files_paths(applied);
if (!paths) {
priv->private_files.state = PRIVATE_FILES_STATE_DONE;
break;
}
if (_nm_setting_connection_get_num_permissions_users(s_con) > 1) {
_LOGW(LOGD_DEVICE,
"private connections with multiple users are not allowed to reference "
"certificates and keys on the filesystem. Specify only one user in the "
"connection.permissions property.");
nm_device_state_changed(self,
NM_DEVICE_STATE_FAILED,
NM_DEVICE_STATE_REASON_CONFIG_FAILED);
return;
}
priv->private_files.state = PRIVATE_FILES_STATE_READING;
priv->private_files.cancellable = g_cancellable_new();
_LOGD(LOGD_DEVICE, "reading private files");
nm_utils_read_private_files(paths,
priv->private_files.user,
priv->private_files.cancellable,
read_private_files_cb,
self);
return;
}
case PRIVATE_FILES_STATE_READING:
/* wait */
return;
case PRIVATE_FILES_STATE_DONE:
/* proceed */
break;
}
if (!nm_device_managed_type_is_external(self)) {
_ethtool_state_set(self);
nm_device_link_properties_set(self, FALSE);
@ -10838,7 +11015,7 @@ activate_stage2_device_config(NMDevice *self)
priv->tc_committed = TRUE;
}
nm_routing_rules_sync(nm_device_get_applied_connection(self),
nm_routing_rules_sync(applied,
NM_TERNARY_TRUE,
klass->get_extra_rules,
self,
@ -12850,7 +13027,7 @@ _dev_ipac6_start(NMDevice *self)
.router_solicitations = router_solicitations,
.router_solicitation_interval = router_solicitation_interval,
.ra_timeout = ra_timeout,
.ip6_privacy = _prop_get_ipv6_ip6_privacy(self),
.ip6_privacy = _prop_get_ipv6_ip6_privacy(self, connection),
};
priv->ipac6_data.ndisc = nm_lndp_ndisc_new(&config);
@ -13163,17 +13340,12 @@ activate_stage3_ip_config_for_addr_family(NMDevice *self, int addr_family)
goto out_devip;
if (IS_IPv4) {
NMSettingIPConfigForwarding ipv4_forwarding = nm_device_get_ipv4_forwarding(self);
if (NM_IN_SET(ipv4_forwarding,
NM_SETTING_IP_CONFIG_FORWARDING_NO,
NM_SETTING_IP_CONFIG_FORWARDING_YES)) {
nm_device_sysctl_ip_conf_set(self, AF_INET, "forwarding", ipv4_forwarding ? "1" : "0");
}
priv->ipll_data_4.v4.mode = _prop_get_ipv4_link_local(self);
if (priv->ipll_data_4.v4.mode == NM_SETTING_IP4_LL_ENABLED)
_dev_ipll4_start(self);
_dev_ipforwarding4_start(self, addr_family);
if (nm_streq(priv->ipv4_method, NM_SETTING_IP4_CONFIG_METHOD_AUTO))
_dev_ipdhcpx_start(self, AF_INET);
else if (nm_streq(priv->ipv4_method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL)) {
@ -13493,15 +13665,21 @@ nm_device_activate_schedule_stage3_ip_config(NMDevice *self, gboolean do_sync)
static void
_dev_ipsharedx_set_state(NMDevice *self, int addr_family, NMDeviceIPState state)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
const int IS_IPv4 = NM_IS_IPv4(addr_family);
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
const int IS_IPv4 = NM_IS_IPv4(addr_family);
NMDeviceIPState old_state = priv->ipshared_data_x[IS_IPv4].state;
if (priv->ipshared_data_x[IS_IPv4].state != state) {
if (old_state != state) {
_LOGD_ipshared(addr_family,
"set state %s (was %s)",
nm_device_ip_state_to_string(state),
nm_device_ip_state_to_string(priv->ipshared_data_x[IS_IPv4].state));
nm_device_ip_state_to_string(old_state));
priv->ipshared_data_x[IS_IPv4].state = state;
if (old_state == NM_DEVICE_IP_STATE_READY || state == NM_DEVICE_IP_STATE_READY)
nm_manager_update_shared_connection(NM_MANAGER_GET,
addr_family,
state == NM_DEVICE_IP_STATE_READY);
}
}
@ -13797,6 +13975,106 @@ _dev_ipshared6_start(NMDevice *self)
/*****************************************************************************/
/**
* Set the device's forwarding to the specified value. If %NM_TERNARY_DEFAULT is specified,
* it's set to the kernel's default, otherwise it's set to the specific value.
*/
static void
_dev_ipforwarding4_set(NMDevice *self, NMTernary val)
{
gs_free const char *default_forwarding = NULL;
gs_free const char *current_forwarding = NULL;
const char *val_str;
if (val != NM_TERNARY_DEFAULT) {
val_str = val ? "1" : "0";
} else {
default_forwarding = nm_platform_sysctl_get(
nm_device_get_platform(self),
NMP_SYSCTL_PATHID_ABSOLUTE("/proc/sys/net/ipv4/conf/default/forwarding"));
if (!default_forwarding) {
_LOGW(LOGD_DEVICE,
"error setting IPv4 forwarding: can't read default forwarding value: %s",
nm_strerror_native(errno));
return; /* Non fatal */
}
val_str = default_forwarding;
}
current_forwarding = nm_device_sysctl_ip_conf_get(self, AF_INET, "forwarding");
if (nm_streq0(current_forwarding, val_str))
return;
if (!nm_device_sysctl_ip_conf_set(self, AF_INET, "forwarding", val_str))
_LOGW(LOGD_DEVICE,
"error setting IPv4 forwarding to '%s': %s",
val_str,
nm_strerror_native(errno));
}
static void
_dev_ipforwarding4_auto_cb(NMManager *manager, gboolean sharing_ipv4, gpointer data)
{
NMDevice *self = NM_DEVICE(data);
_dev_ipforwarding4_set(self, sharing_ipv4 ? NM_TERNARY_TRUE : NM_TERNARY_DEFAULT);
}
static void
_dev_ipforwarding4_start(NMDevice *self, int addr_family)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
NMSettingIPConfigForwarding ipv4_forwarding = _prop_get_ipv4_forwarding(self);
NMTernary new_forwarding = NM_TERNARY_DEFAULT;
/* IPv6 per-interface forwarding not supported yet */
if (addr_family != AF_INET)
return;
if (nm_streq(priv->ipv4_method, NM_SETTING_IP4_CONFIG_METHOD_SHARED)) {
new_forwarding = NM_TERNARY_TRUE;
} else if (ipv4_forwarding == NM_SETTING_IP_CONFIG_FORWARDING_YES) {
new_forwarding = NM_TERNARY_TRUE;
} else if (ipv4_forwarding == NM_SETTING_IP_CONFIG_FORWARDING_NO) {
new_forwarding = NM_TERNARY_FALSE;
} else if (ipv4_forwarding == NM_SETTING_IP_CONFIG_FORWARDING_AUTO) {
if (nm_manager_get_sharing_ipv4(NM_MANAGER_GET))
new_forwarding = NM_TERNARY_TRUE;
else
new_forwarding = NM_TERNARY_DEFAULT;
if (!priv->sharing_ipv4_changed_id)
priv->sharing_ipv4_changed_id = g_signal_connect(NM_MANAGER_GET,
NM_MANAGER_SHARING_IPV4_CHANGED,
G_CALLBACK(_dev_ipforwarding4_auto_cb),
self);
} else {
nm_assert_not_reached();
}
_dev_ipforwarding4_set(self, new_forwarding);
}
static void
_dev_ipforwarding_cleanup(NMDevice *self, int addr_family, CleanupType cleanup_type)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
if (!NM_IS_IPv4(addr_family))
return;
nm_clear_g_signal_handler(NM_MANAGER_GET, &priv->sharing_ipv4_changed_id);
if (NM_IN_SET(cleanup_type, CLEANUP_TYPE_DECONFIGURE, CLEANUP_TYPE_KEEP_REAPPLY)) {
/* Deconfigure by restoring kernel's default */
_dev_ipforwarding4_set(self, NM_TERNARY_DEFAULT);
}
}
/*****************************************************************************/
static void
act_request_set(NMDevice *self, NMActRequest *act_request)
{
@ -13909,6 +14187,8 @@ _cleanup_ip_pre(NMDevice *self, int addr_family, CleanupType cleanup_type, gbool
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
gboolean keep_reapply = (cleanup_type == CLEANUP_TYPE_KEEP_REAPPLY);
_dev_ipforwarding_cleanup(self, addr_family, cleanup_type);
_dev_ipsharedx_cleanup(self, addr_family);
_dev_ipdev_cleanup(self, AF_UNSPEC);
@ -14056,6 +14336,7 @@ can_reapply_change(NMDevice *self,
NM_SETTING_CONNECTION_MDNS,
NM_SETTING_CONNECTION_LLMNR,
NM_SETTING_CONNECTION_DNS_OVER_TLS,
NM_SETTING_CONNECTION_DNSSEC,
NM_SETTING_CONNECTION_MPTCP_FLAGS,
NM_SETTING_CONNECTION_WAIT_ACTIVATION_DELAY);
}
@ -14314,6 +14595,7 @@ check_and_reapply_connection(NMDevice *self,
NM_SETTING_CONNECTION_MDNS,
NM_SETTING_CONNECTION_LLMNR,
NM_SETTING_CONNECTION_DNS_OVER_TLS,
NM_SETTING_CONNECTION_DNSSEC,
NM_SETTING_CONNECTION_MPTCP_FLAGS)) {
priv->ip_data_4.do_reapply = TRUE;
priv->ip_data_6.do_reapply = TRUE;
@ -15665,7 +15947,7 @@ nm_device_get_firmware_missing(NMDevice *self)
NM_UTILS_FLAGS2STR_DEFINE(nm_unmanaged_flags2str,
NMUnmanagedFlags,
NM_UTILS_FLAGS2STR(NM_UNMANAGED_SLEEPING, "sleeping"),
NM_UTILS_FLAGS2STR(NM_UNMANAGED_MANAGER_DISABLED, "nm-disabled"),
NM_UTILS_FLAGS2STR(NM_UNMANAGED_QUITTING, "quitting"),
NM_UTILS_FLAGS2STR(NM_UNMANAGED_PLATFORM_INIT, "platform-init"),
NM_UTILS_FLAGS2STR(NM_UNMANAGED_USER_EXPLICIT, "user-explicit"),
@ -15729,8 +16011,8 @@ unmanaged_flags_to_reason(NMUnmanagedFlags flags)
/* Even if there are multiple flags, we can only return one reason.
* Return the most important reason.
*/
if (NM_FLAGS_HAS(flags, NM_UNMANAGED_SLEEPING))
return NM_DEVICE_STATE_REASON_UNMANAGED_SLEEPING;
if (NM_FLAGS_HAS(flags, NM_UNMANAGED_MANAGER_DISABLED))
return NM_DEVICE_STATE_REASON_UNMANAGED_MANAGER_DISABLED;
if (NM_FLAGS_HAS(flags, NM_UNMANAGED_QUITTING))
return NM_DEVICE_STATE_REASON_UNMANAGED_QUITTING;
if (NM_FLAGS_HAS(flags, NM_UNMANAGED_USER_SETTINGS))
@ -16975,8 +17257,6 @@ _cleanup_generic_post(NMDevice *self, NMDeviceStateReason reason, CleanupType cl
priv->v4_route_table_all_sync_before = FALSE;
priv->v6_route_table_all_sync_before = FALSE;
priv->refresh_forwarding_done = FALSE;
priv->mtu_force_set_done = FALSE;
priv->needs_ip6_subnet = FALSE;
@ -17022,7 +17302,6 @@ nm_device_cleanup(NMDevice *self, NMDeviceStateReason reason, CleanupType cleanu
NMDevicePrivate *priv;
NMDeviceClass *klass = NM_DEVICE_GET_CLASS(self);
int ifindex;
gint32 default_forwarding_v4;
g_return_if_fail(NM_IS_DEVICE(self));
@ -17045,21 +17324,16 @@ nm_device_cleanup(NMDevice *self, NMDeviceStateReason reason, CleanupType cleanu
nm_device_sysctl_ip_conf_set(self, AF_INET6, "use_tempaddr", "0");
}
/* Restoring the device's forwarding to the sysctl default is necessary because
* `refresh_forwarding()` only updates forwarding on activated devices. */
default_forwarding_v4 = nm_platform_sysctl_get_int32(
nm_device_get_platform(self),
NMP_SYSCTL_PATHID_ABSOLUTE("/proc/sys/net/ipv4/conf/default/forwarding"),
0);
nm_device_sysctl_ip_conf_set(self,
AF_INET,
"forwarding",
default_forwarding_v4 == 1 ? "1" : "0");
/* Call device type-specific deactivation */
if (klass->deactivate)
klass->deactivate(self);
/* Clean up private files */
nm_clear_g_cancellable(&priv->private_files.cancellable);
g_clear_pointer(&priv->private_files.table, g_hash_table_unref);
g_clear_pointer(&priv->private_files.user, g_free);
priv->private_files.state = PRIVATE_FILES_STATE_UNKNOWN;
ifindex = nm_device_get_ip_ifindex(self);
if (cleanup_type == CLEANUP_TYPE_DECONFIGURE) {
@ -19009,19 +19283,6 @@ nm_device_get_hostname_from_dns_lookup(NMDevice *self, int addr_family, gboolean
return nm_assert_unreachable_val(NULL);
}
gboolean
nm_device_get_refresh_forwarding_done(NMDevice *self)
{
return NM_DEVICE_GET_PRIVATE(self)->refresh_forwarding_done;
}
void
nm_device_set_refresh_forwarding_done(NMDevice *self, gboolean is_refresh_forwarding_done)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
priv->refresh_forwarding_done = is_refresh_forwarding_done;
}
/*****************************************************************************/
static const char *

View file

@ -581,7 +581,8 @@ void nm_device_copy_ip6_dns_config(NMDevice *self, NMDevice *from_device);
/**
* NMUnmanagedFlags:
* @NM_UNMANAGED_NONE: placeholder value
* @NM_UNMANAGED_SLEEPING: %TRUE when unmanaged because NM is sleeping.
* @NM_UNMANAGED_MANAGER_DISABLED: %TRUE when unmanaged because NM is disabled.
* Currently, this happens when sleeping or with networking disabled.
* @NM_UNMANAGED_QUITTING: %TRUE when unmanaged because NM is shutting down.
* @NM_UNMANAGED_PLATFORM_INIT: %TRUE when unmanaged because platform link not
* yet initialized. Unrealized device are also unmanaged for this reason.
@ -610,11 +611,11 @@ typedef enum {
/* these flags are authoritative. If one of them is set,
* the device cannot be managed. */
NM_UNMANAGED_SLEEPING = (1LL << 0),
NM_UNMANAGED_QUITTING = (1LL << 1),
NM_UNMANAGED_PLATFORM_INIT = (1LL << 2),
NM_UNMANAGED_USER_EXPLICIT = (1LL << 3),
NM_UNMANAGED_USER_SETTINGS = (1LL << 4),
NM_UNMANAGED_MANAGER_DISABLED = (1LL << 0),
NM_UNMANAGED_QUITTING = (1LL << 1),
NM_UNMANAGED_PLATFORM_INIT = (1LL << 2),
NM_UNMANAGED_USER_EXPLICIT = (1LL << 3),
NM_UNMANAGED_USER_SETTINGS = (1LL << 4),
/* These flags can be non-effective and be overwritten
* by other flags. */
@ -852,14 +853,7 @@ void nm_routing_rules_sync(NMConnection *applied_connection,
NMDevice *self,
NMNetns *netns);
NMSettingIPConfigForwarding nm_device_get_ipv4_forwarding(NMDevice *self);
const char *nm_device_get_effective_ip_config_method(NMDevice *self, int addr_family);
char *nm_device_sysctl_ip_conf_get(NMDevice *self, int addr_family, const char *property);
gboolean nm_device_get_refresh_forwarding_done(NMDevice *self);
void nm_device_set_refresh_forwarding_done(NMDevice *self, gboolean is_refresh_forwarding_done);
NML3ConfigData *nm_device_create_l3_config_data_from_connection(NMDevice *self,
NMConnection *connection);
#endif /* __NETWORKMANAGER_DEVICE_H__ */

View file

@ -1460,40 +1460,42 @@ _delete_interface(NMOvsdb *self, json_t *params, const char *ifname)
json_array_append_new(new_interfaces, json_pack("[s,s]", "uuid", interface_uuid));
}
if (num_nm_interfaces == 0) {
/* The port no longer has any NM interface. Don't add it to "new_ports" and set
* ports_changed=TRUE, so that it will be deleted. */
if (interfaces_changed && num_nm_interfaces == 0) {
/* We are deleting the last nm-interface of this port. Don't add it to "new_ports"
* and set ports_changed=TRUE, so that it will be deleted. */
ports_changed = TRUE;
} else {
if (interfaces_changed) {
/* An interface needs to be deleted from this port */
_expect_port_interfaces(params, ovs_port->name, interfaces);
_set_port_interfaces(params, ovs_port->name, new_interfaces);
}
/* The port is still alive */
/* Keep this port: it's still alive, or it's unrelated to the deleted interface */
json_array_append_new(new_ports, json_pack("[s,s]", "uuid", port_uuid));
if (ovs_port->connection_uuid)
num_nm_ports++;
if (interfaces_changed) {
/* This port is still alive, but an interface needs to be deleted from it */
_expect_port_interfaces(params, ovs_port->name, interfaces);
_set_port_interfaces(params, ovs_port->name, new_interfaces);
}
}
}
if (num_nm_ports == 0) {
/* The bridge no longer has any NM port. Don't add it to "new_bridges" and set
* bridges_changed=TRUE, so that it will be deleted. */
if (ports_changed && num_nm_ports == 0) {
/* We are deleting the last nm-port of this bridge. Don't add it to "new_bridges"
* and set bridges_changed=TRUE, so that it will be deleted. */
bridges_changed = TRUE;
} else {
/* Keep this bridge: it's still alive, or it's unrelated to the deleted interface */
json_array_append_new(new_bridges, json_pack("[s,s]", "uuid", ovs_bridge->bridge_uuid));
if (ports_changed) {
/* A port needs to be deleted from this bridge */
/* This bridge is still alive, but a port needs to be deleted from it */
_expect_bridge_ports(params, ovs_bridge->name, ports);
_set_bridge_ports(params, ovs_bridge->name, new_ports);
}
/* The bridge is still alive */
json_array_append_new(new_bridges, json_pack("[s,s]", "uuid", ovs_bridge->bridge_uuid));
}
}
if (bridges_changed) {
/* A port needs to be deleted from this bridge */
/* A bridge needs to be deleted */
_expect_ovs_bridges(params, priv->db_uuid, bridges);
_set_ovs_bridges(params, priv->db_uuid, new_bridges);
}
@ -1888,7 +1890,7 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg)
== -1) {
/* This doesn't really have to be an error; the key might
* be missing if there really are no bridges present. */
_LOGD("Bad update: %s", json_error.text);
_LOGD("monitor: bad update: %s", json_error.text);
}
if (ovs) {
@ -1934,12 +1936,12 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg)
&unused))
continue;
_LOGT("obj[iface:%s]: removed an '%s' interface: %s%s%s",
key,
ovs_interface->type,
_LOGT("monitor: %s: interface removed: type=%s, obj[iface:%s]%s%s",
ovs_interface->name,
ovs_interface->type,
key,
NM_PRINT_FMT_QUOTED2(ovs_interface->connection_uuid,
", ",
", connection=",
ovs_interface->connection_uuid,
""));
_signal_emit_device_removed(self,
@ -1987,17 +1989,18 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg)
gs_free char *strtmp1 = NULL;
gs_free char *strtmp2 = NULL;
_LOGT("obj[iface:%s]: changed an '%s' interface: %s%s%s, external-ids=%s, "
"other-config=%s",
key,
type,
ovs_interface->name,
NM_PRINT_FMT_QUOTED2(ovs_interface->connection_uuid,
", ",
ovs_interface->connection_uuid,
""),
(strtmp1 = _strdict_to_string(ovs_interface->external_ids)),
(strtmp2 = _strdict_to_string(ovs_interface->other_config)));
_LOGT(
"monitor: %s: interface changed: type=%s, obj[iface:%s]%s%s, external-ids=%s, "
"other-config=%s",
ovs_interface->name,
type,
key,
NM_PRINT_FMT_QUOTED2(ovs_interface->connection_uuid,
", connection=",
ovs_interface->connection_uuid,
""),
(strtmp1 = _strdict_to_string(ovs_interface->external_ids)),
(strtmp2 = _strdict_to_string(ovs_interface->other_config)));
}
} else {
gs_free char *strtmp1 = NULL;
@ -2013,17 +2016,17 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg)
.other_config = g_steal_pointer(&other_config_arr),
};
g_hash_table_add(priv->interfaces, ovs_interface);
_LOGT(
"obj[iface:%s]: added an '%s' interface: %s%s%s, external-ids=%s, other-config=%s",
key,
ovs_interface->type,
ovs_interface->name,
NM_PRINT_FMT_QUOTED2(ovs_interface->connection_uuid,
", ",
ovs_interface->connection_uuid,
""),
(strtmp1 = _strdict_to_string(ovs_interface->external_ids)),
(strtmp2 = _strdict_to_string(ovs_interface->other_config)));
_LOGT("monitor: %s: interface added: type=%s, obj[iface:%s]%s%s, external-ids=%s, "
"other-config=%s",
ovs_interface->name,
ovs_interface->type,
key,
NM_PRINT_FMT_QUOTED2(ovs_interface->connection_uuid,
", connection=",
ovs_interface->connection_uuid,
""),
(strtmp1 = _strdict_to_string(ovs_interface->external_ids)),
(strtmp2 = _strdict_to_string(ovs_interface->other_config)));
_signal_emit_device_added(self,
ovs_interface->name,
NM_DEVICE_TYPE_OVS_INTERFACE,
@ -2069,11 +2072,11 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg)
if (!g_hash_table_steal_extended(priv->ports, &key, (gpointer *) &ovs_port, &unused))
continue;
_LOGT("obj[port:%s]: removed a port: %s%s%s",
key,
_LOGT("monitor: %s: port removed: obj[port:%s]%s%s",
ovs_port->name,
key,
NM_PRINT_FMT_QUOTED2(ovs_port->connection_uuid,
", ",
", connection=",
ovs_port->connection_uuid,
""));
_signal_emit_device_removed(self, ovs_port->name, NM_DEVICE_TYPE_OVS_PORT, NULL);
@ -2120,15 +2123,16 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg)
gs_free char *strtmp1 = NULL;
gs_free char *strtmp2 = NULL;
_LOGT("obj[port:%s]: changed a port: %s%s%s, external-ids=%s, other-config=%s",
key,
ovs_port->name,
NM_PRINT_FMT_QUOTED2(ovs_port->connection_uuid,
", ",
ovs_port->connection_uuid,
""),
(strtmp1 = _strdict_to_string(ovs_port->external_ids)),
(strtmp2 = _strdict_to_string(ovs_port->other_config)));
_LOGT(
"monitor: %s: port changed: obj[port:%s]%s%s, external-ids=%s, other-config=%s",
ovs_port->name,
key,
NM_PRINT_FMT_QUOTED2(ovs_port->connection_uuid,
", connection=",
ovs_port->connection_uuid,
""),
(strtmp1 = _strdict_to_string(ovs_port->external_ids)),
(strtmp2 = _strdict_to_string(ovs_port->other_config)));
}
} else {
gs_free char *strtmp1 = NULL;
@ -2144,11 +2148,11 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg)
.other_config = g_steal_pointer(&other_config_arr),
};
g_hash_table_add(priv->ports, ovs_port);
_LOGT("obj[port:%s]: added a port: %s%s%s, external-ids=%s, other-config=%s",
key,
_LOGT("monitor: %s: port added: obj[port:%s]%s%s, external-ids=%s, other-config=%s",
ovs_port->name,
key,
NM_PRINT_FMT_QUOTED2(ovs_port->connection_uuid,
", ",
", connection=",
ovs_port->connection_uuid,
""),
(strtmp1 = _strdict_to_string(ovs_port->external_ids)),
@ -2190,11 +2194,11 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg)
&unused))
continue;
_LOGT("obj[bridge:%s]: removed a bridge: %s%s%s",
key,
_LOGT("monitor: %s: bridge removed: obj[bridge:%s]%s%s",
ovs_bridge->name,
key,
NM_PRINT_FMT_QUOTED2(ovs_bridge->connection_uuid,
", ",
", connection=",
ovs_bridge->connection_uuid,
""));
_signal_emit_device_removed(self, ovs_bridge->name, NM_DEVICE_TYPE_OVS_BRIDGE, NULL);
@ -2241,11 +2245,12 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg)
gs_free char *strtmp1 = NULL;
gs_free char *strtmp2 = NULL;
_LOGT("obj[bridge:%s]: changed a bridge: %s%s%s, external-ids=%s, other-config=%s",
key,
_LOGT("monitor: %s: bridge changed: obj[bridge:%s]%s%s, external-ids=%s, "
"other-config=%s",
ovs_bridge->name,
key,
NM_PRINT_FMT_QUOTED2(ovs_bridge->connection_uuid,
", ",
", connection=",
ovs_bridge->connection_uuid,
""),
(strtmp1 = _strdict_to_string(ovs_bridge->external_ids)),
@ -2265,11 +2270,11 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg)
.other_config = g_steal_pointer(&other_config_arr),
};
g_hash_table_add(priv->bridges, ovs_bridge);
_LOGT("obj[bridge:%s]: added a bridge: %s%s%s, external-ids=%s, other-config=%s",
key,
_LOGT("monitor: %s: bridge added: obj[bridge:%s]%s%s, external-ids=%s, other-config=%s",
ovs_bridge->name,
key,
NM_PRINT_FMT_QUOTED2(ovs_bridge->connection_uuid,
", ",
", connection=",
ovs_bridge->connection_uuid,
""),
(strtmp1 = _strdict_to_string(ovs_bridge->external_ids)),

View file

@ -191,6 +191,12 @@ static void supplicant_iface_notify_p2p_available(NMSupplicantInterface *iface,
GParamSpec *pspec,
NMDeviceWifi *self);
static void supplicant_iface_notify_wpa_psk_mismatch_cb(NMSupplicantInterface *iface,
NMDeviceWifi *self);
static void supplicant_iface_notify_wpa_sae_mismatch_cb(NMSupplicantInterface *iface,
NMDeviceWifi *self);
static void periodic_update(NMDeviceWifi *self);
static void ap_add_remove(NMDeviceWifi *self,
@ -624,6 +630,14 @@ supplicant_interface_acquire_cb(NMSupplicantManager *supplicant_manager,
"notify::" NM_SUPPLICANT_INTERFACE_P2P_AVAILABLE,
G_CALLBACK(supplicant_iface_notify_p2p_available),
self);
g_signal_connect(priv->sup_iface,
NM_SUPPLICANT_INTERFACE_PSK_MISMATCH,
G_CALLBACK(supplicant_iface_notify_wpa_psk_mismatch_cb),
self);
g_signal_connect(priv->sup_iface,
NM_SUPPLICANT_INTERFACE_SAE_MISMATCH,
G_CALLBACK(supplicant_iface_notify_wpa_sae_mismatch_cb),
self);
_scan_notify_is_scanning(self);
@ -2398,6 +2412,9 @@ handle_8021x_or_psk_auth_fail(NMDeviceWifi *self,
g_return_val_if_fail(new_state == NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED, FALSE);
if (nm_device_get_state(device) != NM_DEVICE_STATE_CONFIG)
return FALSE;
req = nm_device_get_act_request(NM_DEVICE(self));
g_return_val_if_fail(req != NULL, FALSE);
@ -2841,6 +2858,62 @@ handle_auth_or_fail(NMDeviceWifi *self, NMActRequest *req, gboolean new_secrets)
return TRUE;
}
static void
supplicant_iface_notify_wpa_psk_mismatch_cb(NMSupplicantInterface *iface, NMDeviceWifi *self)
{
NMDevice *device = NM_DEVICE(self);
NMActRequest *req;
const char *setting_name = NM_SETTING_WIRELESS_SECURITY_SETTING_NAME;
if (nm_device_get_state(device) != NM_DEVICE_STATE_CONFIG)
return;
_LOGI(LOGD_DEVICE | LOGD_WIFI,
"Activation: (wifi) psk mismatch reported by supplicant, asking for new key");
req = nm_device_get_act_request(NM_DEVICE(self));
g_return_if_fail(req != NULL);
nm_act_request_clear_secrets(req);
cleanup_association_attempt(self, TRUE);
nm_device_state_changed(device,
NM_DEVICE_STATE_NEED_AUTH,
NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT);
wifi_secrets_get_secrets(self,
setting_name,
NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION
| NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW);
}
static void
supplicant_iface_notify_wpa_sae_mismatch_cb(NMSupplicantInterface *iface, NMDeviceWifi *self)
{
NMDevice *device = NM_DEVICE(self);
NMActRequest *req;
const char *setting_name = NM_SETTING_WIRELESS_SECURITY_SETTING_NAME;
if (nm_device_get_state(device) != NM_DEVICE_STATE_CONFIG)
return;
_LOGI(LOGD_DEVICE | LOGD_WIFI,
"Activation: (wifi) SAE password mismatch reported by supplicant, asking for new key");
req = nm_device_get_act_request(NM_DEVICE(self));
g_return_if_fail(req != NULL);
nm_act_request_clear_secrets(req);
cleanup_association_attempt(self, TRUE);
nm_device_state_changed(device,
NM_DEVICE_STATE_NEED_AUTH,
NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT);
wifi_secrets_get_secrets(self,
setting_name,
NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION
| NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW);
}
/*
* supplicant_connection_timeout_cb
*
@ -2946,7 +3019,8 @@ build_supplicant_config(NMDeviceWifi *self,
s_wireless = nm_connection_get_setting_wireless(connection);
g_return_val_if_fail(s_wireless != NULL, NULL);
config = nm_supplicant_config_new(nm_supplicant_interface_get_capabilities(priv->sup_iface));
config = nm_supplicant_config_new(nm_supplicant_interface_get_capabilities(priv->sup_iface),
nm_utils_get_connection_first_permissions_user(connection));
/* Warn if AP mode may not be supported */
if (nm_streq0(nm_setting_wireless_get_mode(s_wireless), NM_SETTING_WIRELESS_MODE_AP)
@ -3022,6 +3096,7 @@ build_supplicant_config(NMDeviceWifi *self,
mtu,
pmf,
fils,
nm_device_get_private_files(NM_DEVICE(self)),
error)) {
g_prefix_error(error, "802-11-wireless-security: ");
goto error;

View file

@ -684,7 +684,7 @@ iwd_config_write(GKeyFile *config,
* in the last few filename characters -- it cannot end in .open, .psk
* or .8021x.
*/
return nm_utils_file_set_contents(filepath, data, length, 0600, times, NULL, error);
return nm_utils_file_set_contents(filepath, data, length, 0600, times, NULL, NULL, error);
}
static const char *

View file

@ -508,8 +508,9 @@ find_gsm_apn_cb(const char *apn,
static gboolean
try_create_connect_properties(NMModemBroadband *self)
{
NMModemBroadbandPrivate *priv = NM_MODEM_BROADBAND_GET_PRIVATE(self);
ConnectContext *ctx = priv->ctx;
NMModemBroadbandPrivate *priv = NM_MODEM_BROADBAND_GET_PRIVATE(self);
ConnectContext *ctx = priv->ctx;
NMDeviceStateReason fail_reason = NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED;
if (MODEM_CAPS_3GPP(ctx->caps)) {
NMSettingGsm *s_gsm = nm_connection_get_setting_gsm(ctx->connection);
@ -522,7 +523,7 @@ try_create_connect_properties(NMModemBroadband *self)
if (s_gsm)
network_id = nm_setting_gsm_get_network_id(s_gsm);
if (!network_id) {
if (mm_modem_get_state(self->_priv.modem_iface) < MM_MODEM_STATE_REGISTERED)
if (mm_modem_get_state(self->_priv.modem_iface) != MM_MODEM_STATE_REGISTERED)
return FALSE;
modem_3gpp = mm_object_get_modem_3gpp(priv->modem_object);
network_id = mm_modem_3gpp_get_operator_code(modem_3gpp);
@ -530,6 +531,7 @@ try_create_connect_properties(NMModemBroadband *self)
if (!network_id) {
_LOGW("failed to connect '%s': unable to determine the network id",
nm_connection_get_id(ctx->connection));
fail_reason = NM_DEVICE_STATE_REASON_MODEM_NO_OPERATOR_CODE;
goto out;
}
@ -558,7 +560,7 @@ try_create_connect_properties(NMModemBroadband *self)
}
out:
nm_modem_emit_prepare_result(NM_MODEM(self), FALSE, NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED);
nm_modem_emit_prepare_result(NM_MODEM(self), FALSE, fail_reason);
connect_context_clear(self);
return TRUE;
}
@ -1649,6 +1651,8 @@ nm_modem_broadband_new(GObject *object, GError **error)
driver,
NM_MODEM_OPERATOR_CODE,
operator_code,
NM_MODEM_DEVICE_UID,
mm_modem_get_device(modem_iface),
NULL);
}

View file

@ -39,7 +39,8 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMModem,
PROP_IP_TYPES,
PROP_SIM_OPERATOR_ID,
PROP_OPERATOR_CODE,
PROP_APN, );
PROP_APN,
PROP_DEVICE_UID, );
enum {
PPP_STATS,
@ -78,6 +79,7 @@ typedef struct _NMModemPrivate {
char *sim_operator_id;
char *operator_code;
char *apn;
char *device_uid;
NMPPPManager *ppp_manager;
NMPppMgr *ppp_mgr;
@ -618,6 +620,12 @@ nm_modem_get_apn(NMModem *self)
return NM_MODEM_GET_PRIVATE(self)->apn;
}
const char *
nm_modem_get_device_uid(NMModem *self)
{
return NM_MODEM_GET_PRIVATE(self)->device_uid;
}
/*****************************************************************************/
static void
@ -1121,6 +1129,22 @@ nm_modem_check_connection_compatible(NMModem *self, NMConnection *connection, GE
}
}
str = nm_setting_gsm_get_device_uid(s_gsm);
if (str) {
if (!priv->device_uid) {
nm_utils_error_set_literal(error,
NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
"GSM profile has device-uid, device does not");
return FALSE;
}
if (!nm_streq(str, priv->device_uid)) {
nm_utils_error_set_literal(error,
NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
"device has differing device-uid than GSM profile");
return FALSE;
}
}
/* SIM properties may not be available before the SIM is unlocked, so
* to ensure that autoconnect works, the connection's SIM properties
* are only compared if present on the device.
@ -1644,6 +1668,9 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
case PROP_APN:
g_value_set_string(value, priv->apn);
break;
case PROP_DEVICE_UID:
g_value_set_string(value, priv->device_uid);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
@ -1699,6 +1726,10 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps
/* construct-only */
priv->operator_code = g_value_dup_string(value);
break;
case PROP_DEVICE_UID:
/* construct-only */
priv->device_uid = g_value_dup_string(value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
@ -1758,6 +1789,7 @@ finalize(GObject *object)
g_free(priv->sim_operator_id);
g_free(priv->operator_code);
g_free(priv->apn);
g_free(priv->device_uid);
G_OBJECT_CLASS(nm_modem_parent_class)->finalize(object);
}
@ -1863,6 +1895,13 @@ nm_modem_class_init(NMModemClass *klass)
obj_properties[PROP_APN] =
g_param_spec_string(NM_MODEM_APN, "", "", NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
obj_properties[PROP_DEVICE_UID] =
g_param_spec_string(NM_MODEM_DEVICE_UID,
"",
"",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties);
signals[PPP_STATS] = g_signal_new(NM_MODEM_PPP_STATS,

View file

@ -30,6 +30,7 @@
#define NM_MODEM_SIM_OPERATOR_ID "sim-operator-id"
#define NM_MODEM_OPERATOR_CODE "operator-code"
#define NM_MODEM_APN "apn"
#define NM_MODEM_DEVICE_UID "device-uid"
/* Signals */
#define NM_MODEM_PPP_STATS "ppp-stats"
@ -154,6 +155,7 @@ const char *nm_modem_get_sim_id(NMModem *modem);
const char *nm_modem_get_sim_operator_id(NMModem *modem);
const char *nm_modem_get_operator_code(NMModem *modem);
const char *nm_modem_get_apn(NMModem *modem);
const char *nm_modem_get_device_uid(NMModem *modem);
gboolean nm_modem_set_data_port(NMModem *self,
NMPlatform *platform,

View file

@ -32,11 +32,11 @@ ip4_process_dhcpcd_rfc3442_routes(const char *iface,
in_addr_t address,
guint32 *out_gwaddr)
{
gs_free const char **routes = NULL;
const char **r;
gboolean have_routes = FALSE;
gs_free char **routes = NULL;
char **r;
gboolean have_routes = FALSE;
routes = nm_strsplit_set(str, " ");
routes = (char **) nm_strsplit_set(str, " ");
if (!routes)
return FALSE;

View file

@ -521,9 +521,10 @@ _gl_pid_spawn_next_step(void)
argv[argv_idx++] = "--no-resolv"; /* Use only commandline */
argv[argv_idx++] = "--keep-in-foreground";
argv[argv_idx++] = "--no-hosts"; /* don't use /etc/hosts to resolve */
argv[argv_idx++] = "--bind-interfaces";
argv[argv_idx++] = "--bind-dynamic";
argv[argv_idx++] = "--pid-file=" PIDFILE;
argv[argv_idx++] = "--listen-address=127.0.0.1"; /* Should work for both 4 and 6 */
argv[argv_idx++] = "--listen-address=127.0.0.1";
argv[argv_idx++] = "--listen-address=::1";
argv[argv_idx++] = "--cache-size=400";
argv[argv_idx++] = "--clear-on-reload"; /* clear cache when dns server changes */
argv[argv_idx++] = "--conf-file=/dev/null"; /* avoid loading /etc/dnsmasq.conf */

View file

@ -26,6 +26,7 @@
#include "libnm-core-intern/nm-core-internal.h"
#include "libnm-glib-aux/nm-str-buf.h"
#include "libnm-glib-aux/nm-io-utils.h"
#include "NetworkManagerUtils.h"
#include "devices/nm-device.h"
@ -1006,7 +1007,8 @@ _read_link_cached(const char *path, gboolean *is_cached, char **cached)
#define MY_RESOLV_CONF_TMP MY_RESOLV_CONF ".tmp"
#define RESOLV_CONF_TMP "/etc/.resolv.conf.NetworkManager"
#define NO_STUB_RESOLV_CONF NMRUNDIR "/no-stub-resolv.conf"
#define NO_STUB_RESOLV_CONF NMRUNDIR "/no-stub-resolv.conf"
#define NO_STUB_RESOLV_CONF_TMP NMRUNDIR "/no-stub-resolv.conf.tmp"
static void
update_resolv_conf_no_stub(NMDnsManager *self,
@ -1019,7 +1021,14 @@ update_resolv_conf_no_stub(NMDnsManager *self,
content = create_resolv_conf(searches, nameservers, options);
if (!g_file_set_contents(NO_STUB_RESOLV_CONF, content, -1, &local)) {
if (!nm_utils_file_set_contents(NO_STUB_RESOLV_CONF,
content,
-1,
0644,
NULL,
NO_STUB_RESOLV_CONF_TMP,
NULL,
&local)) {
_LOGD("update-resolv-no-stub: failure to write file: %s", local->message);
g_error_free(local);
return;
@ -1501,8 +1510,8 @@ _domain_track_is_shadowed(GHashTable *ht,
const char **out_parent,
int *out_parent_priority)
{
char *parent;
int parent_priority;
const char *parent;
int parent_priority;
if (!ht)
return FALSE;

View file

@ -37,6 +37,7 @@
static const char *const DBUS_OP_SET_LINK_DEFAULT_ROUTE = "SetLinkDefaultRoute";
static const char *const DBUS_OP_SET_LINK_DNS_OVER_TLS = "SetLinkDNSOverTLS";
static const char *const DBUS_OP_SET_LINK_DNS_EX = "SetLinkDNSEx";
static const char *const DBUS_OP_SET_LINK_DNSSEC = "SetLinkDNSSEC";
/*****************************************************************************/
@ -484,9 +485,11 @@ prepare_one_interface(NMDnsSystemdResolved *self, const InterfaceConfig *ic)
NMSettingConnectionMdns mdns = NM_SETTING_CONNECTION_MDNS_DEFAULT;
NMSettingConnectionLlmnr llmnr = NM_SETTING_CONNECTION_LLMNR_DEFAULT;
NMSettingConnectionDnsOverTls dns_over_tls = NM_SETTING_CONNECTION_DNS_OVER_TLS_DEFAULT;
NMSettingConnectionDnssec dnssec = NM_SETTING_CONNECTION_DNSSEC_DEFAULT;
const char *mdns_arg = NULL;
const char *llmnr_arg = NULL;
const char *dns_over_tls_arg = NULL;
const char *dnssec_arg = NULL;
gboolean has_config = FALSE;
gboolean has_default_route = FALSE;
guint i;
@ -517,6 +520,7 @@ prepare_one_interface(NMDnsSystemdResolved *self, const InterfaceConfig *ic)
llmnr = NM_MAX(llmnr, nm_l3_config_data_get_llmnr(ip_data->l3cd));
dns_over_tls =
NM_MAX(dns_over_tls, nm_l3_config_data_get_dns_over_tls(ip_data->l3cd));
dnssec = NM_MAX(dnssec, nm_l3_config_data_get_dnssec(ip_data->l3cd));
}
}
}
@ -589,8 +593,24 @@ prepare_one_interface(NMDnsSystemdResolved *self, const InterfaceConfig *ic)
}
nm_assert(dns_over_tls_arg);
switch (dnssec) {
case NM_SETTING_CONNECTION_DNSSEC_NO:
dnssec_arg = "no";
break;
case NM_SETTING_CONNECTION_DNSSEC_ALLOW_DOWNGRADE:
dnssec_arg = "allow-downgrade";
break;
case NM_SETTING_CONNECTION_DNSSEC_YES:
dnssec_arg = "yes";
break;
case NM_SETTING_CONNECTION_DNSSEC_DEFAULT:
dnssec_arg = "";
break;
}
nm_assert(dnssec_arg);
if (!nm_str_is_empty(mdns_arg) || !nm_str_is_empty(llmnr_arg)
|| !nm_str_is_empty(dns_over_tls_arg))
|| !nm_str_is_empty(dns_over_tls_arg) || !nm_str_is_empty(dnssec_arg))
has_config = TRUE;
_request_item_append(self, "SetLinkDomains", ic->ifindex, g_variant_builder_end(&domains));
@ -618,6 +638,10 @@ prepare_one_interface(NMDnsSystemdResolved *self, const InterfaceConfig *ic)
DBUS_OP_SET_LINK_DNS_OVER_TLS,
ic->ifindex,
g_variant_new("(is)", ic->ifindex, dns_over_tls_arg ?: ""));
_request_item_append(self,
DBUS_OP_SET_LINK_DNSSEC,
ic->ifindex,
g_variant_new("(is)", ic->ifindex, dnssec_arg ?: ""));
return has_config;
}

View file

@ -81,7 +81,7 @@ nm_main_utils_write_pidfile(const char *pidfile)
char pid[16];
nm_sprintf_buf(pid, "%lld", (long long) getpid());
if (!nm_utils_file_set_contents(pidfile, pid, -1, 00644, NULL, NULL, &error)) {
if (!nm_utils_file_set_contents(pidfile, pid, -1, 00644, NULL, NULL, NULL, &error)) {
fprintf(stderr, _("Writing to %s failed: %s\n"), pidfile, error->message);
return FALSE;
}

View file

@ -19,6 +19,7 @@
#include "libnm-systemd-shared/nm-sd-utils-shared.h"
#include "nm-l3cfg.h"
#include "nm-ndisc-private.h"
#include "nm-core-utils.h"
#define _NMLOG_PREFIX_NAME "ndisc-lndp"
@ -27,6 +28,14 @@
typedef struct {
struct ndp *ndp;
GSource *event_source;
struct {
NMRateLimit pio_lft;
NMRateLimit mtu;
NMRateLimit omit_prefix;
NMRateLimit omit_dns;
NMRateLimit omit_dnssl;
} msg_ratelimit;
} NMLndpNDiscPrivate;
/*****************************************************************************/
@ -49,6 +58,36 @@ G_DEFINE_TYPE(NMLndpNDisc, nm_lndp_ndisc, NM_TYPE_NDISC)
/*****************************************************************************/
/*
* If we log a message about an invalid RA packet, don't repeat the same message
* at every packet received or sent. Rate limit the message to 6 every 12 hours
* per type and per ndisc instance.
*/
#define LOG_INV_RA_WINDOW (12 * 3600)
#define LOG_INV_RA_BURST 6
#define _LOG_INVALID_RA(ndisc, rate_limit, ...) \
G_STMT_START \
{ \
NMNDisc *__ndisc = (ndisc); \
NMRateLimit *__rl = (rate_limit); \
const char *__ifname = nm_ndisc_get_ifname(__ndisc); \
\
if (__ifname && nm_logging_enabled(LOGL_WARN, LOGD_IP6) \
&& nm_rate_limit_check(__rl, LOG_INV_RA_WINDOW, LOG_INV_RA_BURST)) { \
nm_log(LOGL_WARN, \
LOGD_IP6, \
__ifname, \
NULL, \
"ndisc (%s): " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
__ifname _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
} \
} \
G_STMT_END
/*****************************************************************************/
static gboolean
send_rs(NMNDisc *ndisc, GError **error)
{
@ -113,6 +152,7 @@ static int
receive_ra(struct ndp *ndp, struct ndp_msg *msg, gpointer user_data)
{
NMNDisc *ndisc = (NMNDisc *) user_data;
NMLndpNDiscPrivate *priv = NM_LNDP_NDISC_GET_PRIVATE(ndisc);
NMNDiscDataInternal *rdata = ndisc->rdata;
NMNDiscConfigMap changed = 0;
NMNDiscGateway gateway;
@ -229,7 +269,11 @@ receive_ra(struct ndp *ndp, struct ndp_msg *msg, gpointer user_data)
* log a system management error in this case.
*/
if (preferred_time > valid_time) {
_LOGW("skipping PIO - preferred lifetime > valid lifetime");
_LOG_INVALID_RA(
ndisc,
&priv->msg_ratelimit.pio_lft,
"ignoring Prefix Information Option with invalid lifetimes in received IPv6 "
"router advertisement");
continue;
}
@ -349,7 +393,11 @@ receive_ra(struct ndp *ndp, struct ndp_msg *msg, gpointer user_data)
* Kernel would set it, but would flush out all IPv6 addresses away
* from the link, even the link-local, and we wouldn't be able to
* listen for further RAs that could fix the MTU. */
_LOGW("MTU too small for IPv6 ignored: %d", mtu);
_LOG_INVALID_RA(ndisc,
&priv->msg_ratelimit.mtu,
"ignoring too small MTU %u in received IPv6 "
"router advertisement",
mtu);
}
}
@ -445,8 +493,11 @@ send_ra(NMNDisc *ndisc, GError **error)
prefix = _ndp_msg_add_option(msg, sizeof(*prefix));
if (!prefix) {
/* Maybe we could sent separate RAs, but why bother... */
_LOGW("The RA is too big, had to omit some some prefixes.");
/* Maybe we could send separate RAs, but why bother... */
_LOG_INVALID_RA(
ndisc,
&priv->msg_ratelimit.omit_prefix,
"the outgoing IPv6 router advertisement is too big: omitting some prefixes");
break;
}
@ -475,7 +526,10 @@ send_ra(NMNDisc *ndisc, GError **error)
option = _ndp_msg_add_option(msg, len);
if (!option) {
_LOGW("The RA is too big, had to omit DNS information.");
_LOG_INVALID_RA(
ndisc,
&priv->msg_ratelimit.omit_dns,
"the outgoing IPv6 router advertisement is too big: omitting DNS information");
goto dns_servers_done;
}
@ -553,7 +607,10 @@ dns_servers_done:
nm_assert(len / 8u >= 2u);
if (len / 8u >= 256u || !(option = _ndp_msg_add_option(msg, len))) {
_LOGW("The RA is too big, had to omit DNS search list.");
_LOG_INVALID_RA(
ndisc,
&priv->msg_ratelimit.omit_dnssl,
"the outgoing IPv6 router advertisement is too big: omitting DNS search list");
goto dns_domains_done;
}

View file

@ -160,7 +160,7 @@ parse_connection_from_shadowed_file(const char *path, GError **error)
{
nm_auto_unref_keyfile GKeyFile *keyfile = NULL;
gs_free char *base_dir = NULL;
char *sep;
const char *sep;
keyfile = g_key_file_new();
if (!g_key_file_load_from_file(keyfile, path, G_KEY_FILE_NONE, error))

View file

@ -892,6 +892,7 @@ static const ConfigGroup config_groups[] = {
.is_prefix = TRUE,
.keys = NM_MAKE_STRV(NM_CONFIG_KEYFILE_KEY_DEVICE_CARRIER_WAIT_TIMEOUT,
NM_CONFIG_KEYFILE_KEY_DEVICE_IGNORE_CARRIER,
NM_CONFIG_KEYFILE_KEY_DEVICE_CHECK_CONNECTIVITY,
NM_CONFIG_KEYFILE_KEY_DEVICE_MANAGED,
NM_CONFIG_KEYFILE_KEY_DEVICE_SRIOV_NUM_VFS,
NM_CONFIG_KEYFILE_KEY_DEVICE_KEEP_CONFIGURATION,

View file

@ -77,6 +77,8 @@ struct _NMConnectivityCheckHandle {
ConConfig *con_config;
GCancellable *resolve_cancellable;
int resolve_ifindex;
GDBusConnection *dbus_connection;
CURLM *curl_mhandle;
CURL *curl_ehandle;
struct curl_slist *request_headers;
@ -953,6 +955,113 @@ systemd_resolved_resolve_cb(GObject *object, GAsyncResult *res, gpointer user_da
do_curl_request(cb_data, nm_str_buf_get_str(&strbuf_hosts));
}
static void
systemd_resolved_resolve(NMConnectivityCheckHandle *cb_data)
{
_LOG2D("start request to '%s' (try resolving '%s' using systemd-resolved with ifindex %d)",
cb_data->concheck.con_config->uri,
cb_data->concheck.con_config->host,
cb_data->concheck.resolve_ifindex);
g_dbus_connection_call(cb_data->concheck.dbus_connection,
"org.freedesktop.resolve1",
"/org/freedesktop/resolve1",
"org.freedesktop.resolve1.Manager",
"ResolveHostname",
g_variant_new("(isit)",
(gint32) cb_data->concheck.resolve_ifindex,
cb_data->concheck.con_config->host,
(gint32) cb_data->addr_family,
SD_RESOLVED_DNS),
G_VARIANT_TYPE("(a(iiay)st)"),
G_DBUS_CALL_FLAGS_NONE,
-1,
cb_data->concheck.resolve_cancellable,
systemd_resolved_resolve_cb,
cb_data);
}
static void
systemd_resolved_link_scopes_cb(GObject *object, GAsyncResult *res, gpointer user_data)
{
NMConnectivityCheckHandle *cb_data;
gs_unref_variant GVariant *result = NULL;
gs_unref_variant GVariant *value = NULL;
gs_free_error GError *error = NULL;
guint64 scope_mask = 0;
result = g_dbus_connection_call_finish(G_DBUS_CONNECTION(object), res, &error);
if (nm_utils_error_is_cancelled(error))
return;
cb_data = user_data;
if (!result) {
_LOG2D("unable to obtain systemd-resolved link ScopesMask for interface %d: %s",
cb_data->concheck.resolve_ifindex,
error->message);
cb_data->concheck.resolve_ifindex = 0;
systemd_resolved_resolve(cb_data);
return;
}
g_variant_get(result, "(v)", &value);
g_variant_get(value, "t", &scope_mask);
if (!(scope_mask & SD_RESOLVED_DNS)) {
/* there is no per-link DNS configured / active; query all available /
* system DNS resolvers instead of restricting the lookup to just this
* one, which would turn up no results. */
_LOG2D("no per-link DNS available (scope mask %" G_GUINT64_FORMAT
"); falling back to system-wide lookups",
scope_mask);
cb_data->concheck.resolve_ifindex = 0;
}
systemd_resolved_resolve(cb_data);
}
static void
systemd_resolved_get_link_cb(GObject *object, GAsyncResult *res, gpointer user_data)
{
NMConnectivityCheckHandle *cb_data;
gs_unref_variant GVariant *result = NULL;
gs_free char *link_path = NULL;
gs_free_error GError *error = NULL;
result = g_dbus_connection_call_finish(G_DBUS_CONNECTION(object), res, &error);
if (nm_utils_error_is_cancelled(error))
return;
cb_data = user_data;
if (!result) {
_LOG2D("unable to obtain systemd-resolved link D-Bus object for interface %d: %s",
cb_data->concheck.resolve_ifindex,
error->message);
cb_data->concheck.resolve_ifindex = 0;
systemd_resolved_resolve(cb_data);
return;
}
g_variant_get(result, "(o)", &link_path);
g_dbus_connection_call(cb_data->concheck.dbus_connection,
"org.freedesktop.resolve1",
link_path,
"org.freedesktop.DBus.Properties",
"Get",
g_variant_new("(ss)", "org.freedesktop.resolve1.Link", "ScopesMask"),
G_VARIANT_TYPE("(v)"),
G_DBUS_CALL_FLAGS_NONE,
-1,
cb_data->concheck.resolve_cancellable,
systemd_resolved_link_scopes_cb,
cb_data);
}
static NMConnectivityState
check_platform_config(NMConnectivity *self,
NMPlatform *platform,
@ -1067,6 +1176,7 @@ nm_connectivity_check_start(NMConnectivity *self,
}
cb_data->concheck.resolve_cancellable = g_cancellable_new();
cb_data->concheck.resolve_ifindex = ifindex;
/* note that we pick up support for systemd-resolved right away when we need it.
* We don't need to remember the setting, because we can (cheaply) check anew
@ -1089,10 +1199,8 @@ nm_connectivity_check_start(NMConnectivity *self,
has_systemd_resolved = !!nm_dns_manager_get_systemd_resolved(nm_dns_manager_get());
if (has_systemd_resolved) {
GDBusConnection *dbus_connection;
dbus_connection = NM_MAIN_DBUS_CONNECTION_GET;
if (!dbus_connection) {
cb_data->concheck.dbus_connection = NM_MAIN_DBUS_CONNECTION_GET;
if (!cb_data->concheck.dbus_connection) {
/* we have no D-Bus connection? That might happen in configure and quit mode.
*
* Anyway, something is very odd, just fail connectivity check. */
@ -1103,25 +1211,19 @@ nm_connectivity_check_start(NMConnectivity *self,
return cb_data;
}
g_dbus_connection_call(dbus_connection,
/* first check whether there has been a per-link DNS configured */
g_dbus_connection_call(cb_data->concheck.dbus_connection,
"org.freedesktop.resolve1",
"/org/freedesktop/resolve1",
"org.freedesktop.resolve1.Manager",
"ResolveHostname",
g_variant_new("(isit)",
0,
cb_data->concheck.con_config->host,
(gint32) cb_data->addr_family,
SD_RESOLVED_DNS),
G_VARIANT_TYPE("(a(iiay)st)"),
"GetLink",
g_variant_new("(i)", ifindex),
G_VARIANT_TYPE("(o)"),
G_DBUS_CALL_FLAGS_NONE,
-1,
cb_data->concheck.resolve_cancellable,
systemd_resolved_resolve_cb,
systemd_resolved_get_link_cb,
cb_data);
_LOG2D("start request to '%s' (try resolving '%s' using systemd-resolved)",
cb_data->concheck.con_config->uri,
cb_data->concheck.con_config->host);
return cb_data;
}

View file

@ -2865,6 +2865,7 @@ _host_id_read(guint8 **out_host_id, gsize *out_host_id_len)
0600,
NULL,
NULL,
NULL,
&error)) {
nm_log_warn(
LOGD_CORE,
@ -5011,6 +5012,7 @@ typedef struct {
int child_stdin;
int child_stdout;
int child_stderr;
gboolean binary_output;
GSource *input_source;
GSource *output_source;
GSource *error_source;
@ -5090,9 +5092,17 @@ helper_complete(HelperInfo *info, GError *error)
}
nm_clear_g_cancellable_disconnect(g_task_get_cancellable(info->task), &info->cancellable_id);
g_task_return_pointer(info->task,
nm_str_buf_finalize(&info->in_buffer, NULL) ?: g_new0(char, 1),
g_free);
if (info->binary_output) {
g_task_return_pointer(
info->task,
g_bytes_new(nm_str_buf_get_str_unsafe(&info->in_buffer), info->in_buffer.len),
(GDestroyNotify) (g_bytes_unref));
} else {
g_task_return_pointer(info->task,
nm_str_buf_finalize(&info->in_buffer, NULL) ?: g_new0(char, 1),
g_free);
}
helper_info_free(info);
}
@ -5235,6 +5245,7 @@ helper_cancelled(GObject *object, gpointer user_data)
void
nm_utils_spawn_helper(const char *const *args,
gboolean binary_output,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer cb_data)
@ -5250,9 +5261,14 @@ nm_utils_spawn_helper(const char *const *args,
info = g_new(HelperInfo, 1);
*info = (HelperInfo) {
.task = nm_g_task_new(NULL, cancellable, nm_utils_spawn_helper, callback, cb_data),
.task = nm_g_task_new(NULL, cancellable, nm_utils_spawn_helper, callback, cb_data),
.binary_output = binary_output,
};
/* Store if the caller requested binary output so that we can check later
* that the right result function is called. */
g_task_set_task_data(info->task, GINT_TO_POINTER(binary_output), NULL);
if (!g_spawn_async_with_pipes("/",
(char **) NM_MAKE_STRV(LIBEXECDIR "/nm-daemon-helper"),
(char **) NM_MAKE_STRV(),
@ -5363,11 +5379,25 @@ nm_utils_spawn_helper(const char *const *args,
}
char *
nm_utils_spawn_helper_finish(GAsyncResult *result, GError **error)
nm_utils_spawn_helper_finish_string(GAsyncResult *result, GError **error)
{
GTask *task = G_TASK(result);
nm_assert(nm_g_task_is_valid(result, NULL, nm_utils_spawn_helper));
/* Check binary_output */
nm_assert(GPOINTER_TO_INT(g_task_get_task_data(task)) == FALSE);
return g_task_propagate_pointer(task, error);
}
GBytes *
nm_utils_spawn_helper_finish_binary(GAsyncResult *result, GError **error)
{
GTask *task = G_TASK(result);
nm_assert(nm_g_task_is_valid(result, NULL, nm_utils_spawn_helper));
/* Check binary_output */
nm_assert(GPOINTER_TO_INT(g_task_get_task_data(task)) == TRUE);
return g_task_propagate_pointer(task, error);
}
@ -5474,3 +5504,334 @@ nm_utils_shorten_hostname(const char *hostname, char **shortened)
*shortened = g_steal_pointer(&s);
return TRUE;
}
/**
* nm_utils_connection_supported:
* @connection: the connection
* @error: on return, the reason why the connection in not supported
*
* Returns whether the given connection is supported by this version
* of NetworkManager.
*/
gboolean
nm_utils_connection_supported(NMConnection *connection, GError **error)
{
const char *type;
const char *feature = NULL;
g_return_val_if_fail(connection, FALSE);
g_return_val_if_fail(!error || !*error, FALSE);
type = nm_connection_get_connection_type(connection);
if (!WITH_TEAMDCTL) {
NMSettingConnection *s_con;
if (nm_streq0(type, NM_SETTING_TEAM_SETTING_NAME)) {
feature = "team";
goto out_disabled;
}
/* Match team ports */
if ((s_con = nm_connection_get_setting_connection(connection))
&& nm_streq0(nm_setting_connection_get_port_type(s_con),
NM_SETTING_TEAM_SETTING_NAME)) {
feature = "team";
goto out_disabled;
}
}
if (!WITH_OPENVSWITCH) {
if (NM_IN_STRSET(type,
NM_SETTING_OVS_BRIDGE_SETTING_NAME,
NM_SETTING_OVS_PORT_SETTING_NAME,
NM_SETTING_OVS_INTERFACE_SETTING_NAME)) {
feature = "Open vSwitch";
goto out_disabled;
}
/* Match OVS system interfaces */
if (nm_connection_get_setting_ovs_interface(connection)) {
feature = "Open vSwitch";
goto out_disabled;
}
}
if (!WITH_WIFI
&& NM_IN_STRSET(type,
NM_SETTING_WIRELESS_SETTING_NAME,
NM_SETTING_OLPC_MESH_SETTING_NAME,
NM_SETTING_WIFI_P2P_SETTING_NAME)) {
feature = "Wi-Fi";
goto out_disabled;
}
if (!WITH_WWAN
&& NM_IN_STRSET(type, NM_SETTING_GSM_SETTING_NAME, NM_SETTING_CDMA_SETTING_NAME)) {
feature = "WWAN";
goto out_disabled;
}
if (nm_streq0(type, NM_SETTING_WIMAX_SETTING_NAME)) {
feature = "WiMAX";
goto out_removed;
}
return TRUE;
out_disabled:
nm_assert(feature);
g_set_error(error,
NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_FEATURE_DISABLED,
"%s support is disabled in this build",
feature);
return FALSE;
out_removed:
nm_assert(feature);
g_set_error(error,
NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_FEATURE_REMOVED,
"%s is no longer supported",
feature);
return FALSE;
}
/*****************************************************************************/
/**
* nm_rate_limit_check():
* @rate_limit: the NMRateLimit instance
* @window_sec: the time window in seconds, between 1 and 864000 (ten days)
* @burst: the number of max allowed event occurrences in the given time
* window
*
* The function rate limits an event. Call it multiple times with the
* same @window_sec, and @burst values.
*
* Returns: TRUE if the event is allowed, FALSE if it is rate-limited
*/
gboolean
nm_rate_limit_check(NMRateLimit *rate_limit, gint32 window_sec, gint32 burst)
{
gint64 now;
gint64 old_ts_msec;
gint64 window_msec;
gint64 capacity;
gint64 elapsed;
nm_assert(window_sec >= 1 && window_sec <= 864000);
nm_assert(burst >= 1);
/* This implements a simple token bucket algorithm. For each millisecond,
* refill "burst" tokens. Thus, during a full time window we
* refill (window_msec * burst) tokens. Each event consumes @window_msec
* tokens. */
window_msec = (gint64) window_sec * NM_UTILS_MSEC_PER_SEC;
capacity = window_msec * (gint64) burst;
old_ts_msec = rate_limit->ts_msec;
now = nm_utils_get_monotonic_timestamp_msec();
rate_limit->ts_msec = now;
elapsed = now - old_ts_msec;
if (old_ts_msec == 0 || elapsed > window_msec) {
/* On the first call, or in case a whole window passed, (re)start with
* a full budget */
rate_limit->tokens = capacity;
} else {
rate_limit->tokens += elapsed * (gint64) burst;
rate_limit->tokens = NM_MIN(rate_limit->tokens, capacity);
}
/* Consume the tokens */
if (rate_limit->tokens >= window_msec) {
rate_limit->tokens -= window_msec;
return TRUE;
}
return FALSE;
}
const char *
nm_utils_get_connection_first_permissions_user(NMConnection *connection)
{
NMSettingConnection *s_con;
s_con = nm_connection_get_setting_connection(connection);
nm_assert(s_con);
return _nm_setting_connection_get_first_permissions_user(s_con);
}
/*****************************************************************************/
const char **
nm_utils_get_connection_private_files_paths(NMConnection *connection)
{
GPtrArray *files;
gs_free NMSetting **settings = NULL;
guint num_settings;
guint i;
files = g_ptr_array_new();
settings = nm_connection_get_settings(connection, &num_settings);
for (i = 0; i < num_settings; i++) {
_nm_setting_get_private_files(settings[i], files);
}
g_ptr_array_add(files, NULL);
return (const char **) g_ptr_array_free(files, files->len == 1);
}
typedef struct _ReadInfo ReadInfo;
typedef struct {
char *path;
ReadInfo *read_info;
} FileInfo;
struct _ReadInfo {
GTask *task;
GHashTable *table;
GPtrArray *file_infos; /* of FileInfo */
GError *first_error;
guint num_pending;
};
static void
read_file_helper_cb(GObject *source, GAsyncResult *result, gpointer user_data)
{
FileInfo *file_info = user_data;
ReadInfo *read_info = file_info->read_info;
gs_unref_bytes GBytes *output = NULL;
gs_free_error GError *error = NULL;
output = nm_utils_spawn_helper_finish_binary(result, &error);
nm_assert(read_info->num_pending > 0);
read_info->num_pending--;
if (nm_utils_error_is_cancelled(error)) {
/* nop */
} else if (error) {
nm_log_dbg(LOGD_CORE,
"read-private-files: failed to read file '%s': %s",
file_info->path,
error->message);
if (!read_info->first_error) {
/* @error just says "helper process exited with status X".
* Return a more human-friendly one. */
read_info->first_error = g_error_new(NM_UTILS_ERROR,
NM_UTILS_ERROR_UNKNOWN,
"error reading file '%s'",
file_info->path);
}
} else {
nm_log_dbg(LOGD_SUPPLICANT,
"read-private-files: successfully read file '%s'",
file_info->path);
/* Store the file contents in the hash table */
if (!read_info->table) {
read_info->table = g_hash_table_new_full(nm_str_hash,
g_str_equal,
g_free,
(GDestroyNotify) g_bytes_unref);
}
g_hash_table_insert(read_info->table,
g_steal_pointer(&file_info->path),
g_steal_pointer(&output));
}
g_clear_pointer(&file_info->path, g_free);
/* If all operations are completed, return */
if (read_info->num_pending == 0) {
if (read_info->first_error) {
g_task_return_error(read_info->task, g_steal_pointer(&read_info->first_error));
} else {
g_task_return_pointer(read_info->task,
g_steal_pointer(&read_info->table),
(GDestroyNotify) g_hash_table_unref);
}
if (read_info->table)
g_hash_table_unref(read_info->table);
if (read_info->file_infos)
g_ptr_array_unref(read_info->file_infos);
g_object_unref(read_info->task);
g_free(read_info);
}
}
/**
* nm_utils_read_private_files:
* @paths: array of file paths to be read
* @user: name of the user to impersonate when reading the files
* @cancellable: cancellable to cancel the operation
* @callback: callback to invoke on completion
* @cb_data: data for @callback
*
* Reads the given list of files @paths on behalf of user @user. Invokes
* @callback asynchronously on completion. The callback must use
* nm_utils_read_private_files_finish() to obtain the result.
*/
void
nm_utils_read_private_files(const char *const *paths,
const char *user,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer cb_data)
{
ReadInfo *read_info;
FileInfo *file_info;
guint i;
g_return_if_fail(paths && paths[0]);
g_return_if_fail(cancellable);
g_return_if_fail(callback);
g_return_if_fail(cb_data);
read_info = g_new(ReadInfo, 1);
*read_info = (ReadInfo) {
.task = nm_g_task_new(NULL, cancellable, nm_utils_read_private_files, callback, cb_data),
.file_infos = g_ptr_array_new_with_free_func(g_free),
};
for (i = 0; paths[i]; i++) {
file_info = g_new(FileInfo, 1);
*file_info = (FileInfo) {
.path = g_strdup(paths[i]),
.read_info = read_info,
};
g_ptr_array_add(read_info->file_infos, file_info);
read_info->num_pending++;
nm_utils_spawn_helper(NM_MAKE_STRV("read-file-as-user", user, paths[i]),
TRUE,
cancellable,
read_file_helper_cb,
file_info);
}
}
/**
* nm_utils_read_private_files_finish:
* @result: the GAsyncResult
* @error: on return, the error
*
* Returns the files read by nm_utils_read_private_files(). The return value
* is a hash table {char * -> GBytes *}. Free it with g_hash_table_unref().
*/
GHashTable *
nm_utils_read_private_files_finish(GAsyncResult *result, GError **error)
{
GTask *task = G_TASK(result);
nm_assert(nm_g_task_is_valid(result, NULL, nm_utils_read_private_files));
return g_task_propagate_pointer(task, error);
}

View file

@ -478,11 +478,13 @@ guint8 nm_wifi_utils_level_to_quality(int val);
/*****************************************************************************/
void nm_utils_spawn_helper(const char *const *args,
gboolean binary_output,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer cb_data);
char *nm_utils_spawn_helper_finish(GAsyncResult *result, GError **error);
char *nm_utils_spawn_helper_finish_string(GAsyncResult *result, GError **error);
GBytes *nm_utils_spawn_helper_finish_binary(GAsyncResult *result, GError **error);
/*****************************************************************************/
@ -490,4 +492,32 @@ uid_t nm_utils_get_nm_uid(void);
gid_t nm_utils_get_nm_gid(void);
/*****************************************************************************/
gboolean nm_utils_connection_supported(NMConnection *connection, GError **error);
/*****************************************************************************/
typedef struct {
gint64 ts_msec;
gint64 tokens;
} NMRateLimit;
gboolean nm_rate_limit_check(NMRateLimit *rate_limit, gint32 window_sec, gint32 burst);
/*****************************************************************************/
const char *nm_utils_get_connection_first_permissions_user(NMConnection *connection);
/*****************************************************************************/
const char **nm_utils_get_connection_private_files_paths(NMConnection *connection);
void nm_utils_read_private_files(const char *const *paths,
const char *user,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer cb_data);
GHashTable *nm_utils_read_private_files_finish(GAsyncResult *result, GError **error);
#endif /* __NM_CORE_UTILS_H__ */

View file

@ -120,6 +120,7 @@ struct _NML3ConfigData {
NMSettingConnectionMdns mdns;
NMSettingConnectionLlmnr llmnr;
NMSettingConnectionDnsOverTls dns_over_tls;
NMSettingConnectionDnssec dnssec;
NMUtilsIPv6IfaceId ip6_token;
NML3ConfigDatFlags flags;
@ -577,6 +578,16 @@ nm_l3_config_data_log(const NML3ConfigData *self,
NULL)));
}
if (self->dnssec != NM_SETTING_CONNECTION_DNSSEC_DEFAULT) {
gs_free char *s = NULL;
_L("dnssec: %s",
(s = _nm_utils_enum_to_str_full(nm_setting_connection_dnssec_get_type(),
self->dnssec,
" ",
NULL)));
}
if (self->mptcp_flags != NM_MPTCP_FLAGS_NONE) {
gs_free char *s = NULL;
@ -694,6 +705,7 @@ nm_l3_config_data_new(NMDedupMultiIndex *multi_idx, int ifindex, NMIPConfigSourc
.mdns = NM_SETTING_CONNECTION_MDNS_DEFAULT,
.llmnr = NM_SETTING_CONNECTION_LLMNR_DEFAULT,
.dns_over_tls = NM_SETTING_CONNECTION_DNS_OVER_TLS_DEFAULT,
.dnssec = NM_SETTING_CONNECTION_DNSSEC_DEFAULT,
.flags = NM_L3_CONFIG_DAT_FLAGS_NONE,
.metered = NM_TERNARY_DEFAULT,
.proxy_browser_only = NM_TERNARY_DEFAULT,
@ -1767,6 +1779,26 @@ nm_l3_config_data_set_dns_over_tls(NML3ConfigData *self, NMSettingConnectionDnsO
return TRUE;
}
NMSettingConnectionDnssec
nm_l3_config_data_get_dnssec(const NML3ConfigData *self)
{
nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE));
return self->dnssec;
}
gboolean
nm_l3_config_data_set_dnssec(NML3ConfigData *self, NMSettingConnectionDnssec dnssec)
{
nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE));
if (self->dnssec == dnssec)
return FALSE;
self->dnssec = dnssec;
return TRUE;
}
NMIPRouteTableSyncMode
nm_l3_config_data_get_route_table_sync(const NML3ConfigData *self, int addr_family)
{
@ -2446,6 +2478,7 @@ nm_l3_config_data_cmp_full(const NML3ConfigData *a,
NM_CMP_DIRECT(a->mdns, b->mdns);
NM_CMP_DIRECT(a->llmnr, b->llmnr);
NM_CMP_DIRECT(a->dns_over_tls, b->dns_over_tls);
NM_CMP_DIRECT(a->dnssec, b->dnssec);
}
if (NM_FLAGS_HAS(flags, NM_L3_CONFIG_CMP_FLAGS_OTHER)) {
@ -3211,6 +3244,12 @@ nm_l3_config_data_hash_dns(const NML3ConfigData *l3cd,
empty = FALSE;
}
val = nm_l3_config_data_get_dnssec(l3cd);
if (val != NM_SETTING_CONNECTION_DNSSEC_DEFAULT) {
g_checksum_update(sum, (const guint8 *) &val, sizeof(val));
empty = FALSE;
}
if (!empty) {
int prio = 0;
@ -3461,6 +3500,9 @@ nm_l3_config_data_merge(NML3ConfigData *self,
if (self->dns_over_tls == NM_SETTING_CONNECTION_DNS_OVER_TLS_DEFAULT)
self->dns_over_tls = src->dns_over_tls;
if (self->dnssec == NM_SETTING_CONNECTION_DNSSEC_DEFAULT)
self->dnssec = src->dnssec;
if (self->ip6_token.id == 0)
self->ip6_token.id = src->ip6_token.id;

View file

@ -458,6 +458,10 @@ NMSettingConnectionDnsOverTls nm_l3_config_data_get_dns_over_tls(const NML3Confi
gboolean nm_l3_config_data_set_dns_over_tls(NML3ConfigData *self,
NMSettingConnectionDnsOverTls dns_over_tls);
NMSettingConnectionDnssec nm_l3_config_data_get_dnssec(const NML3ConfigData *self);
gboolean nm_l3_config_data_set_dnssec(NML3ConfigData *self, NMSettingConnectionDnssec dnssec);
NMIPRouteTableSyncMode nm_l3_config_data_get_route_table_sync(const NML3ConfigData *self,
int addr_family);

View file

@ -3056,9 +3056,10 @@ handle_start_probing:
}
_LOGT_acd(acd_data,
"%sstart probing (timeout %u msec, %s)",
"%sstart probing (timeout %u msec, ebpf %s; %s)",
orig_state == NM_L3_ACD_ADDR_STATE_INIT ? "" : "re",
acd_data->probing_timeout_msec,
n_acd_has_bpf(self->priv.p->nacd) ? "enabled" : "disabled",
log_reason);
return;
}
@ -3153,10 +3154,11 @@ handle_start_defending:
}
_LOGT_acd(acd_data,
"start announcing (defend=%s) (probe created)",
"start announcing (defend=%s) (probe created with ebpf %s)",
_l3_acd_defend_type_to_string(acd_data->acd_defend_type_current,
sbuf256,
sizeof(sbuf256)));
sizeof(sbuf256)),
n_acd_has_bpf(self->priv.p->nacd) ? "enabled" : "disabled");
acd_data->acd_defend_type_is_active = FALSE;
acd_data->nacd_probe = probe;
return;
@ -5052,8 +5054,8 @@ _l3_commit_mptcp_af(NML3Cfg *self,
(NM_FLAGS_HAS(mptcp_flags, NM_MPTCP_FLAGS_SIGNAL) ? MPTCP_PM_ADDR_FLAG_SIGNAL : 0)
| (NM_FLAGS_HAS(mptcp_flags, NM_MPTCP_FLAGS_SUBFLOW) ? MPTCP_PM_ADDR_FLAG_SUBFLOW : 0)
| (NM_FLAGS_HAS(mptcp_flags, NM_MPTCP_FLAGS_BACKUP) ? MPTCP_PM_ADDR_FLAG_BACKUP : 0)
| (NM_FLAGS_HAS(mptcp_flags, NM_MPTCP_FLAGS_FULLMESH) ? MPTCP_PM_ADDR_FLAG_FULLMESH
: 0);
| (NM_FLAGS_HAS(mptcp_flags, NM_MPTCP_FLAGS_FULLMESH) ? MPTCP_PM_ADDR_FLAG_FULLMESH : 0)
| (NM_FLAGS_HAS(mptcp_flags, NM_MPTCP_FLAGS_LAMINAR) ? MPTCP_PM_ADDR_FLAG_LAMINAR : 0);
NMPlatformMptcpAddr a = {
.ifindex = self->priv.ifindex,
.id = 0,

View file

@ -136,6 +136,7 @@ enum {
ACTIVE_CONNECTION_REMOVED,
CONFIGURE_QUIT,
DEVICE_IFINDEX_CHANGED,
SHARING_IPV4_CHANGED,
LAST_SIGNAL
};
@ -238,6 +239,8 @@ typedef struct {
guint8 device_state_prune_ratelimit_count;
guint shared_connections_ip4_count;
bool startup : 1;
bool devices_inited : 1;
@ -1960,7 +1963,7 @@ find_device_by_iface(NMManager *self,
}
static gboolean
manager_sleeping(NMManager *self)
manager_is_disabled(NMManager *self)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE(self);
@ -1973,8 +1976,8 @@ static const char *
_nm_state_to_string(NMState state)
{
switch (state) {
case NM_STATE_ASLEEP:
return "ASLEEP";
case NM_STATE_DISABLED:
return "DISABLED";
case NM_STATE_DISCONNECTED:
return "DISCONNECTED";
case NM_STATE_DISCONNECTING:
@ -2078,15 +2081,18 @@ nm_manager_update_state(NMManager *self)
{
NMManagerPrivate *priv;
NMState new_state = NM_STATE_DISCONNECTED;
const char *detail = "";
g_return_if_fail(NM_IS_MANAGER(self));
priv = NM_MANAGER_GET_PRIVATE(self);
if (manager_sleeping(self))
new_state = NM_STATE_ASLEEP;
else
if (manager_is_disabled(self)) {
new_state = NM_STATE_DISABLED;
detail = priv->sleeping ? " (ASLEEP)" : " (NETWORKING OFF)";
} else {
new_state = find_best_device_state(self);
}
if (new_state >= NM_STATE_CONNECTED_LOCAL && priv->connectivity_state == NM_CONNECTIVITY_FULL) {
new_state = NM_STATE_CONNECTED_GLOBAL;
@ -2097,7 +2103,7 @@ nm_manager_update_state(NMManager *self)
priv->state = new_state;
_LOGI(LOGD_CORE, "NetworkManager state is now %s", _nm_state_to_string(new_state));
_LOGI(LOGD_CORE, "NetworkManager state is now %s%s", _nm_state_to_string(new_state), detail);
_notify(self, PROP_STATE);
nm_dbus_object_emit_signal(NM_DBUS_OBJECT(self),
@ -2956,7 +2962,7 @@ _rfkill_update_devices(NMManager *self, NMRfkillType rtype, gboolean enabled)
_notify(self, _rfkill_type_desc[rtype].prop_id);
/* Don't touch devices if asleep/networking disabled */
if (manager_sleeping(self))
if (manager_is_disabled(self))
return;
/* enable/disable wireless devices as required */
@ -3120,7 +3126,7 @@ _rfkill_update_from_user(NMManager *self, NMRfkillType rtype, gboolean enabled)
gboolean old_enabled, new_enabled;
/* Don't touch devices if asleep/networking disabled */
if (manager_sleeping(self))
if (manager_is_disabled(self))
return;
_LOGD(LOGD_RFKILL,
@ -4079,7 +4085,7 @@ add_device(NMManager *self, NMDevice *device, GError **error)
nm_device_set_unmanaged_by_user_settings(device, TRUE);
nm_device_set_unmanaged_flags(device, NM_UNMANAGED_SLEEPING, manager_sleeping(self));
nm_device_set_unmanaged_flags(device, NM_UNMANAGED_MANAGER_DISABLED, manager_is_disabled(self));
dbus_path = nm_dbus_object_export(NM_DBUS_OBJECT(device));
_LOG2I(LOGD_DEVICE, device, "new %s device (%s)", type_desc, dbus_path);
@ -7299,7 +7305,7 @@ device_sleep_cb(NMDevice *device, GParamSpec *pspec, NMManager *self)
case NM_DEVICE_STATE_DISCONNECTED:
_LOGD(LOGD_SUSPEND, "sleep: unmanaging device %s", nm_device_get_ip_iface(device));
nm_device_set_unmanaged_by_flags_queue(device,
NM_UNMANAGED_SLEEPING,
NM_UNMANAGED_MANAGER_DISABLED,
NM_UNMAN_FLAG_OP_SET_UNMANAGED,
NM_DEVICE_STATE_REASON_SLEEPING);
break;
@ -7321,24 +7327,26 @@ _handle_device_takedown(NMManager *self,
gboolean suspending,
gboolean is_shutdown)
{
gboolean is_sleep = suspending || is_shutdown;
NMDeviceStateReason reason =
is_sleep ? NM_DEVICE_STATE_REASON_SLEEPING : NM_DEVICE_STATE_REASON_NETWORKING_OFF;
nm_device_notify_sleeping(device);
if (nm_device_is_activating(device)
|| nm_device_get_state(device) == NM_DEVICE_STATE_ACTIVATED) {
_LOGD(LOGD_SUSPEND,
_LOGD(is_sleep ? LOGD_SUSPEND : LOGD_CORE,
"%s: wait disconnection of device %s",
is_shutdown ? "shutdown" : "sleep",
is_sleep ? (is_shutdown ? "shutdown" : "sleep") : "networking off",
nm_device_get_ip_iface(device));
if (sleep_devices_add(self, device, suspending))
nm_device_queue_state(device,
NM_DEVICE_STATE_DEACTIVATING,
NM_DEVICE_STATE_REASON_SLEEPING);
nm_device_queue_state(device, NM_DEVICE_STATE_DEACTIVATING, reason);
} else {
nm_device_set_unmanaged_by_flags(device,
NM_UNMANAGED_SLEEPING,
NM_UNMANAGED_MANAGER_DISABLED,
NM_UNMAN_FLAG_OP_SET_UNMANAGED,
NM_DEVICE_STATE_REASON_SLEEPING);
reason);
}
}
@ -7352,8 +7360,10 @@ do_sleep_wake(NMManager *self, gboolean sleeping_changed)
suspending = sleeping_changed && priv->sleeping;
waking_from_suspend = sleeping_changed && !priv->sleeping;
if (manager_sleeping(self)) {
_LOGD(LOGD_SUSPEND, "sleep: %s...", suspending ? "sleeping" : "disabling");
if (manager_is_disabled(self)) {
_LOGD(suspending ? LOGD_SUSPEND : LOGD_CORE,
"%s...",
suspending ? "sleep: sleeping" : "networking: disabling");
/* FIXME: are there still hardware devices that need to be disabled around
* suspend/resume?
@ -7379,7 +7389,9 @@ do_sleep_wake(NMManager *self, gboolean sleeping_changed)
_handle_device_takedown(self, device, suspending, FALSE);
}
} else {
_LOGD(LOGD_SUSPEND, "sleep: %s...", waking_from_suspend ? "waking up" : "re-enabling");
_LOGD(waking_from_suspend ? LOGD_SUSPEND : LOGD_CORE,
"%s...",
waking_from_suspend ? "sleep: waking up" : "networking: re-enabling");
sleep_devices_clear(self);
@ -7393,7 +7405,7 @@ do_sleep_wake(NMManager *self, gboolean sleeping_changed)
*/
if (device_is_wake_on_lan(priv->platform, device))
nm_device_set_unmanaged_by_flags(device,
NM_UNMANAGED_SLEEPING,
NM_UNMANAGED_MANAGER_DISABLED,
NM_UNMAN_FLAG_OP_SET_UNMANAGED,
NM_DEVICE_STATE_REASON_SLEEPING);
@ -7421,10 +7433,12 @@ do_sleep_wake(NMManager *self, gboolean sleeping_changed)
guint i;
if (nm_device_is_software(device)
&& !nm_device_get_unmanaged_flags(device, NM_UNMANAGED_SLEEPING)) {
&& !nm_device_get_unmanaged_flags(device, NM_UNMANAGED_MANAGER_DISABLED)) {
/* DHCP leases of software devices could have gone stale
* so we need to renew them. */
nm_device_update_dynamic_ip_setup(device, "wake up");
nm_device_update_dynamic_ip_setup(device,
waking_from_suspend ? "wake up"
: "networking on");
continue;
}
@ -7455,7 +7469,7 @@ do_sleep_wake(NMManager *self, gboolean sleeping_changed)
? NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED
: NM_DEVICE_STATE_REASON_NOW_MANAGED;
nm_device_set_unmanaged_by_flags(device,
NM_UNMANAGED_SLEEPING,
NM_UNMANAGED_MANAGER_DISABLED,
NM_UNMAN_FLAG_OP_SET_MANAGED,
reason);
}
@ -8818,6 +8832,41 @@ nm_manager_emit_device_ifindex_changed(NMManager *self, NMDevice *device)
g_signal_emit(self, signals[DEVICE_IFINDEX_CHANGED], 0, device);
}
void
nm_manager_update_shared_connection(NMManager *self, int addr_family, gboolean enabled)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE(self);
gboolean state_changed, state;
/* Only IPv4 supported for the moment */
if (addr_family != AF_INET)
return;
if (enabled) {
g_return_if_fail(priv->shared_connections_ip4_count < G_MAXUINT);
priv->shared_connections_ip4_count++;
state_changed = priv->shared_connections_ip4_count == 1;
} else {
g_return_if_fail(priv->shared_connections_ip4_count > 0);
priv->shared_connections_ip4_count--;
state_changed = priv->shared_connections_ip4_count == 0;
}
if (state_changed) {
state = priv->shared_connections_ip4_count > 0;
_LOGD(LOGD_SHARING, "sharing-ipv4 state change %d -> %d", !state, state);
g_signal_emit(self, signals[SHARING_IPV4_CHANGED], 0, state);
}
}
gboolean
nm_manager_get_sharing_ipv4(NMManager *self)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE(self);
return priv->shared_connections_ip4_count > 0;
}
/*****************************************************************************/
NM_DEFINE_SINGLETON_REGISTER(NMManager);
@ -9921,6 +9970,17 @@ nm_manager_class_init(NMManagerClass *manager_class)
G_TYPE_NONE,
1,
NM_TYPE_DEVICE);
signals[SHARING_IPV4_CHANGED] = g_signal_new(NM_MANAGER_SHARING_IPV4_CHANGED,
G_OBJECT_CLASS_TYPE(object_class),
G_SIGNAL_RUN_FIRST,
0,
NULL,
NULL,
NULL,
G_TYPE_NONE,
1,
G_TYPE_BOOLEAN);
}
NMConfig *

View file

@ -61,6 +61,7 @@
#define NM_MANAGER_CONFIGURE_QUIT "configure-quit"
#define NM_MANAGER_INTERNAL_DEVICE_ADDED "internal-device-added"
#define NM_MANAGER_INTERNAL_DEVICE_REMOVED "internal-device-removed"
#define NM_MANAGER_SHARING_IPV4_CHANGED "sharing-ipv4-changed"
GType nm_manager_get_type(void);
@ -212,6 +213,9 @@ struct _NMDnsManager;
struct _NMDnsManager *nm_manager_get_dns_manager(NMManager *self);
void nm_manager_update_shared_connection(NMManager *self, int addr_family, gboolean enabled);
gboolean nm_manager_get_sharing_ipv4(NMManager *self);
/*****************************************************************************/
void nm_manager_notify_delete_settings_connections(NMManager *self,

View file

@ -18,7 +18,6 @@
#include "NetworkManagerUtils.h"
#include "devices/nm-device.h"
#include "devices/nm-device-factory.h"
#include "devices/nm-device-private.h"
#include "dns/nm-dns-manager.h"
#include "nm-act-request.h"
#include "nm-auth-utils.h"
@ -98,6 +97,7 @@ typedef struct {
bool updating_dns : 1;
GArray *ip6_prefix_delegations; /* pool of ip6 prefixes delegated to all devices */
} NMPolicyPrivate;
struct _NMPolicy {
@ -1845,7 +1845,7 @@ nm_policy_device_recheck_auto_activate_schedule(NMPolicy *self, NMDevice *device
priv = NM_POLICY_GET_PRIVATE(self);
if (nm_manager_get_state(priv->manager) == NM_STATE_ASLEEP)
if (nm_manager_get_state(priv->manager) == NM_STATE_DISABLED)
return;
if (!nm_device_autoconnect_allowed(device))
@ -2083,65 +2083,6 @@ unblock_autoconnect_for_ports_for_sett_conn(NMPolicy *self, NMSettingsConnection
unblock_autoconnect_for_ports(self, controller_device, controller_uuid_settings, NULL);
}
static void
refresh_forwarding(NMPolicy *self, NMDevice *device, gboolean is_activated_shared_device)
{
NMActiveConnection *ac;
NMDevice *tmp_device;
NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE(self);
const CList *tmp_lst;
gboolean any_shared_active = false;
gint32 default_forwarding_v4;
const char *new_value = NULL;
/* FIXME: This implementation is still inefficient because refresh_forwarding()
* is called every time a device goes up or down, requiring a full scan of all
* active connections to determine if any shared connection is active. */
nm_manager_for_each_active_connection (priv->manager, ac, tmp_lst) {
NMSettingIPConfig *s_ip;
NMDevice *to_device = nm_active_connection_get_device(ac);
if (to_device) {
s_ip = nm_device_get_applied_setting(to_device, NM_TYPE_SETTING_IP4_CONFIG);
if (s_ip) {
if (nm_streq0(nm_device_get_effective_ip_config_method(to_device, AF_INET),
NM_SETTING_IP4_CONFIG_METHOD_SHARED)) {
any_shared_active = true;
break;
}
}
}
}
default_forwarding_v4 = nm_platform_sysctl_get_int32(
NM_PLATFORM_GET,
NMP_SYSCTL_PATHID_ABSOLUTE("/proc/sys/net/ipv4/conf/default/forwarding"),
0);
new_value = any_shared_active ? "1" : (default_forwarding_v4 ? "1" : "0");
nm_manager_for_each_device (priv->manager, tmp_device, tmp_lst) {
NMDeviceState state;
NMSettingIPConfigForwarding ipv4_forwarding;
state = nm_device_get_state(tmp_device);
if (state != NM_DEVICE_STATE_ACTIVATED)
continue;
ipv4_forwarding = nm_device_get_ipv4_forwarding(tmp_device);
if (ipv4_forwarding == NM_SETTING_IP_CONFIG_FORWARDING_AUTO
|| (device == tmp_device && is_activated_shared_device)) {
gs_free char *sysctl_value = NULL;
sysctl_value = nm_device_sysctl_ip_conf_get(tmp_device, AF_INET, "forwarding");
if (!nm_streq0(sysctl_value, new_value))
nm_device_sysctl_ip_conf_set(tmp_device, AF_INET, "forwarding", new_value);
}
}
}
static void
activate_port_or_children_connections(NMPolicy *self,
NMDevice *device,
@ -2286,9 +2227,8 @@ device_state_changed(NMDevice *device,
NMPolicyPrivate *priv = user_data;
NMPolicy *self = _PRIV_TO_SELF(priv);
NMActiveConnection *ac;
NMSettingsConnection *sett_conn = nm_device_get_settings_connection(device);
NMSettingConnection *s_con = NULL;
gboolean is_activated_shared_device = FALSE;
NMSettingsConnection *sett_conn = nm_device_get_settings_connection(device);
NMSettingConnection *s_con = NULL;
switch (nm_device_state_reason_check(reason)) {
case NM_DEVICE_STATE_REASON_GSM_SIM_PIN_REQUIRED:
@ -2404,10 +2344,6 @@ device_state_changed(NMDevice *device,
}
}
}
if (!nm_device_get_refresh_forwarding_done(device)) {
refresh_forwarding(self, device, FALSE);
nm_device_set_refresh_forwarding_done(device, TRUE);
}
break;
case NM_DEVICE_STATE_ACTIVATED:
if (nm_device_get_device_type(device) == NM_DEVICE_TYPE_OVS_INTERFACE) {
@ -2417,7 +2353,10 @@ device_state_changed(NMDevice *device,
}
if (sett_conn) {
/* Reset auto retries back to default since connection was successful */
nm_manager_devcon_autoconnect_retries_reset(priv->manager, device, sett_conn);
nm_manager_devcon_autoconnect_reset_reconnect_all(priv->manager,
device,
sett_conn,
FALSE);
}
/* Since there is no guarantee that device_l3cd_changed() is called
@ -2440,20 +2379,11 @@ device_state_changed(NMDevice *device,
update_system_hostname(self, "routing and dns", TRUE);
nm_dns_manager_end_updates(priv->dns_manager, __func__);
is_activated_shared_device =
nm_streq0(nm_device_get_effective_ip_config_method(device, AF_INET),
NM_SETTING_IP4_CONFIG_METHOD_SHARED);
refresh_forwarding(self, device, is_activated_shared_device);
nm_device_set_refresh_forwarding_done(device, FALSE);
break;
case NM_DEVICE_STATE_UNMANAGED:
case NM_DEVICE_STATE_UNAVAILABLE:
if (old_state > NM_DEVICE_STATE_DISCONNECTED)
update_routing_and_dns(self, FALSE, device);
if (!nm_device_get_refresh_forwarding_done(device)) {
refresh_forwarding(self, device, FALSE);
nm_device_set_refresh_forwarding_done(device, TRUE);
}
break;
case NM_DEVICE_STATE_DEACTIVATING:
if (sett_conn) {
@ -2489,10 +2419,6 @@ device_state_changed(NMDevice *device,
}
}
ip6_remove_device_prefix_delegations(self, device);
if (!nm_device_get_refresh_forwarding_done(device)) {
refresh_forwarding(self, device, FALSE);
nm_device_set_refresh_forwarding_done(device, TRUE);
}
break;
case NM_DEVICE_STATE_DISCONNECTED:
g_signal_handlers_disconnect_by_func(device, device_dns_lookup_done, self);
@ -2509,10 +2435,6 @@ device_state_changed(NMDevice *device,
/* Device is now available for auto-activation */
nm_policy_device_recheck_auto_activate_schedule(self, device);
if (!nm_device_get_refresh_forwarding_done(device)) {
refresh_forwarding(self, device, FALSE);
nm_device_set_refresh_forwarding_done(device, TRUE);
}
break;
case NM_DEVICE_STATE_PREPARE:
@ -2528,10 +2450,6 @@ device_state_changed(NMDevice *device,
g_object_weak_unref(G_OBJECT(ac), pending_ac_gone, self);
g_object_unref(self);
}
if (!nm_device_get_refresh_forwarding_done(device)) {
refresh_forwarding(self, device, FALSE);
nm_device_set_refresh_forwarding_done(device, TRUE);
}
break;
case NM_DEVICE_STATE_IP_CONFIG:
/* We must have secrets if we got here. */
@ -2542,10 +2460,6 @@ device_state_changed(NMDevice *device,
sett_conn,
NM_SETTINGS_AUTOCONNECT_BLOCKED_REASON_FAILED,
FALSE);
if (!nm_device_get_refresh_forwarding_done(device)) {
refresh_forwarding(self, device, FALSE);
nm_device_set_refresh_forwarding_done(device, TRUE);
}
break;
case NM_DEVICE_STATE_SECONDARIES:
if (sett_conn)

View file

@ -186,6 +186,7 @@ ip_again:
00644,
NULL,
NULL,
NULL,
NULL);
nm_log_dbg(LOGD_PLATFORM, "dump to file complete");

View file

@ -123,7 +123,8 @@ software_add(NMLinkType link_type, const char *name)
gboolean bond0_exists = !!nm_platform_link_get_by_ifname(NM_PLATFORM_GET, "bond0");
int r;
const NMPlatformLnkBond nm_platform_lnk_bond_default = {
.mode = nmtst_rand_select(3, 1),
.mode = nmtst_rand_select(3, 1),
.use_carrier = 1,
};
r = nm_platform_link_bond_add(NM_PLATFORM_GET, name, &nm_platform_lnk_bond_default, NULL);

View file

@ -27,6 +27,19 @@
struct _NMSettingsPlugin;
/**
* NMSettingsStorage:
* @_plugin: The settings plugin that provides this storage.
* @_uuid: UUID of the profile represented by this storage.
* @_filename: Backing filename (can be NULL for in-memory or meta-data).
* @_storage_lst: Node in the per-plugin storage list.
* @_storage_by_uuid_lst: Node in the per-UUID storage list.
*
* Describes the origin and identity of one profile instance as provided by a
* specific settings plugin and (optionally) a backing file. A single UUID may
* have multiple storages from different plugins; plugin order determines
* priority.
*/
typedef struct NMSettingsStorage {
GObject parent;
struct _NMSettingsPlugin *_plugin;

View file

@ -76,6 +76,17 @@ static NM_CACHED_QUARK_FCN("default-wired-connection-blocked",
/*****************************************************************************/
/**
* StorageData:
* @sd_lst: Node used in per-UUID storage lists.
* @storage: Storage provider instance for this UUID.
* @connection: Connection object backed by @storage, or NULL for meta-data.
* @prioritize: Request to prioritize this storage during merge.
*
* Per-UUID storage entry used to accumulate and merge updates from plugins.
* Items live temporarily in the dirty list and are merged into the current list
* with stable priority ordering.
*/
typedef struct _StorageData {
CList sd_lst;
NMSettingsStorage *storage;
@ -165,6 +176,20 @@ _storage_data_is_alive(StorageData *sd)
/*****************************************************************************/
/**
* SettConnEntry:
* @uuid: Normalized UUID key for this entry (points to @_uuid_data).
* @sett_conn: Current NMSettingsConnection selected for @uuid, or NULL.
* @storage: The storage that currently owns @sett_conn, or NULL.
* @sd_lst_head: Head of current storages list for @uuid (high to low priority).
* @dirty_sd_lst_head: Head of pending storage updates to merge.
* @sce_dirty_lst: Node in the global dirty queue.
* @_uuid_data: Inline storage backing @uuid.
*
* Tracks one connection profile across all storages and its dirty state.
* It holds the authoritative in-memory connection and the sets of storages
* providing or updating it.
*/
typedef struct {
const char *uuid;
NMSettingsConnection *sett_conn;
@ -1368,10 +1393,11 @@ _connection_changed_track(NMSettings *self,
NMConnection *connection,
gboolean prioritize)
{
NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE(self);
SettConnEntry *sett_conn_entry;
StorageData *sd;
const char *uuid;
NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE(self);
SettConnEntry *sett_conn_entry;
StorageData *sd;
const char *uuid;
gs_free_error GError *error = NULL;
nm_assert_valid_settings_storage(NULL, storage);
@ -1382,6 +1408,17 @@ _connection_changed_track(NMSettings *self,
|| (_nm_connection_verify(connection, NULL) == NM_SETTING_VERIFY_SUCCESS));
nm_assert(!connection || nm_streq0(uuid, nm_connection_get_uuid(connection)));
if (connection && !nm_utils_connection_supported(connection, &error)) {
_LOGD("storage[%s," NM_SETTINGS_STORAGE_PRINT_FMT
"]: ignoring connection \"%s\" from file \"%s\": %s",
uuid,
NM_SETTINGS_STORAGE_PRINT_ARG(storage),
nm_connection_get_id(connection),
nm_settings_storage_get_filename(storage),
error->message);
connection = NULL;
}
nm_assert_connection_unchanging(connection);
sett_conn_entry =
@ -1851,6 +1888,9 @@ nm_settings_add_connection(NMSettings *self,
NM_SET_OUT(out_sett_conn, NULL);
if (!nm_utils_connection_supported(connection, error))
return FALSE;
uuid = nm_connection_get_uuid(connection);
sett_conn_entry = _sett_conn_entries_get(self, uuid);

View file

@ -77,7 +77,7 @@ get_full_file_path(const char *ifcfg_path, const char *file_path)
{
const char *base = file_path;
gs_free char *dirname = NULL;
char *p;
const char *p;
g_return_val_if_fail(ifcfg_path != NULL, NULL);
g_return_val_if_fail(file_path != NULL, NULL);

View file

@ -320,6 +320,7 @@ write_blobs(GHashTable *blobs, GError **error)
0600,
NULL,
NULL,
NULL,
&write_error)) {
g_set_error(error,
NM_SETTINGS_ERROR,
@ -3626,6 +3627,14 @@ do_write_construct(NMConnection *connection,
write_ip_routing_rules(connection, ifcfg, route_ignore);
if (nm_setting_connection_get_dnssec(s_con) != NM_SETTING_CONNECTION_DNSSEC_DEFAULT) {
set_error_unsupported(error,
connection,
NM_SETTING_CONNECTION_SETTING_NAME "." NM_SETTING_CONNECTION_DNSSEC,
TRUE);
return FALSE;
}
write_connection_setting(s_con, ifcfg, interface_name);
NM_SET_OUT(out_ifcfg, g_steal_pointer(&ifcfg));

View file

@ -280,6 +280,7 @@ nms_keyfile_nmmeta_write(const char *dirname,
length,
0600,
NULL,
NULL,
&errsv,
NULL)) {
NM_SET_OUT(out_full_filename, g_steal_pointer(&full_filename_tmp));

View file

@ -133,6 +133,7 @@ cert_writer(NMConnection *connection,
0600,
NULL,
NULL,
NULL,
&local);
if (success) {
/* Write the path value to the keyfile.
@ -384,7 +385,14 @@ _internal_write_connection(NMConnection *connection,
}
}
nm_utils_file_set_contents(path, kf_content_buf, kf_content_len, 0600, NULL, NULL, &local_err);
nm_utils_file_set_contents(path,
kf_content_buf,
kf_content_len,
0600,
NULL,
NULL,
NULL,
&local_err);
if (local_err) {
g_set_error(error,
NM_SETTINGS_ERROR,

View file

@ -8,6 +8,7 @@ timestamp=305415219
[gsm]
apn=internet2.voicestream.com
device-id=da812de91eec16620b06cd0ca5cbc7ea25245222
device-uid=MODEM1
home-only=true
network-id=254098
password=parliament2

View file

@ -1408,6 +1408,8 @@ test_write_gsm_connection(void)
"89148000000060671234",
NM_SETTING_GSM_SIM_OPERATOR_ID,
"310260",
NM_SETTING_GSM_DEVICE_UID,
"MODEM1",
NULL);
write_test_connection_and_reread(connection, TRUE, TEST_KEYFILES_DIR "/Test_Write_GSM");

View file

@ -30,6 +30,7 @@ typedef struct {
typedef struct {
GHashTable *config;
GHashTable *blobs;
char *private_user;
NMSupplCapMask capabilities;
guint32 ap_scan;
bool fast_required : 1;
@ -60,7 +61,7 @@ _get_capability(NMSupplicantConfigPrivate *priv, NMSupplCapType type)
}
NMSupplicantConfig *
nm_supplicant_config_new(NMSupplCapMask capabilities)
nm_supplicant_config_new(NMSupplCapMask capabilities, const char *private_user)
{
NMSupplicantConfigPrivate *priv;
NMSupplicantConfig *self;
@ -69,6 +70,7 @@ nm_supplicant_config_new(NMSupplCapMask capabilities)
priv = NM_SUPPLICANT_CONFIG_GET_PRIVATE(self);
priv->capabilities = capabilities;
priv->private_user = g_strdup(private_user);
return self;
}
@ -258,19 +260,19 @@ static gboolean
nm_supplicant_config_add_blob_for_connection(NMSupplicantConfig *self,
GBytes *field,
const char *name,
const char *con_uid,
const char *con_uuid,
GError **error)
{
if (field && g_bytes_get_size(field)) {
gs_free char *uid = NULL;
gs_free char *blob_id = NULL;
char *p;
uid = g_strdup_printf("%s-%s", con_uid, name);
for (p = uid; *p; p++) {
blob_id = g_strdup_printf("%s-%s", con_uuid, name);
for (p = blob_id; *p; p++) {
if (*p == '/')
*p = '-';
}
if (!nm_supplicant_config_add_blob(self, name, field, uid, error))
if (!nm_supplicant_config_add_blob(self, name, field, blob_id, error))
return FALSE;
}
return TRUE;
@ -283,6 +285,7 @@ nm_supplicant_config_finalize(GObject *object)
g_hash_table_destroy(priv->config);
nm_clear_pointer(&priv->blobs, g_hash_table_destroy);
nm_clear_pointer(&priv->private_user, g_free);
G_OBJECT_CLASS(nm_supplicant_config_parent_class)->finalize(object);
}
@ -930,6 +933,7 @@ nm_supplicant_config_add_setting_wireless_security(NMSupplicantConfig
guint32 mtu,
NMSettingWirelessSecurityPmf pmf,
NMSettingWirelessSecurityFils fils,
GHashTable *files,
GError **error)
{
NMSupplicantConfigPrivate *priv = NM_SUPPLICANT_CONFIG_GET_PRIVATE(self);
@ -1284,6 +1288,7 @@ nm_supplicant_config_add_setting_wireless_security(NMSupplicantConfig
con_uuid,
mtu,
FALSE,
files,
error))
return FALSE;
}
@ -1365,6 +1370,7 @@ nm_supplicant_config_add_setting_8021x(NMSupplicantConfig *self,
const char *con_uuid,
guint32 mtu,
gboolean wired,
GHashTable *files,
GError **error)
{
NMSupplicantConfigPrivate *priv;
@ -1594,24 +1600,21 @@ nm_supplicant_config_add_setting_8021x(NMSupplicantConfig *self,
}
/* CA certificate */
path = NULL;
bytes = NULL;
if (ca_cert_override) {
if (!add_string_val(self, ca_cert_override, "ca_cert", FALSE, NULL, error))
return FALSE;
/* This is a build-time-configured system-wide file path, no need to pass
* it as a blob */
path = ca_cert_override;
} else {
switch (nm_setting_802_1x_get_ca_cert_scheme(setting)) {
case NM_SETTING_802_1X_CK_SCHEME_BLOB:
bytes = nm_setting_802_1x_get_ca_cert_blob(setting);
if (!nm_supplicant_config_add_blob_for_connection(self,
bytes,
"ca_cert",
con_uuid,
error))
return FALSE;
break;
case NM_SETTING_802_1X_CK_SCHEME_PATH:
path = nm_setting_802_1x_get_ca_cert_path(setting);
if (!add_string_val(self, path, "ca_cert", FALSE, NULL, error))
return FALSE;
if (priv->private_user)
bytes = nm_g_hash_table_lookup(files, path);
break;
case NM_SETTING_802_1X_CK_SCHEME_PKCS11:
if (!add_pkcs11_uri_with_pin(self,
@ -1627,26 +1630,32 @@ nm_supplicant_config_add_setting_8021x(NMSupplicantConfig *self,
break;
}
}
if (bytes) {
if (!nm_supplicant_config_add_blob_for_connection(self, bytes, "ca_cert", con_uuid, error))
return FALSE;
} else if (path) {
/* Private connections cannot use paths other than the system CA store */
g_return_val_if_fail(ca_cert_override || !priv->private_user, FALSE);
if (!add_string_val(self, path, "ca_cert", FALSE, NULL, error))
return FALSE;
}
/* Phase 2 CA certificate */
path = NULL;
bytes = NULL;
if (ca_cert_override) {
if (!add_string_val(self, ca_cert_override, "ca_cert2", FALSE, NULL, error))
return FALSE;
/* This is a build-time-configured system-wide file path, no need to pass
* it as a blob */
path = ca_cert_override;
} else {
switch (nm_setting_802_1x_get_phase2_ca_cert_scheme(setting)) {
case NM_SETTING_802_1X_CK_SCHEME_BLOB:
bytes = nm_setting_802_1x_get_phase2_ca_cert_blob(setting);
if (!nm_supplicant_config_add_blob_for_connection(self,
bytes,
"ca_cert2",
con_uuid,
error))
return FALSE;
break;
case NM_SETTING_802_1X_CK_SCHEME_PATH:
path = nm_setting_802_1x_get_phase2_ca_cert_path(setting);
if (!add_string_val(self, path, "ca_cert2", FALSE, NULL, error))
return FALSE;
if (priv->private_user)
bytes = nm_g_hash_table_lookup(files, path);
break;
case NM_SETTING_802_1X_CK_SCHEME_PKCS11:
if (!add_pkcs11_uri_with_pin(
@ -1663,6 +1672,15 @@ nm_supplicant_config_add_setting_8021x(NMSupplicantConfig *self,
break;
}
}
if (bytes) {
if (!nm_supplicant_config_add_blob_for_connection(self, bytes, "ca_cert2", con_uuid, error))
return FALSE;
} else if (path) {
/* Private connections cannot use paths other than the system CA store */
g_return_val_if_fail(ca_cert_override || !priv->private_user, FALSE);
if (!add_string_val(self, path, "ca_cert2", FALSE, NULL, error))
return FALSE;
}
/* Subject match */
value = nm_setting_802_1x_get_subject_match(setting);
@ -1714,21 +1732,17 @@ nm_supplicant_config_add_setting_8021x(NMSupplicantConfig *self,
/* Private key */
added = FALSE;
path = NULL;
bytes = NULL;
switch (nm_setting_802_1x_get_private_key_scheme(setting)) {
case NM_SETTING_802_1X_CK_SCHEME_BLOB:
bytes = nm_setting_802_1x_get_private_key_blob(setting);
if (!nm_supplicant_config_add_blob_for_connection(self,
bytes,
"private_key",
con_uuid,
error))
return FALSE;
added = TRUE;
break;
case NM_SETTING_802_1X_CK_SCHEME_PATH:
path = nm_setting_802_1x_get_private_key_path(setting);
if (!add_string_val(self, path, "private_key", FALSE, NULL, error))
return FALSE;
if (priv->private_user)
bytes = nm_g_hash_table_lookup(files, path);
added = TRUE;
break;
case NM_SETTING_802_1X_CK_SCHEME_PKCS11:
@ -1745,6 +1759,19 @@ nm_supplicant_config_add_setting_8021x(NMSupplicantConfig *self,
default:
break;
}
if (bytes) {
if (!nm_supplicant_config_add_blob_for_connection(self,
bytes,
"private_key",
con_uuid,
error))
return FALSE;
} else if (path) {
/* Private connections cannot use paths */
g_return_val_if_fail(!priv->private_user, FALSE);
if (!add_string_val(self, path, "private_key", FALSE, NULL, error))
return FALSE;
}
if (added) {
NMSetting8021xCKFormat format;
@ -1768,20 +1795,16 @@ nm_supplicant_config_add_setting_8021x(NMSupplicantConfig *self,
/* Only add the client cert if the private key is not PKCS#12, as
* wpa_supplicant configuration directs us to do.
*/
path = NULL;
bytes = NULL;
switch (nm_setting_802_1x_get_client_cert_scheme(setting)) {
case NM_SETTING_802_1X_CK_SCHEME_BLOB:
bytes = nm_setting_802_1x_get_client_cert_blob(setting);
if (!nm_supplicant_config_add_blob_for_connection(self,
bytes,
"client_cert",
con_uuid,
error))
return FALSE;
break;
case NM_SETTING_802_1X_CK_SCHEME_PATH:
path = nm_setting_802_1x_get_client_cert_path(setting);
if (!add_string_val(self, path, "client_cert", FALSE, NULL, error))
return FALSE;
if (priv->private_user)
bytes = nm_g_hash_table_lookup(files, path);
break;
case NM_SETTING_802_1X_CK_SCHEME_PKCS11:
if (!add_pkcs11_uri_with_pin(
@ -1797,26 +1820,35 @@ nm_supplicant_config_add_setting_8021x(NMSupplicantConfig *self,
default:
break;
}
if (bytes) {
if (!nm_supplicant_config_add_blob_for_connection(self,
bytes,
"client_cert",
con_uuid,
error))
return FALSE;
} else if (path) {
/* Private connections cannot use paths */
g_return_val_if_fail(!priv->private_user, FALSE);
if (!add_string_val(self, path, "client_cert", FALSE, NULL, error))
return FALSE;
}
}
}
/* Phase 2 private key */
added = FALSE;
path = NULL;
bytes = NULL;
switch (nm_setting_802_1x_get_phase2_private_key_scheme(setting)) {
case NM_SETTING_802_1X_CK_SCHEME_BLOB:
bytes = nm_setting_802_1x_get_phase2_private_key_blob(setting);
if (!nm_supplicant_config_add_blob_for_connection(self,
bytes,
"private_key2",
con_uuid,
error))
return FALSE;
added = TRUE;
break;
case NM_SETTING_802_1X_CK_SCHEME_PATH:
path = nm_setting_802_1x_get_phase2_private_key_path(setting);
if (!add_string_val(self, path, "private_key2", FALSE, NULL, error))
return FALSE;
if (priv->private_user)
bytes = nm_g_hash_table_lookup(files, path);
added = TRUE;
break;
case NM_SETTING_802_1X_CK_SCHEME_PKCS11:
@ -1834,6 +1866,19 @@ nm_supplicant_config_add_setting_8021x(NMSupplicantConfig *self,
default:
break;
}
if (bytes) {
if (!nm_supplicant_config_add_blob_for_connection(self,
bytes,
"private_key2",
con_uuid,
error))
return FALSE;
} else if (path) {
/* Private connections cannot use paths */
g_return_val_if_fail(!priv->private_user, FALSE);
if (!add_string_val(self, path, "private_key2", FALSE, NULL, error))
return FALSE;
}
if (added) {
NMSetting8021xCKFormat format;
@ -1857,20 +1902,16 @@ nm_supplicant_config_add_setting_8021x(NMSupplicantConfig *self,
/* Only add the client cert if the private key is not PKCS#12, as
* wpa_supplicant configuration directs us to do.
*/
path = NULL;
bytes = NULL;
switch (nm_setting_802_1x_get_phase2_client_cert_scheme(setting)) {
case NM_SETTING_802_1X_CK_SCHEME_BLOB:
bytes = nm_setting_802_1x_get_phase2_client_cert_blob(setting);
if (!nm_supplicant_config_add_blob_for_connection(self,
bytes,
"client_cert2",
con_uuid,
error))
return FALSE;
break;
case NM_SETTING_802_1X_CK_SCHEME_PATH:
path = nm_setting_802_1x_get_phase2_client_cert_path(setting);
if (!add_string_val(self, path, "client_cert2", FALSE, NULL, error))
return FALSE;
if (priv->private_user)
bytes = nm_g_hash_table_lookup(files, path);
break;
case NM_SETTING_802_1X_CK_SCHEME_PKCS11:
if (!add_pkcs11_uri_with_pin(
@ -1886,6 +1927,19 @@ nm_supplicant_config_add_setting_8021x(NMSupplicantConfig *self,
default:
break;
}
if (bytes) {
if (!nm_supplicant_config_add_blob_for_connection(self,
bytes,
"client_cert2",
con_uuid,
error))
return FALSE;
} else if (path) {
/* Private connections cannot use paths */
g_return_val_if_fail(!priv->private_user, FALSE);
if (!add_string_val(self, path, "client_cert2", FALSE, NULL, error))
return FALSE;
}
}
}

View file

@ -29,7 +29,7 @@ typedef struct _NMSupplicantConfigClass NMSupplicantConfigClass;
GType nm_supplicant_config_get_type(void);
NMSupplicantConfig *nm_supplicant_config_new(NMSupplCapMask capabilities);
NMSupplicantConfig *nm_supplicant_config_new(NMSupplCapMask capabilities, const char *private_user);
guint32 nm_supplicant_config_get_ap_scan(NMSupplicantConfig *self);
@ -57,6 +57,7 @@ gboolean nm_supplicant_config_add_setting_wireless_security(NMSupplicantConfig
guint32 mtu,
NMSettingWirelessSecurityPmf pmf,
NMSettingWirelessSecurityFils fils,
GHashTable *files,
GError **error);
gboolean nm_supplicant_config_add_no_security(NMSupplicantConfig *self, GError **error);
@ -66,6 +67,7 @@ gboolean nm_supplicant_config_add_setting_8021x(NMSupplicantConfig *self,
const char *con_uuid,
guint32 mtu,
gboolean wired,
GHashTable *files,
GError **error);
gboolean nm_supplicant_config_add_setting_macsec(NMSupplicantConfig *self,

View file

@ -46,6 +46,7 @@ typedef struct {
gpointer user_data;
guint fail_on_idle_id;
guint blobs_left;
guint remove_blobs_left;
guint calls_left;
struct _AddNetworkData *add_network_data;
} AssocData;
@ -65,6 +66,8 @@ enum {
WPS_CREDENTIALS, /* WPS credentials received */
GROUP_STARTED, /* a new Group (interface) was created */
GROUP_FINISHED, /* a Group (interface) has been finished */
PSK_MISMATCH, /* supplicant reported incorrect PSK */
SAE_MISMATCH, /* supplicant reported incorrect SAE Password */
LAST_SIGNAL
};
@ -2264,6 +2267,7 @@ assoc_add_blob_cb(GObject *source, GAsyncResult *result, gpointer user_data)
return;
}
nm_assert(priv->assoc_data->blobs_left > 0);
priv->assoc_data->blobs_left--;
_LOGT("assoc[" NM_HASH_OBFUSCATE_PTR_FMT "]: blob added (%u left)",
NM_HASH_OBFUSCATE_PTR(priv->assoc_data),
@ -2272,6 +2276,148 @@ assoc_add_blob_cb(GObject *source, GAsyncResult *result, gpointer user_data)
assoc_call_select_network(self);
}
static void
assoc_add_blobs(NMSupplicantInterface *self)
{
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
GHashTable *blobs;
GHashTableIter iter;
const char *blob_name;
GBytes *blob_data;
blobs = nm_supplicant_config_get_blobs(priv->assoc_data->cfg);
priv->assoc_data->blobs_left = nm_g_hash_table_size(blobs);
_LOGT("assoc[" NM_HASH_OBFUSCATE_PTR_FMT "]: need to add %u blobs",
NM_HASH_OBFUSCATE_PTR(priv->assoc_data),
priv->assoc_data->blobs_left);
if (priv->assoc_data->blobs_left == 0) {
assoc_call_select_network(self);
return;
}
g_hash_table_iter_init(&iter, blobs);
while (g_hash_table_iter_next(&iter, (gpointer) &blob_name, (gpointer) &blob_data)) {
_LOGT("assoc[" NM_HASH_OBFUSCATE_PTR_FMT "]: adding blob '%s'",
NM_HASH_OBFUSCATE_PTR(priv->assoc_data),
blob_name);
_dbus_connection_call(
self,
NM_WPAS_DBUS_IFACE_INTERFACE,
"AddBlob",
g_variant_new("(s@ay)", blob_name, nm_g_bytes_to_variant_ay(blob_data)),
G_VARIANT_TYPE("()"),
G_DBUS_CALL_FLAGS_NONE,
DBUS_TIMEOUT_MSEC,
priv->assoc_data->cancellable,
assoc_add_blob_cb,
self);
}
}
static void
assoc_remove_blob_cb(GObject *source, GAsyncResult *result, gpointer user_data)
{
NMSupplicantInterface *self;
NMSupplicantInterfacePrivate *priv;
gs_free_error GError *error = NULL;
gs_unref_variant GVariant *res = NULL;
res = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), result, &error);
if (nm_utils_error_is_cancelled(error))
return;
self = NM_SUPPLICANT_INTERFACE(user_data);
priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
/* We don't consider a failure fatal. The new association might be able
* to proceed even with the existing blobs, if they don't conflict with new
* ones. */
nm_assert(priv->assoc_data->remove_blobs_left > 0);
priv->assoc_data->remove_blobs_left--;
if (error) {
g_dbus_error_strip_remote_error(error);
_LOGD("assoc[" NM_HASH_OBFUSCATE_PTR_FMT "]: failed to delete blob: %s",
NM_HASH_OBFUSCATE_PTR(priv->assoc_data),
error->message);
} else {
_LOGT("assoc[" NM_HASH_OBFUSCATE_PTR_FMT "]: blob removed (%u left)",
NM_HASH_OBFUSCATE_PTR(priv->assoc_data),
priv->assoc_data->remove_blobs_left);
}
if (priv->assoc_data->remove_blobs_left == 0)
assoc_add_blobs(self);
}
static void
assoc_get_blobs_cb(GObject *source, GAsyncResult *result, gpointer user_data)
{
NMSupplicantInterface *self;
NMSupplicantInterfacePrivate *priv;
gs_free_error GError *error = NULL;
gs_unref_variant GVariant *res = NULL;
gs_unref_variant GVariant *value = NULL;
GVariantIter iter;
const char *blob_name;
GVariant *blob_data;
res = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), result, &error);
if (nm_utils_error_is_cancelled(error))
return;
self = NM_SUPPLICANT_INTERFACE(user_data);
priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
if (error) {
_LOGD("assoc[" NM_HASH_OBFUSCATE_PTR_FMT "]: failed to get blob list: %s",
NM_HASH_OBFUSCATE_PTR(priv->assoc_data),
error->message);
assoc_add_blobs(self);
return;
}
g_variant_get(res, "(v)", &value);
/* While the "Blobs" property is documented as type "as", it is actually "a{say}" */
if (!value || !g_variant_is_of_type(value, G_VARIANT_TYPE("a{say}"))) {
_LOGD("assoc[" NM_HASH_OBFUSCATE_PTR_FMT "]: failed to get blob list: wrong return type %s",
NM_HASH_OBFUSCATE_PTR(priv->assoc_data),
value ? g_variant_get_type_string(value) : "NULL");
assoc_add_blobs(self);
return;
}
g_variant_iter_init(&iter, value);
priv->assoc_data->remove_blobs_left = g_variant_iter_n_children(&iter);
_LOGT("assoc[" NM_HASH_OBFUSCATE_PTR_FMT "]: need to delete %u blobs",
NM_HASH_OBFUSCATE_PTR(priv->assoc_data),
priv->assoc_data->remove_blobs_left);
if (priv->assoc_data->remove_blobs_left == 0) {
assoc_add_blobs(self);
} else {
while (g_variant_iter_loop(&iter, "{&s@ay}", &blob_name, &blob_data)) {
_LOGT("assoc[" NM_HASH_OBFUSCATE_PTR_FMT "]: removing blob '%s'",
NM_HASH_OBFUSCATE_PTR(priv->assoc_data),
blob_name);
_dbus_connection_call(self,
NM_WPAS_DBUS_IFACE_INTERFACE,
"RemoveBlob",
g_variant_new("(s)", blob_name),
G_VARIANT_TYPE("()"),
G_DBUS_CALL_FLAGS_NONE,
DBUS_TIMEOUT_MSEC,
priv->assoc_data->cancellable,
assoc_remove_blob_cb,
self);
}
}
}
static void
assoc_add_network_cb(GObject *source, GAsyncResult *result, gpointer user_data)
{
@ -2279,12 +2425,8 @@ assoc_add_network_cb(GObject *source, GAsyncResult *result, gpointer user_data)
AssocData *assoc_data;
NMSupplicantInterface *self;
NMSupplicantInterfacePrivate *priv;
gs_unref_variant GVariant *res = NULL;
gs_free_error GError *error = NULL;
GHashTable *blobs;
GHashTableIter iter;
const char *blob_name;
GBytes *blob_data;
gs_unref_variant GVariant *res = NULL;
gs_free_error GError *error = NULL;
nm_auto_ref_string NMRefString *name_owner = NULL;
nm_auto_ref_string NMRefString *object_path = NULL;
@ -2336,34 +2478,21 @@ assoc_add_network_cb(GObject *source, GAsyncResult *result, gpointer user_data)
nm_assert(!priv->net_path);
g_variant_get(res, "(o)", &priv->net_path);
/* Send blobs first; otherwise jump to selecting the network */
blobs = nm_supplicant_config_get_blobs(priv->assoc_data->cfg);
priv->assoc_data->blobs_left = blobs ? g_hash_table_size(blobs) : 0u;
_LOGT("assoc[" NM_HASH_OBFUSCATE_PTR_FMT "]: network added (%s) (%u blobs left)",
_LOGT("assoc[" NM_HASH_OBFUSCATE_PTR_FMT "]: network added (%s)",
NM_HASH_OBFUSCATE_PTR(priv->assoc_data),
priv->net_path,
priv->assoc_data->blobs_left);
priv->net_path);
if (priv->assoc_data->blobs_left == 0) {
assoc_call_select_network(self);
return;
}
g_hash_table_iter_init(&iter, blobs);
while (g_hash_table_iter_next(&iter, (gpointer) &blob_name, (gpointer) &blob_data)) {
_dbus_connection_call(
self,
NM_WPAS_DBUS_IFACE_INTERFACE,
"AddBlob",
g_variant_new("(s@ay)", blob_name, nm_g_bytes_to_variant_ay(blob_data)),
G_VARIANT_TYPE("()"),
G_DBUS_CALL_FLAGS_NONE,
DBUS_TIMEOUT_MSEC,
priv->assoc_data->cancellable,
assoc_add_blob_cb,
self);
}
/* Delete any existing blobs before adding new ones */
_dbus_connection_call(self,
DBUS_INTERFACE_PROPERTIES,
"Get",
g_variant_new("(ss)", NM_WPAS_DBUS_IFACE_INTERFACE, "Blobs"),
G_VARIANT_TYPE("(v)"),
G_DBUS_CALL_FLAGS_NONE,
DBUS_TIMEOUT_MSEC,
priv->assoc_data->cancellable,
assoc_get_blobs_cb,
self);
}
static void
@ -3105,6 +3234,15 @@ _signal_handle(NMSupplicantInterface *self,
return;
}
if (nm_streq(signal_name, "PskMismatch")) {
g_signal_emit(self, signals[PSK_MISMATCH], 0);
return;
}
if (nm_streq(signal_name, "SaePasswordMismatch")) {
g_signal_emit(self, signals[SAE_MISMATCH], 0);
return;
}
return;
}
@ -3737,4 +3875,23 @@ nm_supplicant_interface_class_init(NMSupplicantInterfaceClass *klass)
G_TYPE_NONE,
1,
G_TYPE_STRING);
signals[PSK_MISMATCH] = g_signal_new(NM_SUPPLICANT_INTERFACE_PSK_MISMATCH,
G_OBJECT_CLASS_TYPE(object_class),
G_SIGNAL_RUN_LAST,
0,
NULL,
NULL,
NULL,
G_TYPE_NONE,
0);
signals[SAE_MISMATCH] = g_signal_new(NM_SUPPLICANT_INTERFACE_SAE_MISMATCH,
G_OBJECT_CLASS_TYPE(object_class),
G_SIGNAL_RUN_LAST,
0,
NULL,
NULL,
NULL,
G_TYPE_NONE,
0);
}

View file

@ -86,6 +86,8 @@ typedef enum {
#define NM_SUPPLICANT_INTERFACE_WPS_CREDENTIALS "wps-credentials"
#define NM_SUPPLICANT_INTERFACE_GROUP_STARTED "group-started"
#define NM_SUPPLICANT_INTERFACE_GROUP_FINISHED "group-finished"
#define NM_SUPPLICANT_INTERFACE_PSK_MISMATCH "wpa-psk-mismatch"
#define NM_SUPPLICANT_INTERFACE_SAE_MISMATCH "wpa-sae-password-mismatch"
typedef struct _NMSupplicantInterfaceClass NMSupplicantInterfaceClass;

View file

@ -212,18 +212,19 @@ validate_type_utf8(const struct Opt *opt, const char *value, const guint32 len)
}
static gboolean
validate_type_keyword(const struct Opt *opt, const char *value, const guint32 len)
validate_type_keyword(const struct Opt *opt, const char *value_in, const guint32 len)
{
gs_free char *value_free = NULL;
char *value;
nm_assert(opt);
nm_assert(value);
nm_assert(value_in);
/* Allow everything */
if (!opt->str_allowed)
return TRUE;
value = nm_strndup_a(300, value, len, &value_free);
value = nm_strndup_a(300, value_in, len, &value_free);
/* validate each space-separated word in 'value' */

View file

@ -98,7 +98,8 @@ build_supplicant_config(NMConnection *connection,
NMSetting8021x *s_8021x;
gboolean success;
config = nm_supplicant_config_new(capabilities);
config = nm_supplicant_config_new(capabilities,
nm_utils_get_connection_first_permissions_user(connection));
s_wifi = nm_connection_get_setting_wireless(connection);
g_assert(s_wifi);
@ -120,6 +121,7 @@ build_supplicant_config(NMConnection *connection,
mtu,
pmf,
fils,
NULL,
&error);
} else {
success = nm_supplicant_config_add_no_security(config, &error);

View file

@ -260,6 +260,70 @@ test_shorten_hostname(void)
do_test_shorten_hostname(".name1", FALSE, NULL);
}
/*****************************************************************************/
typedef struct {
NMRateLimit ratelimit;
GMainLoop *loop;
GSource *source;
guint num;
} RateLimitData;
static int
rate_limit_window_expire_cb(gpointer user_data)
{
RateLimitData *data = user_data;
g_assert(nm_rate_limit_check(&data->ratelimit, 1, 5));
g_assert(nm_rate_limit_check(&data->ratelimit, 1, 5));
g_assert(nm_rate_limit_check(&data->ratelimit, 1, 5));
g_assert(nm_rate_limit_check(&data->ratelimit, 1, 5));
g_assert(nm_rate_limit_check(&data->ratelimit, 1, 5));
g_assert(!nm_rate_limit_check(&data->ratelimit, 1, 5));
g_assert(!nm_rate_limit_check(&data->ratelimit, 1, 5));
nm_clear_g_source_inst(&data->source);
g_main_loop_quit(data->loop);
return G_SOURCE_CONTINUE;
}
static int
rate_limit_check_cb(gpointer user_data)
{
RateLimitData *data = user_data;
g_assert(nm_rate_limit_check(&data->ratelimit, 1, 5));
g_assert(nm_rate_limit_check(&data->ratelimit, 1, 5));
g_assert(nm_rate_limit_check(&data->ratelimit, 1, 5));
g_assert(nm_rate_limit_check(&data->ratelimit, 1, 5));
g_assert(nm_rate_limit_check(&data->ratelimit, 1, 5));
g_assert(!nm_rate_limit_check(&data->ratelimit, 1, 5));
g_assert(!nm_rate_limit_check(&data->ratelimit, 1, 5));
nm_clear_g_source_inst(&data->source);
data->source = nm_g_timeout_add_source(1000, rate_limit_window_expire_cb, data);
return G_SOURCE_CONTINUE;
}
static void
test_rate_limit_check(void)
{
RateLimitData data;
data = (RateLimitData) {
.loop = g_main_loop_new(NULL, FALSE),
.ratelimit = {},
.source = nm_g_timeout_add_source(1, rate_limit_check_cb, &data),
.num = 0,
};
g_main_loop_run(data.loop);
g_main_loop_unref(data.loop);
}
/*****************************************************************************/
NMTST_DEFINE();
@ -272,6 +336,7 @@ main(int argc, char **argv)
g_test_add_func("/utils/stable_privacy", test_stable_privacy);
g_test_add_func("/utils/hw_addr_gen_stable_eth", test_hw_addr_gen_stable_eth);
g_test_add_func("/utils/shorten-hostname", test_shorten_hostname);
g_test_add_func("/utils/rate-limit-check", test_rate_limit_check);
return g_test_run();
}

View file

@ -26,10 +26,12 @@
#include "nm-active-connection.h"
#include "nm-config.h"
#include "nm-dbus-manager.h"
#include "devices/nm-device.h"
#include "nm-dispatcher.h"
#include "nm-firewalld-manager.h"
#include "nm-ip-config.h"
#include "nm-l3-config-data.h"
#include "nm-manager.h"
#include "nm-netns.h"
#include "nm-pacrunner-manager.h"
#include "nm-vpn-manager.h"
@ -1409,9 +1411,11 @@ _check_complete(NMVpnConnection *self, gboolean success)
NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(self);
nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL;
NMConnection *connection;
NMDevice *device;
NMSettingConnection *s_con;
const char *zone;
const char *iface;
int ifindex;
if (priv->vpn_state < STATE_IP_CONFIG_GET || priv->vpn_state > STATE_ACTIVATED)
return;
@ -1437,10 +1441,23 @@ _check_complete(NMVpnConnection *self, gboolean success)
}
connection = _get_applied_connection(self);
l3cd = nm_l3_config_data_new_from_connection(nm_netns_get_multi_idx(priv->netns),
nm_vpn_connection_get_ip_ifindex(self, TRUE),
connection);
ifindex = nm_vpn_connection_get_ip_ifindex(self, FALSE);
/* Use nm_device_create_l3_config_data_from_connection here if possible. This ensures that
* connection properties like mdns, llmnr, dns-over-tls or dnssec are applied to vpn connections
* If this vpn connection does not have its own device resort to nm_l3_config_data_new_from_connection
* since we can't properly apply these properties anyway
*/
if (ifindex > 0) {
device = nm_manager_get_device_by_ifindex(NM_MANAGER_GET, ifindex);
nm_assert(device);
l3cd = nm_device_create_l3_config_data_from_connection(device, connection);
} else {
l3cd = nm_l3_config_data_new_from_connection(nm_netns_get_multi_idx(priv->netns),
nm_vpn_connection_get_ip_ifindex(self, TRUE),
connection);
_LOGD("VPN connection does not have its own device. Some connection properties won't be "
"supported.");
}
nm_l3_config_data_set_allow_routes_without_address(l3cd, AF_INET, TRUE);
nm_l3_config_data_set_allow_routes_without_address(l3cd, AF_INET6, TRUE);

View file

@ -60,16 +60,21 @@ nm_vpn_manager_activate_connection(NMVpnManager *manager, NMVpnConnection *vpn,
{
NMVpnManagerPrivate *priv;
NMVpnPluginInfo *plugin_info;
NMConnection *applied;
const char *service_name;
NMDevice *device;
const char *user;
g_return_val_if_fail(NM_IS_VPN_MANAGER(manager), FALSE);
g_return_val_if_fail(NM_IS_VPN_CONNECTION(vpn), FALSE);
g_return_val_if_fail(!error || !*error, FALSE);
priv = NM_VPN_MANAGER_GET_PRIVATE(manager);
device = nm_active_connection_get_device(NM_ACTIVE_CONNECTION(vpn));
g_assert(device);
priv = NM_VPN_MANAGER_GET_PRIVATE(manager);
device = nm_active_connection_get_device(NM_ACTIVE_CONNECTION(vpn));
applied = nm_active_connection_get_applied_connection(NM_ACTIVE_CONNECTION(vpn));
nm_assert(device);
nm_assert(applied);
if (nm_device_get_state(device) != NM_DEVICE_STATE_ACTIVATED
&& nm_device_get_state(device) != NM_DEVICE_STATE_SECONDARIES) {
g_set_error_literal(error,
@ -101,6 +106,30 @@ nm_vpn_manager_activate_connection(NMVpnManager *manager, NMVpnConnection *vpn,
return FALSE;
}
user = nm_utils_get_connection_first_permissions_user(applied);
if (user) {
NMSettingConnection *s_con;
s_con = nm_connection_get_setting_connection(applied);
nm_assert(s_con);
if (_nm_setting_connection_get_num_permissions_users(s_con) > 1) {
g_set_error_literal(error,
NM_MANAGER_ERROR,
NM_MANAGER_ERROR_CONNECTION_NOT_AVAILABLE,
"private VPN connections with multiple users are not allowed.");
return FALSE;
}
if (!nm_vpn_plugin_info_supports_safe_private_file_access(plugin_info)) {
g_set_error(error,
NM_MANAGER_ERROR,
NM_MANAGER_ERROR_CONNECTION_NOT_AVAILABLE,
"The '%s' plugin doesn't support private connections.",
nm_vpn_plugin_info_get_name(plugin_info));
return FALSE;
}
}
nm_vpn_connection_activate(vpn, plugin_info);
if (!nm_vpn_plugin_info_supports_multiple(plugin_info)) {

View file

@ -65,6 +65,7 @@
#define NM_CONFIG_KEYFILE_KEY_DEVICE_MANAGED "managed"
#define NM_CONFIG_KEYFILE_KEY_DEVICE_IGNORE_CARRIER "ignore-carrier"
#define NM_CONFIG_KEYFILE_KEY_DEVICE_CHECK_CONNECTIVITY "check-connectivity"
#define NM_CONFIG_KEYFILE_KEY_DEVICE_SRIOV_NUM_VFS "sriov-num-vfs"
#define NM_CONFIG_KEYFILE_KEY_DEVICE_KEEP_CONFIGURATION "keep-configuration"
#define NM_CONFIG_KEYFILE_KEY_DEVICE_ALLOWED_CONNECTIONS "allowed-connections"

View file

@ -2077,7 +2077,19 @@ global:
nm_sriov_preserve_on_down_get_type;
} libnm_1_52_0;
libnm_1_54_2 {
global:
nm_setting_hsr_get_interlink;
nm_setting_hsr_get_protocol_version;
nm_setting_hsr_protocol_version_get_type;
} libnm_1_54_0;
libnm_1_56_0 {
global:
nm_dns_server_validate;
nm_setting_gsm_get_device_uid;
nm_setting_connection_get_dnssec;
nm_setting_connection_dnssec_get_type;
nm_utils_copy_cert_as_user;
nm_vpn_plugin_info_supports_safe_private_file_access;
} libnm_1_54_0;

View file

@ -5,6 +5,7 @@ test_units = [
'test-nm-client',
'test-remote-settings-client',
'test-secret-agent',
'test-copy-cert-as-user'
]
foreach test_unit: test_units
@ -37,12 +38,15 @@ foreach test_unit: test_units
],
)
test(
'src/libnm-client-impl/tests/' + test_unit,
test_script,
timeout: 90,
args: test_args + [exe.full_path()],
)
# test-copy-cert-as-user is a manual test, don't run it automatically
if test_unit != 'test-copy-cert-as-user'
test(
'src/libnm-client-impl/tests/' + test_unit,
test_script,
timeout: 90,
args: test_args + [exe.full_path()],
)
endif
endforeach
if enable_introspection

View file

@ -0,0 +1,32 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
* This is a program to manually test the
* nm_utils_copy_cert_as_user() libnm function.
*/
#include "libnm-client-impl/nm-default-libnm.h"
#include "nm-utils.h"
int
main(int argc, char **argv)
{
gs_free_error GError *error = NULL;
gs_free char *filename = NULL;
if (argc != 3) {
g_printerr("Usage: %s <FILE> <USER>\n", argv[0]);
return 1;
}
filename = nm_utils_copy_cert_as_user(argv[1], argv[2], &error);
if (!filename) {
g_printerr("Error: %s\n", error->message);
return 1;
}
g_print("%s\n", filename);
return 0;
}

View file

@ -2756,6 +2756,8 @@ test_types(void)
G(nm_setting_connection_lldp_get_type),
G(nm_setting_connection_llmnr_get_type),
G(nm_setting_connection_mdns_get_type),
G(nm_setting_connection_dns_over_tls_get_type),
G(nm_setting_connection_dnssec_get_type),
G(nm_setting_dcb_flags_get_type),
G(nm_setting_dcb_get_type),
G(nm_setting_diff_result_get_type),

View file

@ -483,8 +483,8 @@ nm_utils_validate_shared_dhcp_range(const char *shared_dhcp_range,
GPtrArray *addresses,
GError **error)
{
char *start_address_str;
char *end_address_str;
const char *start_address_str;
const char *end_address_str;
NMIPAddress *interface_address_with_prefix;
NMIPAddr interface_address;
NMIPAddr start_address;
@ -825,7 +825,7 @@ nm_dns_uri_parse(int addr_family, const char *str, NMDnsServer *dns, GError **er
addr = nm_strndup_a(100, addr_port, end - addr_port, &addr_heap);
/* IPv6 link-local scope-id */
perc = strchr(addr, '%');
perc = (char *) strchr(addr, '%');
if (perc) {
*perc = '\0';
if (g_strlcpy(dns->interface, perc + 1, sizeof(dns->interface))

View file

@ -300,13 +300,15 @@ gpointer _nm_connection_new_setting(NMConnection *connection, GType gtype);
/*****************************************************************************/
#define _NM_MPTCP_FLAGS_ALL \
((NMMptcpFlags) (NM_MPTCP_FLAGS_DISABLED | NM_MPTCP_FLAGS_ENABLED \
| NM_MPTCP_FLAGS_ALSO_WITHOUT_SYSCTL \
| NM_MPTCP_FLAGS_ALSO_WITHOUT_DEFAULT_ROUTE | NM_MPTCP_FLAGS_SIGNAL \
| NM_MPTCP_FLAGS_SUBFLOW | NM_MPTCP_FLAGS_BACKUP | NM_MPTCP_FLAGS_FULLMESH))
#define _NM_MPTCP_FLAGS_ALL \
((NMMptcpFlags) (NM_MPTCP_FLAGS_DISABLED | NM_MPTCP_FLAGS_ENABLED \
| NM_MPTCP_FLAGS_ALSO_WITHOUT_SYSCTL \
| NM_MPTCP_FLAGS_ALSO_WITHOUT_DEFAULT_ROUTE | NM_MPTCP_FLAGS_SIGNAL \
| NM_MPTCP_FLAGS_SUBFLOW | NM_MPTCP_FLAGS_BACKUP | NM_MPTCP_FLAGS_FULLMESH \
| NM_MPTCP_FLAGS_LAMINAR))
#define _NM_MPTCP_FLAGS_DEFAULT ((NMMptcpFlags) (NM_MPTCP_FLAGS_ENABLED | NM_MPTCP_FLAGS_SUBFLOW))
#define _NM_MPTCP_FLAGS_DEFAULT \
((NMMptcpFlags) (NM_MPTCP_FLAGS_ENABLED | NM_MPTCP_FLAGS_SUBFLOW | NM_MPTCP_FLAGS_LAMINAR))
NMMptcpFlags nm_mptcp_flags_normalize(NMMptcpFlags flags);

View file

@ -810,6 +810,10 @@
dbus-type="i"
gprop-type="gint"
/>
<property name="dnssec"
dbus-type="i"
gprop-type="gint"
/>
<property name="down-on-poweroff"
dbus-type="i"
gprop-type="gint"
@ -1393,6 +1397,10 @@
dbus-type="s"
gprop-type="gchararray"
/>
<property name="device-uid"
dbus-type="s"
gprop-type="gchararray"
/>
<property name="home-only"
dbus-type="b"
gprop-type="gboolean"
@ -1516,6 +1524,10 @@
<setting name="hsr"
gtype="NMSettingHsr"
>
<property name="interlink"
dbus-type="s"
gprop-type="gchararray"
/>
<property name="multicast-spec"
dbus-type="u"
gprop-type="guint"
@ -1528,6 +1540,10 @@
dbus-type="s"
gprop-type="gchararray"
/>
<property name="protocol-version"
dbus-type="i"
gprop-type="gint"
/>
<property name="prp"
dbus-type="b"
gprop-type="gboolean"

View file

@ -3133,6 +3133,86 @@ need_secrets(NMSetting *setting, gboolean check_rerequest)
/*****************************************************************************/
static void
get_private_files(NMSetting *setting, GPtrArray *files)
{
const struct {
const char *property;
NMSetting8021xCKScheme (*get_scheme_func)(NMSetting8021x *);
const char *(*get_path_func)(NMSetting8021x *);
} cert_props[] = {
{NM_SETTING_802_1X_CA_CERT,
nm_setting_802_1x_get_ca_cert_scheme,
nm_setting_802_1x_get_ca_cert_path},
{NM_SETTING_802_1X_CLIENT_CERT,
nm_setting_802_1x_get_client_cert_scheme,
nm_setting_802_1x_get_client_cert_path},
{NM_SETTING_802_1X_PRIVATE_KEY,
nm_setting_802_1x_get_private_key_scheme,
nm_setting_802_1x_get_private_key_path},
{NM_SETTING_802_1X_PHASE2_CA_CERT,
nm_setting_802_1x_get_phase2_ca_cert_scheme,
nm_setting_802_1x_get_phase2_ca_cert_path},
{NM_SETTING_802_1X_PHASE2_CLIENT_CERT,
nm_setting_802_1x_get_phase2_client_cert_scheme,
nm_setting_802_1x_get_phase2_client_cert_path},
{NM_SETTING_802_1X_PHASE2_PRIVATE_KEY,
nm_setting_802_1x_get_phase2_private_key_scheme,
nm_setting_802_1x_get_phase2_private_key_path},
};
NMSetting8021x *s_8021x = NM_SETTING_802_1X(setting);
const char *path;
guint i;
if (NM_MORE_ASSERT_ONCE(5)) {
GObjectClass *klass;
gs_free GParamSpec **properties = NULL;
guint n_properties;
gboolean found;
guint j;
/* Check that all the properties in the setting with flag CERT_KEY_FILE
* are listed in the table, and vice versa. */
klass = G_OBJECT_GET_CLASS(setting);
properties = g_object_class_list_properties(klass, &n_properties);
for (i = 0; i < n_properties; i++) {
if (!(properties[i]->flags & NM_SETTING_PARAM_CERT_KEY_FILE))
continue;
found = FALSE;
for (j = 0; j < G_N_ELEMENTS(cert_props); j++) {
if (nm_streq0(properties[i]->name, cert_props[j].property)) {
found = TRUE;
break;
}
}
nm_assert(found);
}
for (i = 0; i < G_N_ELEMENTS(cert_props); i++) {
GParamSpec *prop;
prop = g_object_class_find_property(klass, cert_props[i].property);
nm_assert(prop);
nm_assert(prop->flags & NM_SETTING_PARAM_CERT_KEY_FILE);
}
}
for (i = 0; i < G_N_ELEMENTS(cert_props); i++) {
if (cert_props[i].get_scheme_func(s_8021x) == NM_SETTING_802_1X_CK_SCHEME_PATH) {
path = cert_props[i].get_path_func(s_8021x);
if (path) {
g_ptr_array_add(files, (gpointer) path);
}
}
}
}
/*****************************************************************************/
static void
get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
{
@ -3223,8 +3303,9 @@ nm_setting_802_1x_class_init(NMSetting8021xClass *klass)
object_class->set_property = set_property;
object_class->finalize = finalize;
setting_class->verify = verify;
setting_class->need_secrets = need_secrets;
setting_class->verify = verify;
setting_class->need_secrets = need_secrets;
setting_class->get_private_files = get_private_files;
/**
* NMSetting8021x:eap:
@ -3359,7 +3440,7 @@ nm_setting_802_1x_class_init(NMSetting8021xClass *klass)
obj_properties,
NM_SETTING_802_1X_CA_CERT,
PROP_CA_CERT,
NM_SETTING_PARAM_NONE,
NM_SETTING_PARAM_CERT_KEY_FILE,
NMSetting8021xPrivate,
ca_cert);
@ -3556,7 +3637,7 @@ nm_setting_802_1x_class_init(NMSetting8021xClass *klass)
obj_properties,
NM_SETTING_802_1X_CLIENT_CERT,
PROP_CLIENT_CERT,
NM_SETTING_PARAM_NONE,
NM_SETTING_PARAM_CERT_KEY_FILE,
NMSetting8021xPrivate,
client_cert);
@ -3803,7 +3884,7 @@ nm_setting_802_1x_class_init(NMSetting8021xClass *klass)
obj_properties,
NM_SETTING_802_1X_PHASE2_CA_CERT,
PROP_PHASE2_CA_CERT,
NM_SETTING_PARAM_NONE,
NM_SETTING_PARAM_CERT_KEY_FILE,
NMSetting8021xPrivate,
phase2_ca_cert);
@ -4006,7 +4087,7 @@ nm_setting_802_1x_class_init(NMSetting8021xClass *klass)
obj_properties,
NM_SETTING_802_1X_PHASE2_CLIENT_CERT,
PROP_PHASE2_CLIENT_CERT,
NM_SETTING_PARAM_NONE,
NM_SETTING_PARAM_CERT_KEY_FILE,
NMSetting8021xPrivate,
phase2_client_cert);
@ -4175,7 +4256,7 @@ nm_setting_802_1x_class_init(NMSetting8021xClass *klass)
obj_properties,
NM_SETTING_802_1X_PRIVATE_KEY,
PROP_PRIVATE_KEY,
NM_SETTING_PARAM_NONE,
NM_SETTING_PARAM_CERT_KEY_FILE,
NMSetting8021xPrivate,
private_key);
@ -4276,7 +4357,7 @@ nm_setting_802_1x_class_init(NMSetting8021xClass *klass)
obj_properties,
NM_SETTING_802_1X_PHASE2_PRIVATE_KEY,
PROP_PHASE2_PRIVATE_KEY,
NM_SETTING_PARAM_NONE,
NM_SETTING_PARAM_CERT_KEY_FILE,
NMSetting8021xPrivate,
phase2_private_key);

View file

@ -472,17 +472,17 @@ nm_bridge_vlan_to_str(const NMBridgeVlan *vlan, GError **error)
NMBridgeVlan *
nm_bridge_vlan_from_str(const char *str, GError **error)
{
NMBridgeVlan *vlan = NULL;
gs_free const char **tokens = NULL;
guint i, vid_start, vid_end = 0;
gboolean pvid = FALSE;
gboolean untagged = FALSE;
char *c;
NMBridgeVlan *vlan = NULL;
gs_free char **tokens = NULL;
guint i, vid_start, vid_end = 0;
gboolean pvid = FALSE;
gboolean untagged = FALSE;
char *c;
g_return_val_if_fail(str, NULL);
g_return_val_if_fail(!error || !*error, NULL);
tokens = nm_utils_escaped_tokens_split(str, NM_ASCII_SPACES);
tokens = (char **) nm_utils_escaped_tokens_split(str, NM_ASCII_SPACES);
if (!tokens || !tokens[0]) {
g_set_error_literal(error,
NM_CONNECTION_ERROR,

View file

@ -71,6 +71,7 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMSettingConnection,
PROP_MDNS,
PROP_LLMNR,
PROP_DNS_OVER_TLS,
PROP_DNSSEC,
PROP_MPTCP_FLAGS,
PROP_STABLE_ID,
PROP_AUTH_RETRIES,
@ -103,6 +104,7 @@ typedef struct {
gint32 mdns;
gint32 llmnr;
gint32 dns_over_tls;
gint32 dnssec;
gint32 wait_device_timeout;
gint32 lldp;
gint32 wait_activation_delay;
@ -431,6 +433,47 @@ nm_setting_connection_permissions_user_allowed_by_uid(NMSettingConnection *setti
return _permissions_user_allowed(setting, NULL, uid);
}
guint
_nm_setting_connection_get_num_permissions_users(NMSettingConnection *setting)
{
NMSettingConnectionPrivate *priv;
guint i;
guint count = 0;
nm_assert(NM_IS_SETTING_CONNECTION(setting));
priv = NM_SETTING_CONNECTION_GET_PRIVATE(setting);
for (i = 0; priv->permissions && i < priv->permissions->len; i++) {
const Permission *permission = &nm_g_array_index(priv->permissions, Permission, i);
if (permission->ptype == PERM_TYPE_USER) {
count++;
}
}
return count;
}
const char *
_nm_setting_connection_get_first_permissions_user(NMSettingConnection *setting)
{
NMSettingConnectionPrivate *priv;
guint i;
nm_assert(NM_IS_SETTING_CONNECTION(setting));
priv = NM_SETTING_CONNECTION_GET_PRIVATE(setting);
for (i = 0; priv->permissions && i < priv->permissions->len; i++) {
const Permission *permission = &nm_g_array_index(priv->permissions, Permission, i);
if (permission->ptype == PERM_TYPE_USER) {
return permission->item;
}
}
return NULL;
}
/**
* nm_setting_connection_add_permission:
* @setting: the #NMSettingConnection
@ -1293,6 +1336,22 @@ nm_setting_connection_get_dns_over_tls(NMSettingConnection *setting)
return NM_SETTING_CONNECTION_GET_PRIVATE(setting)->dns_over_tls;
}
/**
* nm_setting_connection_get_dnssec:
* @setting: the #NMSettingConnection
*
* Returns: the #NMSettingConnection:dnssec property of the setting.
*
* Since: 1.56
**/
NMSettingConnectionDnssec
nm_setting_connection_get_dnssec(NMSettingConnection *setting)
{
g_return_val_if_fail(NM_IS_SETTING_CONNECTION(setting), NM_SETTING_CONNECTION_DNSSEC_DEFAULT);
return NM_SETTING_CONNECTION_GET_PRIVATE(setting)->dnssec;
}
/**
* nm_setting_connection_get_mptcp_flags:
* @setting: the #NMSettingConnection
@ -3406,6 +3465,33 @@ nm_setting_connection_class_init(NMSettingConnectionClass *klass)
NMSettingConnectionPrivate,
dns_over_tls);
/**
* NMSettingConnection:dnssec:
*
* Whether DNSSEC (dnssec) is enabled for the connection.
*
* The permitted values are: "yes" (2) use DNSSEC and disable fallback,
* "allow-downgrade" (1) use DNSSEC but allow fallback if the server does not support it,
* "no" (0) don't ever use DNSSEC.
* The effect of "default" (-1) depends on the dns plugin used.
* Systemd-resolved uses its global setting in this case.
*
* This feature requires a plugin which supports DNSSEC. Otherwise, the
* setting has no effect. One such plugin is systemd-resolved.
*
* Since: 1.56
**/
_nm_setting_property_define_direct_enum(properties_override,
obj_properties,
NM_SETTING_CONNECTION_DNSSEC,
PROP_DNSSEC,
NM_TYPE_SETTING_CONNECTION_DNSSEC,
NM_SETTING_CONNECTION_DNSSEC_DEFAULT,
NM_SETTING_PARAM_NONE,
NULL,
NMSettingConnectionPrivate,
dnssec);
/* Notes about "mptcp-flags":
*
* It is a bit odd that NMMptcpFlags mixes flags with different purposes:
@ -3413,7 +3499,7 @@ nm_setting_connection_class_init(NMSettingConnectionClass *klass)
* - "disabled", "disabled-on-local-iface", "enable": whether MPTCP handling
* is enabled. The flag "disabled-on-local-iface" enables it based on whether
* the interface has a default route.
* - "signal", "subflow", "backup", "fullmesh": the endpoint flags
* - "signal", "subflow", "backup", "fullmesh", "laminar": the endpoint flags
* that are used.
*
* The reason is, that it is useful to have one "connection.mptcp-flags"
@ -3473,7 +3559,8 @@ nm_setting_connection_class_init(NMSettingConnectionClass *klass)
*
* When MPTCP handling is enabled then endpoints are configured with
* the specified address flags "signal" (0x10), "subflow" (0x20), "backup" (0x40),
* "fullmesh" (0x80). See ip-mptcp(8) manual for additional information about the flags.
* "fullmesh" (0x80), "laminar" (0x100). See ip-mptcp(8) manual for
* additional information about the flags.
*
* If the flags are zero (0x0), the global connection default from NetworkManager.conf is
* honored. If still unspecified, the fallback is "enabled,subflow".

View file

@ -47,7 +47,8 @@ NM_GOBJECT_PROPERTIES_DEFINE_BASE(PROP_AUTO_CONFIG,
PROP_INITIAL_EPS_REFUSE_PAP,
PROP_INITIAL_EPS_REFUSE_CHAP,
PROP_INITIAL_EPS_REFUSE_MSCHAP,
PROP_INITIAL_EPS_REFUSE_MSCHAPV2, );
PROP_INITIAL_EPS_REFUSE_MSCHAPV2,
PROP_DEVICE_UID, );
typedef struct {
char *number;
@ -75,6 +76,7 @@ typedef struct {
bool auto_config;
bool home_only;
bool initial_eps_config;
char *device_uid;
} NMSettingGsmPrivate;
/**
@ -465,6 +467,22 @@ nm_setting_gsm_get_initial_eps_refuse_mschapv2(NMSettingGsm *setting)
return NM_SETTING_GSM_GET_PRIVATE(setting)->initial_eps_refuse_mschapv2;
}
/**
* nm_setting_gsm_get_device_uid:
* @setting: the #NMSettingGsm
*
* Returns: the #NMSettingGsm:device-uid property of the setting
*
* Since: 1.56
**/
const char *
nm_setting_gsm_get_device_uid(NMSettingGsm *setting)
{
g_return_val_if_fail(NM_IS_SETTING_GSM(setting), NULL);
return NM_SETTING_GSM_GET_PRIVATE(setting)->device_uid;
}
static gboolean
_verify_apn(const char *apn, gboolean allow_empty, const char *property_name, GError **error)
{
@ -1149,6 +1167,26 @@ nm_setting_gsm_class_init(NMSettingGsmClass *klass)
NMSettingGsmPrivate,
initial_eps_refuse_mschapv2);
/**
* NMSettingGsm:device-uid:
*
* The device UID (as given by the WWAN management service) which this
* connection applies to. In contrast to #NMSettingGsm:device-id, which is
* an inherent property of the connected device, this setting refers to
* a property set by a UDEV-rule. Refer to the "Common udev tags" ->
* "ID_MM_PHYSDEV_UID" documentation of ModemManager. If given, the
* connection will only apply to the specified device.
*
* Since: 1.56
**/
_nm_setting_property_define_direct_string(properties_override,
obj_properties,
NM_SETTING_GSM_DEVICE_UID,
PROP_DEVICE_UID,
NM_SETTING_PARAM_NONE,
NMSettingGsmPrivate,
device_uid);
/* Ignore incoming deprecated properties */
_nm_properties_override_dbus(properties_override,
"allowed-bands",

View file

@ -23,12 +23,20 @@
/*****************************************************************************/
NM_GOBJECT_PROPERTIES_DEFINE(NMSettingHsr, PROP_PORT1, PROP_PORT2, PROP_MULTICAST_SPEC, PROP_PRP, );
NM_GOBJECT_PROPERTIES_DEFINE(NMSettingHsr,
PROP_PORT1,
PROP_PORT2,
PROP_MULTICAST_SPEC,
PROP_PRP,
PROP_PROTOCOL_VERSION,
PROP_INTERLINK, );
typedef struct {
char *port1;
char *port2;
char *interlink;
guint32 multicast_spec;
int protocol_version;
bool prp;
} NMSettingHsrPrivate;
@ -117,6 +125,38 @@ nm_setting_hsr_get_prp(NMSettingHsr *setting)
return NM_SETTING_HSR_GET_PRIVATE(setting)->prp;
}
/**
* nm_setting_hsr_get_protocol_version:
* @setting: the #NMSettingHsr
*
* Returns: the #NMSettingHsr:protocol-version property of the setting
*
* Since: 1.56
**/
NMSettingHsrProtocolVersion
nm_setting_hsr_get_protocol_version(NMSettingHsr *setting)
{
g_return_val_if_fail(NM_IS_SETTING_HSR(setting), NM_SETTING_HSR_PROTOCOL_VERSION_DEFAULT);
return NM_SETTING_HSR_GET_PRIVATE(setting)->protocol_version;
}
/**
* nm_setting_hsr_get_interlink:
* @setting: the #NMSettingHsr
*
* Returns: the #NMSettingHsr:interlink property of the setting
*
* Since: 1.56
**/
const char *
nm_setting_hsr_get_interlink(NMSettingHsr *setting)
{
g_return_val_if_fail(NM_IS_SETTING_HSR(setting), NULL);
return NM_SETTING_HSR_GET_PRIVATE(setting)->interlink;
}
/*****************************************************************************/
static gboolean
@ -160,6 +200,18 @@ verify(NMSetting *setting, NMConnection *connection, GError **error)
return FALSE;
}
if (priv->prp && priv->protocol_version != NM_SETTING_HSR_PROTOCOL_VERSION_DEFAULT) {
g_set_error(error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("HSR protocol cannot be configured for PRP interfaces"));
g_prefix_error(error,
"%s.%s: ",
NM_SETTING_HSR_SETTING_NAME,
NM_SETTING_HSR_PROTOCOL_VERSION);
return FALSE;
}
return TRUE;
}
@ -260,6 +312,42 @@ nm_setting_hsr_class_init(NMSettingHsrClass *klass)
NMSettingHsr,
_priv.prp);
/**
* NMSettingHsr:protocol-version:
*
* Configures the protocol version to be used for the HSR/PRP interface.
* %NM_SETTING_HSR_PROTOCOL_VERSION_DEFAULT sets the protocol version to the default version for the protocol.
* %NM_SETTING_HSR_PROTOCOL_VERSION_HSR_2010 sets the protocol version to HSRv0 (IEC 62439-3:2010).
* %NM_SETTING_HSR_PROTOCOL_VERSION_HSR_2012 sets the protocol version to HSRv1 (IEC 62439-3:2012).
*
* Since: 1.56
**/
_nm_setting_property_define_direct_enum(properties_override,
obj_properties,
NM_SETTING_HSR_PROTOCOL_VERSION,
PROP_PROTOCOL_VERSION,
NM_TYPE_SETTING_HSR_PROTOCOL_VERSION,
NM_SETTING_HSR_PROTOCOL_VERSION_DEFAULT,
NM_SETTING_PARAM_NONE,
NULL,
NMSettingHsr,
_priv.protocol_version);
/**
* NMSettingHsr:interlink:
*
* The optional interlink port name of the HSR interface.
*
* Since: 1.56
**/
_nm_setting_property_define_direct_string(properties_override,
obj_properties,
NM_SETTING_HSR_INTERLINK,
PROP_INTERLINK,
NM_SETTING_PARAM_INFERRABLE,
NMSettingHsr,
_priv.interlink);
g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties);
_nm_setting_class_commit(setting_class, NM_META_SETTING_TYPE_HSR, NULL, properties_override, 0);

View file

@ -6740,7 +6740,7 @@ nm_setting_ip_config_class_init(NMSettingIPConfigClass *klass)
* NMSettingIPConfig:gateway:
*
* The gateway associated with this configuration. This is only meaningful
* if #NMSettingIPConfig:addresses is also set.
* if addresses are also set on the device.
*
* Setting the gateway causes NetworkManager to configure a standard default route
* with the gateway as next hop. This is ignored if #NMSettingIPConfig:never-default

View file

@ -154,6 +154,11 @@ struct _NMSettingClass {
guint /* NMSettingParseFlags */ parse_flags,
GError **error);
/* returns a list of certificate/key files referenced in the connection.
* When the connection is private, we need to verify that the owner of
* the connection has access to them. */
void (*get_private_files)(NMSetting *setting, GPtrArray *files);
const struct _NMMetaSettingInfo *setting_info;
};
@ -334,6 +339,11 @@ struct _NMRange {
*/
#define NM_SETTING_PARAM_TO_DBUS_IGNORE_FLAGS (1 << (7 + G_PARAM_USER_SHIFT))
/* The property can refer to a certificate or key stored on disk. As such,
* special care is needed when accessing the file for private connections.
*/
#define NM_SETTING_PARAM_CERT_KEY_FILE (1 << (8 + G_PARAM_USER_SHIFT))
extern const NMSettInfoPropertType nm_sett_info_propert_type_setting_name;
extern const NMSettInfoPropertType nm_sett_info_propert_type_deprecated_interface_name;
extern const NMSettInfoPropertType nm_sett_info_propert_type_deprecated_ignore_i;
@ -859,9 +869,10 @@ _nm_properties_override(GArray *properties_override, const NMSettInfoProperty *p
{ \
GParamSpec *_param_spec; \
\
G_STATIC_ASSERT(!NM_FLAGS_ANY((param_flags), \
~(NM_SETTING_PARAM_SECRET | NM_SETTING_PARAM_INFERRABLE \
| NM_SETTING_PARAM_FUZZY_IGNORE))); \
G_STATIC_ASSERT( \
!NM_FLAGS_ANY((param_flags), \
~(NM_SETTING_PARAM_SECRET | NM_SETTING_PARAM_INFERRABLE \
| NM_SETTING_PARAM_FUZZY_IGNORE | NM_SETTING_PARAM_CERT_KEY_FILE))); \
\
_param_spec = g_param_spec_boxed("" prop_name "", \
"", \

View file

@ -2262,6 +2262,34 @@ init_from_dbus(NMSetting *setting,
return TRUE;
}
static void
get_private_files(NMSetting *setting, GPtrArray *files)
{
if (NM_MORE_ASSERTS) {
GParamSpec **properties;
guint n_properties;
int i;
properties = g_object_class_list_properties(G_OBJECT_GET_CLASS(setting), &n_properties);
for (i = 0; i < n_properties; i++) {
if (properties[i]->flags & NM_SETTING_PARAM_CERT_KEY_FILE) {
/* Certificates and keys needs special handling, see setting 802.1X */
nm_assert_not_reached();
}
}
g_free(properties);
}
}
void
_nm_setting_get_private_files(NMSetting *setting, GPtrArray *files)
{
g_return_if_fail(NM_IS_SETTING(setting));
g_return_if_fail(files);
NM_SETTING_GET_CLASS(setting)->get_private_files(setting, files);
}
/**
* nm_setting_get_dbus_property_type:
* @setting: an #NMSetting
@ -4495,7 +4523,7 @@ nm_range_from_str(const char *str, GError **error)
gs_free char *str_free = NULL;
guint64 start;
guint64 end = 0;
char *c;
const char *c;
g_return_val_if_fail(str, NULL);
g_return_val_if_fail(!error || !*error, NULL);
@ -4672,6 +4700,7 @@ nm_setting_class_init(NMSettingClass *setting_class)
setting_class->enumerate_values = enumerate_values;
setting_class->aggregate = aggregate;
setting_class->init_from_dbus = init_from_dbus;
setting_class->get_private_files = get_private_files;
/**
* NMSetting:name:

View file

@ -17,6 +17,7 @@
#include <linux/pkt_sched.h>
#include <linux/if_infiniband.h>
#include "libnm-glib-aux/nm-io-utils.h"
#include "libnm-glib-aux/nm-uuid.h"
#include "libnm-glib-aux/nm-json-aux.h"
#include "libnm-glib-aux/nm-str-buf.h"
@ -6195,3 +6196,258 @@ nm_utils_ensure_gtypes(void)
for (meta_type = 0; meta_type < _NM_META_SETTING_TYPE_NUM; meta_type++)
nm_meta_setting_infos[meta_type].get_setting_gtype();
}
/*****************************************************************************/
typedef struct {
GPid pid;
GSource *child_watch_source;
GMainLoop *loop;
GError *error;
int child_stdout;
int child_stderr;
GSource *output_source;
GSource *error_source;
NMStrBuf output_buffer;
NMStrBuf error_buffer;
} HelperInfo;
static void
helper_complete(HelperInfo *info, GError *error_take)
{
if (error_take) {
if (!info->error)
info->error = error_take;
else
g_error_free(error_take);
}
if (info->output_source || info->error_source || info->pid != -1) {
/* Wait that the pipe is closed and process has terminated */
return;
}
if (info->error && info->error_buffer.len > 0) {
/* Prefer the message from stderr as it's more informative */
g_error_free(info->error);
info->error = g_error_new(NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_FAILED,
"%s",
nm_str_buf_get_str(&info->error_buffer));
}
g_main_loop_quit(info->loop);
}
static gboolean
helper_have_err_data(int fd, GIOCondition condition, gpointer user_data)
{
HelperInfo *info = user_data;
gssize n_read;
GError *error = NULL;
n_read = nm_utils_fd_read(fd, &info->error_buffer);
if (n_read > 0)
return G_SOURCE_CONTINUE;
nm_clear_g_source_inst(&info->error_source);
nm_clear_fd(&info->child_stderr);
if (n_read < 0) {
error = g_error_new(NM_UTILS_ERROR,
NM_UTILS_ERROR_UNKNOWN,
"read from process returned %d (%s)",
(int) -n_read,
nm_strerror_native((int) -n_read));
}
helper_complete(info, error);
return G_SOURCE_CONTINUE;
}
static gboolean
helper_have_data(int fd, GIOCondition condition, gpointer user_data)
{
HelperInfo *info = user_data;
gssize n_read;
GError *error = NULL;
n_read = nm_utils_fd_read(fd, &info->output_buffer);
if (n_read > 0)
return G_SOURCE_CONTINUE;
nm_clear_g_source_inst(&info->output_source);
nm_clear_fd(&info->child_stdout);
if (n_read < 0) {
error = g_error_new(NM_UTILS_ERROR,
NM_UTILS_ERROR_UNKNOWN,
"read from process returned %d (%s)",
(int) -n_read,
nm_strerror_native((int) -n_read));
}
helper_complete(info, error);
return G_SOURCE_CONTINUE;
}
static void
helper_child_terminated(GPid pid, int status, gpointer user_data)
{
HelperInfo *info = user_data;
gs_free char *status_desc = NULL;
GError *error = NULL;
info->pid = -1;
nm_clear_g_source_inst(&info->child_watch_source);
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
if (!status_desc)
status_desc = nm_utils_get_process_exit_status_desc(status);
error =
g_error_new(NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, "helper process %s", status_desc);
}
helper_complete(info, error);
}
#define RUN_CERT_DIR NMRUNDIR "/cert"
/**
* nm_utils_copy_cert_as_user:
* @filename: the file name of the certificate or key to copy
* @user: the user to impersonate when reading the file
* @error: (nullable): return location for a #GError, or %NULL
*
* Reads @filename on behalf of user @user and writes the
* content to a new file in /run/NetworkManager/cert/.
* The new file has permission 600 and is owned by root.
*
* This function is useful for VPN plugins that run as root and need
* to verify that the user owning the connection (the one listed in the
* connection.permissions property) can access the file.
*
* Returns: (transfer full): the name of the new temporary file. Or %NULL
* if an error occurred, including when the given user can't access the
* file.
*
* Since: 1.56
*/
char *
nm_utils_copy_cert_as_user(const char *filename, const char *user, GError **error)
{
gs_unref_bytes GBytes *bytes = NULL;
char dst_path[] = RUN_CERT_DIR "/XXXXXX";
HelperInfo info = {
.child_stdout = -1,
.child_stderr = -1,
};
GMainContext *context;
int fd = -1;
g_return_val_if_fail(filename, NULL);
g_return_val_if_fail(user, NULL);
g_return_val_if_fail(!error || !*error, NULL);
if (geteuid() != 0) {
g_set_error_literal(error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("This function needs to be called by root"));
return NULL;
}
if (!g_spawn_async_with_pipes(
"/",
(char **)
NM_MAKE_STRV(LIBEXECDIR "/nm-libnm-helper", "read-file-as-user", filename, user),
(char **) NM_MAKE_STRV(),
G_SPAWN_CLOEXEC_PIPES | G_SPAWN_DO_NOT_REAP_CHILD,
NULL,
NULL,
&info.pid,
NULL,
&info.child_stdout,
&info.child_stderr,
error)) {
return NULL;
}
context = g_main_context_new();
info.loop = g_main_loop_new(context, FALSE);
/* Watch process */
info.child_watch_source = nm_g_child_watch_source_new(info.pid,
G_PRIORITY_DEFAULT,
helper_child_terminated,
&info,
NULL);
g_source_attach(info.child_watch_source, context);
/* Watch stdout */
info.output_buffer = NM_STR_BUF_INIT(0, FALSE);
info.output_source = nm_g_unix_fd_source_new(info.child_stdout,
G_IO_IN | G_IO_ERR | G_IO_HUP,
G_PRIORITY_DEFAULT,
helper_have_data,
&info,
NULL);
g_source_attach(info.output_source, context);
/* Watch stderr */
info.error_buffer = NM_STR_BUF_INIT(0, FALSE);
info.error_source = nm_g_unix_fd_source_new(info.child_stderr,
G_IO_IN | G_IO_ERR | G_IO_HUP,
G_PRIORITY_DEFAULT,
helper_have_err_data,
&info,
NULL);
g_source_attach(info.error_source, context);
/* Wait termination */
g_main_loop_run(info.loop);
g_clear_pointer(&info.loop, g_main_loop_unref);
g_clear_pointer(&context, g_main_context_unref);
if (info.error) {
nm_str_buf_destroy(&info.output_buffer);
nm_str_buf_destroy(&info.error_buffer);
g_propagate_error(error, g_steal_pointer(&info.error));
return NULL;
}
/* Write the data to a new file */
bytes = g_bytes_new(nm_str_buf_get_str_unsafe(&info.output_buffer), info.output_buffer.len);
nm_str_buf_destroy(&info.output_buffer);
nm_str_buf_destroy(&info.error_buffer);
mkdir(RUN_CERT_DIR, 0600);
fd = mkstemp(dst_path);
if (fd < 0) {
g_set_error_literal(error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("Failure creating the temporary file"));
return NULL;
}
nm_close(fd);
if (!nm_utils_file_set_contents(dst_path,
g_bytes_get_data(bytes, NULL),
g_bytes_get_size(bytes),
0600,
NULL,
NULL,
NULL,
error)) {
return NULL;
}
return g_strdup(dst_path);
}

View file

@ -913,6 +913,29 @@ nm_vpn_plugin_info_supports_multiple(NMVpnPluginInfo *self)
return _nm_utils_ascii_str_to_bool(s, FALSE);
}
/**
* nm_vpn_plugin_info_supports_safe_private_file_access:
* @self: plugin info instance
*
* Returns: %TRUE if the service supports reading files (certificates, keys) of
* private connections in a safe way (i.e. checking user permissions), or
if the service doesn't need to read any file from disk.
*
* Since: 1.56
*/
gboolean
nm_vpn_plugin_info_supports_safe_private_file_access(NMVpnPluginInfo *self)
{
const char *s;
g_return_val_if_fail(NM_IS_VPN_PLUGIN_INFO(self), FALSE);
s = nm_vpn_plugin_info_lookup_property(self,
NM_VPN_PLUGIN_INFO_KF_GROUP_CONNECTION,
"supports-safe-private-file-access");
return _nm_utils_ascii_str_to_bool(s, FALSE);
}
/**
* nm_vpn_plugin_info_get_aliases:
* @self: plugin info instance

View file

@ -4032,6 +4032,7 @@ test_connection_diff_a_only(void)
{NM_SETTING_CONNECTION_MDNS, NM_SETTING_DIFF_RESULT_IN_A},
{NM_SETTING_CONNECTION_LLMNR, NM_SETTING_DIFF_RESULT_IN_A},
{NM_SETTING_CONNECTION_DNS_OVER_TLS, NM_SETTING_DIFF_RESULT_IN_A},
{NM_SETTING_CONNECTION_DNSSEC, NM_SETTING_DIFF_RESULT_IN_A},
{NM_SETTING_CONNECTION_MPTCP_FLAGS, NM_SETTING_DIFF_RESULT_IN_A},
{NM_SETTING_CONNECTION_MUD_URL, NM_SETTING_DIFF_RESULT_IN_A},
{NM_SETTING_CONNECTION_WAIT_DEVICE_TIMEOUT, NM_SETTING_DIFF_RESULT_IN_A},

View file

@ -1187,4 +1187,11 @@ gboolean nm_connection_need_secrets_for_rerequest(NMConnection *connection);
const GPtrArray *_nm_setting_ovs_port_get_trunks_arr(NMSettingOvsPort *self);
/*****************************************************************************/
guint _nm_setting_connection_get_num_permissions_users(NMSettingConnection *setting);
const char *_nm_setting_connection_get_first_permissions_user(NMSettingConnection *setting);
void _nm_setting_get_private_files(NMSetting *setting, GPtrArray *files);
#endif

View file

@ -145,8 +145,10 @@ typedef enum {
* and not disable controls that require network access.
* The graphical shells may hide the network accessibility indicator altogether
* since no meaningful status indication can be provided.
* @NM_STATE_ASLEEP: Networking is not enabled, the system is being suspended or
* resumed from suspend.
* @NM_STATE_ASLEEP: Deprecated: 1.56: Use %NM_STATE_DISABLED instead.
* @NM_STATE_DISABLED: NetworkManager is disabled, either because the user requested
* to disable networking or because the system is suspended or resuming from suspend.
* Since: 1.56.
* @NM_STATE_DISCONNECTED: There is no active network connection.
* The graphical shell should indicate no network connectivity and the
* applications should not attempt to access the network.
@ -170,7 +172,8 @@ typedef enum {
**/
typedef enum {
NM_STATE_UNKNOWN = 0,
NM_STATE_ASLEEP = 10,
NM_STATE_ASLEEP = 10, /* Deprecated */
NM_STATE_DISABLED = 10,
NM_STATE_DISCONNECTED = 20,
NM_STATE_DISCONNECTING = 30,
NM_STATE_CONNECTING = 40,
@ -632,8 +635,10 @@ typedef enum {
* not initialized by udev. Since: 1.48
* @NM_DEVICE_STATE_REASON_UNMANAGED_QUITTING: The device is unmanaged because NetworkManager is
* quitting. Since: 1.48
* @NM_DEVICE_STATE_REASON_UNMANAGED_SLEEPING: The device is unmanaged because networking is
* disabled or the system is suspended. Since: 1.48
* @NM_DEVICE_STATE_REASON_UNMANAGED_SLEEPING: Since: 1.48. Deprecated: 1.56: Use
* %NM_DEVICE_STATE_REASON_UNMANAGED_MANAGER_DISABLED instead.
* @NM_DEVICE_STATE_REASON_UNMANAGED_MANAGER_DISABLED: The device is unmanaged because networking is
* disabled or the system is suspended. Since: 1.56
* @NM_DEVICE_STATE_REASON_UNMANAGED_USER_CONF: The device is unmanaged by user decision in
* NetworkManager.conf ('unmanaged' in a [device*] section). Since: 1.48
* @NM_DEVICE_STATE_REASON_UNMANAGED_USER_EXPLICIT: The device is unmanaged by explicit user
@ -642,7 +647,9 @@ typedef enum {
* via settings plugin ('unmanaged-devices' for keyfile or 'NM_CONTROLLED=no' for ifcfg-rh).
* Since: 1.48
* @NM_DEVICE_STATE_REASON_UNMANAGED_USER_UDEV: The device is unmanaged via udev rule. Since: 1.48
* @NM_DEVICE_STATE_REASON_NETWORKING_OFF: NetworkManager was disabled (networking off). Since: 1.56
* @NM_DEVICE_STATE_REASON_MODEM_NO_OPERATOR_CODE: The modem's operator code wasn't available,
* and auto-configuration was requested. Since: 1.56
*
* Device state change reason codes
*/
@ -720,11 +727,14 @@ typedef enum {
NM_DEVICE_STATE_REASON_UNMANAGED_EXTERNAL_DOWN = 70,
NM_DEVICE_STATE_REASON_UNMANAGED_LINK_NOT_INIT = 71,
NM_DEVICE_STATE_REASON_UNMANAGED_QUITTING = 72,
NM_DEVICE_STATE_REASON_UNMANAGED_SLEEPING = 73,
NM_DEVICE_STATE_REASON_UNMANAGED_SLEEPING = 73, /* Deprecated */
NM_DEVICE_STATE_REASON_UNMANAGED_MANAGER_DISABLED = 73,
NM_DEVICE_STATE_REASON_UNMANAGED_USER_CONF = 74,
NM_DEVICE_STATE_REASON_UNMANAGED_USER_EXPLICIT = 75,
NM_DEVICE_STATE_REASON_UNMANAGED_USER_SETTINGS = 76,
NM_DEVICE_STATE_REASON_UNMANAGED_USER_UDEV = 77,
NM_DEVICE_STATE_REASON_NETWORKING_OFF = 78,
NM_DEVICE_STATE_REASON_MODEM_NO_OPERATOR_CODE = 79,
} NMDeviceStateReason;
/**
@ -1450,6 +1460,16 @@ typedef enum /*< flags >*/ {
* any additional addresses using the MPTCP ADD_ADDR sub-option, this will behave the same
* as a plain subflow endpoint. When the peer does announce addresses, each received ADD_ADDR
* sub-option will trigger creation of an additional subflow to generate a full mesh topology.
* @NM_MPTCP_FLAGS_LAMINAR: Flag for the MPTCP endpoint. The endpoint will be
* used to create new subflows from the associated address to additional
* addresses announced by the other peer. This will be done if allowed by the
* MPTCP limits, and if the associated address is not already being used by
* another subflow from the same MPTCP connection. Note that the 'fullmesh'
* flag takes precedence over the 'laminar' one. Without any of these two
* flags, the path-manager will create new subflows to additional addresses
* announced by the other peer by selecting the source address from the
* routing tables, which is harder to configure if the announced address is
* not known in advance. Since: 1.56
*
* Since: 1.40
*/
@ -1466,6 +1486,7 @@ typedef enum /*< flags >*/ {
NM_MPTCP_FLAGS_SUBFLOW = 0x20,
NM_MPTCP_FLAGS_BACKUP = 0x40,
NM_MPTCP_FLAGS_FULLMESH = 0x80,
NM_MPTCP_FLAGS_LAMINAR = 0x100,
} NMMptcpFlags;
/* For secrets requests, hints starting with "x-vpn-message:" are a message to show, not

View file

@ -256,6 +256,11 @@ GQuark nm_secret_agent_error_quark(void);
* @NM_SETTINGS_ERROR_NOT_SUPPORTED_BY_PLUGIN: the requested operation is not
* supported by the settings plugin currently in use for the specified object.
* Since: 1.44.
* @NM_SETTINGS_ERROR_FEATURE_DISABLED: the requested operation failed because it
* requires a feature that is disabled in this build of NetworkManager.
* Since: 1.56
* @NM_SETTINGS_ERROR_FEATURE_REMOVED: the requested operation failed because it
* requires a feature that is no longer supported. Since: 1.56
*
* Errors related to the settings/persistent configuration interface of
* NetworkManager.
@ -275,6 +280,8 @@ typedef enum {
NM_SETTINGS_ERROR_INVALID_ARGUMENTS, /*< nick=InvalidArguments >*/
NM_SETTINGS_ERROR_VERSION_ID_MISMATCH, /*< nick=VersionIdMismatch >*/
NM_SETTINGS_ERROR_NOT_SUPPORTED_BY_PLUGIN, /*< nick=NotSupportedByPlugin >*/
NM_SETTINGS_ERROR_FEATURE_DISABLED, /*< nick=FeatureDisabled >*/
NM_SETTINGS_ERROR_FEATURE_REMOVED, /*< nick=FeatureRemoved >*/
} NMSettingsError;
GQuark nm_settings_error_quark(void);

View file

@ -60,6 +60,7 @@ G_BEGIN_DECLS
#define NM_SETTING_CONNECTION_MDNS "mdns"
#define NM_SETTING_CONNECTION_LLMNR "llmnr"
#define NM_SETTING_CONNECTION_DNS_OVER_TLS "dns-over-tls"
#define NM_SETTING_CONNECTION_DNSSEC "dnssec"
#define NM_SETTING_CONNECTION_MPTCP_FLAGS "mptcp-flags"
#define NM_SETTING_CONNECTION_WAIT_DEVICE_TIMEOUT "wait-device-timeout"
#define NM_SETTING_CONNECTION_MUD_URL "mud-url"
@ -162,6 +163,24 @@ typedef enum {
NM_SETTING_CONNECTION_DNS_OVER_TLS_YES = 2,
} NMSettingConnectionDnsOverTls;
/**
* NMSettingConnectionDnssec:
* @NM_SETTING_CONNECTION_DNSSEC_DEFAULT: default value
* @NM_SETTING_CONNECTION_DNSSEC_NO: disable DNSSEC
* @NM_SETTING_CONNECTION_DNSSEC_ALLOW_DOWNGRADE: enable DNSSEC but allow fallback to non-DNSSEC mode
* @NM_SETTING_CONNECTION_DNSSEC_YES: force enable DNSSEC
*
* #NMSettingConnectionDnssec values indicate whether DNSSEC should be enabled.
*
* Since: 1.56
*/
typedef enum {
NM_SETTING_CONNECTION_DNSSEC_DEFAULT = -1,
NM_SETTING_CONNECTION_DNSSEC_NO = 0,
NM_SETTING_CONNECTION_DNSSEC_ALLOW_DOWNGRADE = 1,
NM_SETTING_CONNECTION_DNSSEC_YES = 2,
} NMSettingConnectionDnssec;
/**
* NMSettingConnectionDownOnPoweroff:
* @NM_SETTING_CONNECTION_DOWN_ON_POWEROFF_DEFAULT: default value
@ -304,6 +323,9 @@ void nm_setting_connection_clear_ip_ping_addresses(NMSettingConnection *setting)
NM_AVAILABLE_IN_1_52
NMTernary nm_setting_connection_get_ip_ping_addresses_require_all(NMSettingConnection *setting);
NM_AVAILABLE_IN_1_56
NMSettingConnectionDnssec nm_setting_connection_get_dnssec(NMSettingConnection *setting);
G_END_DECLS
#endif /* __NM_SETTING_CONNECTION_H__ */

View file

@ -50,6 +50,7 @@ G_BEGIN_DECLS
#define NM_SETTING_GSM_INITIAL_EPS_BEARER_REFUSE_CHAP "initial-eps-bearer-refuse-chap"
#define NM_SETTING_GSM_INITIAL_EPS_BEARER_REFUSE_MSCHAP "initial-eps-bearer-refuse-mschap"
#define NM_SETTING_GSM_INITIAL_EPS_BEARER_REFUSE_MSCHAPV2 "initial-eps-bearer-refuse-mschapv2"
#define NM_SETTING_GSM_DEVICE_UID "device-uid"
/* Deprecated */
#define NM_SETTING_GSM_NUMBER "number"
@ -99,6 +100,8 @@ gboolean nm_setting_gsm_get_initial_eps_refuse_mschap(NMSettingGsm *setting);
NM_AVAILABLE_IN_1_52
gboolean nm_setting_gsm_get_initial_eps_refuse_mschapv2(NMSettingGsm *setting);
const char *nm_setting_gsm_get_device_uid(NMSettingGsm *setting);
NM_DEPRECATED_IN_1_16
const char *nm_setting_gsm_get_number(NMSettingGsm *setting);

View file

@ -23,10 +23,28 @@ G_BEGIN_DECLS
#define NM_SETTING_HSR_SETTING_NAME "hsr"
#define NM_SETTING_HSR_PORT1 "port1"
#define NM_SETTING_HSR_PORT2 "port2"
#define NM_SETTING_HSR_MULTICAST_SPEC "multicast-spec"
#define NM_SETTING_HSR_PRP "prp"
#define NM_SETTING_HSR_PORT1 "port1"
#define NM_SETTING_HSR_PORT2 "port2"
#define NM_SETTING_HSR_MULTICAST_SPEC "multicast-spec"
#define NM_SETTING_HSR_PRP "prp"
#define NM_SETTING_HSR_PROTOCOL_VERSION "protocol-version"
#define NM_SETTING_HSR_INTERLINK "interlink"
/**
* NMSettingHsrProtocolVersion:
* @NM_SETTING_HSR_PROTOCOL_VERSION_DEFAULT: Default version for the protocol
* @NM_SETTING_HSR_PROTOCOL_VERSION_HSR_2010: HSRv0, IEC 62439-3:2010
* @NM_SETTING_HSR_PROTOCOL_VERSION_HSR_2012: HSRv1, IEC 62439-3:2012
*
* #NMSettingHsrProtocolVersion values indicate the HSR protocol version.
*
* Since: 1.56
*/
typedef enum {
NM_SETTING_HSR_PROTOCOL_VERSION_DEFAULT = -1,
NM_SETTING_HSR_PROTOCOL_VERSION_HSR_2010 = 0,
NM_SETTING_HSR_PROTOCOL_VERSION_HSR_2012 = 1,
} NMSettingHsrProtocolVersion;
typedef struct _NMSettingHsrClass NMSettingHsrClass;
@ -43,6 +61,10 @@ NM_AVAILABLE_IN_1_46
guint32 nm_setting_hsr_get_multicast_spec(NMSettingHsr *setting);
NM_AVAILABLE_IN_1_46
gboolean nm_setting_hsr_get_prp(NMSettingHsr *setting);
NM_AVAILABLE_IN_1_56
NMSettingHsrProtocolVersion nm_setting_hsr_get_protocol_version(NMSettingHsr *setting);
NM_AVAILABLE_IN_1_56
const char *nm_setting_hsr_get_interlink(NMSettingHsr *setting);
G_END_DECLS

Some files were not shown because too many files have changed in this diff Show more