2020-12-23 22:21:36 +01:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
2014-07-24 08:53:33 -04:00
|
|
|
/*
|
2019-10-01 09:20:35 +02:00
|
|
|
* Copyright (C) 2005 - 2017 Red Hat, Inc.
|
2014-07-24 08:53:33 -04:00
|
|
|
*/
|
|
|
|
|
|
2021-02-12 15:01:09 +01:00
|
|
|
#include "libnm-core-impl/nm-default-libnm-core.h"
|
2016-02-19 14:57:48 +01:00
|
|
|
|
2016-02-12 14:44:52 +01:00
|
|
|
#include "nm-utils.h"
|
|
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
#include <stdlib.h>
|
2020-12-13 17:07:40 +01:00
|
|
|
#include <net/ethernet.h>
|
2014-10-19 17:30:10 -04:00
|
|
|
#include <arpa/inet.h>
|
2020-12-13 17:07:40 +01:00
|
|
|
#include <net/if_arp.h>
|
2014-11-13 10:29:37 -05:00
|
|
|
#include <libintl.h>
|
2014-07-25 17:50:14 -04:00
|
|
|
#include <gmodule.h>
|
2015-05-28 21:52:24 +02:00
|
|
|
#include <sys/stat.h>
|
2017-11-18 17:17:24 +01:00
|
|
|
#include <linux/pkt_sched.h>
|
2020-12-13 16:08:56 +01:00
|
|
|
#include <linux/if_infiniband.h>
|
2014-07-24 08:53:33 -04:00
|
|
|
|
2025-09-26 21:04:04 +02:00
|
|
|
#include "libnm-glib-aux/nm-io-utils.h"
|
2021-05-02 21:47:22 +02:00
|
|
|
#include "libnm-glib-aux/nm-uuid.h"
|
2021-02-18 17:37:47 +01:00
|
|
|
#include "libnm-glib-aux/nm-json-aux.h"
|
|
|
|
|
#include "libnm-glib-aux/nm-str-buf.h"
|
|
|
|
|
#include "libnm-glib-aux/nm-enum-utils.h"
|
|
|
|
|
#include "libnm-glib-aux/nm-time-utils.h"
|
|
|
|
|
#include "libnm-glib-aux/nm-secret-utils.h"
|
2021-02-12 15:01:09 +01:00
|
|
|
#include "libnm-core-aux-intern/nm-common-macros.h"
|
2025-11-28 15:19:59 +01:00
|
|
|
#include "libnm-core-aux-intern/nm-libnm-core-utils.h"
|
2014-07-24 08:53:33 -04:00
|
|
|
#include "nm-utils-private.h"
|
|
|
|
|
#include "nm-setting-private.h"
|
2014-10-21 22:09:52 -04:00
|
|
|
#include "nm-setting-bond.h"
|
2021-08-23 22:00:54 +08:00
|
|
|
#include "nm-setting-bond-port.h"
|
2014-10-21 22:09:52 -04:00
|
|
|
#include "nm-setting-bridge.h"
|
2019-03-16 17:21:35 +01:00
|
|
|
#include "nm-setting-bridge-port.h"
|
2014-10-21 22:09:52 -04:00
|
|
|
#include "nm-setting-infiniband.h"
|
|
|
|
|
#include "nm-setting-ip6-config.h"
|
|
|
|
|
#include "nm-setting-team.h"
|
|
|
|
|
#include "nm-setting-vlan.h"
|
|
|
|
|
#include "nm-setting-wired.h"
|
|
|
|
|
#include "nm-setting-wireless.h"
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
#include "nm-errors.h"
|
2014-10-21 22:09:52 -04:00
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
/**
|
|
|
|
|
* SECTION:nm-utils
|
|
|
|
|
* @short_description: Utility functions
|
|
|
|
|
*
|
|
|
|
|
* A collection of utility functions for working with SSIDs, IP addresses, Wi-Fi
|
|
|
|
|
* access points and devices, among other things.
|
|
|
|
|
*/
|
|
|
|
|
|
2018-12-29 13:01:28 +01:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-05-20 15:20:21 +02:00
|
|
|
/**
|
|
|
|
|
* NMUtilsPredicateStr:
|
|
|
|
|
* @str: the name to check.
|
|
|
|
|
*
|
|
|
|
|
* This function takes a string argument and returns either %TRUE or %FALSE.
|
|
|
|
|
* It is a general purpose predicate, for example used by nm_setting_option_clear_by_name().
|
|
|
|
|
*
|
|
|
|
|
* Returns: %TRUE if the predicate function matches.
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.26
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2018-12-29 13:01:28 +01:00
|
|
|
struct _NMSockAddrEndpoint {
|
|
|
|
|
const char *host;
|
|
|
|
|
guint16 port;
|
|
|
|
|
guint refcount;
|
|
|
|
|
char endpoint[];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
NM_IS_SOCK_ADDR_ENDPOINT(const NMSockAddrEndpoint *self)
|
|
|
|
|
{
|
|
|
|
|
return self && self->refcount > 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
|
_parse_endpoint(char *str, guint16 *out_port)
|
|
|
|
|
{
|
2021-11-09 13:28:54 +01:00
|
|
|
char *s;
|
2018-12-29 13:01:28 +01:00
|
|
|
const char *s_port;
|
|
|
|
|
gint16 port;
|
|
|
|
|
|
|
|
|
|
/* Like
|
|
|
|
|
* - https://git.zx2c4.com/WireGuard/tree/src/tools/config.c?id=5e99a6d43fe2351adf36c786f5ea2086a8fe7ab8#n192
|
|
|
|
|
* - https://github.com/systemd/systemd/blob/911649fdd43f3a9158b847947724a772a5a45c34/src/network/netdev/wireguard.c#L614
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
g_strstrip(str);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-12-29 13:01:28 +01:00
|
|
|
if (!str[0])
|
|
|
|
|
return NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-12-29 13:01:28 +01:00
|
|
|
if (str[0] == '[') {
|
|
|
|
|
str++;
|
|
|
|
|
s = strchr(str, ']');
|
|
|
|
|
if (!s)
|
|
|
|
|
return NULL;
|
|
|
|
|
if (s == str)
|
|
|
|
|
return NULL;
|
|
|
|
|
if (s[1] != ':')
|
|
|
|
|
return NULL;
|
|
|
|
|
if (!s[2])
|
|
|
|
|
return NULL;
|
|
|
|
|
*s = '\0';
|
|
|
|
|
s_port = &s[2];
|
|
|
|
|
} else {
|
|
|
|
|
s = strrchr(str, ':');
|
|
|
|
|
if (!s)
|
|
|
|
|
return NULL;
|
|
|
|
|
if (s == str)
|
|
|
|
|
return NULL;
|
|
|
|
|
if (!s[1])
|
|
|
|
|
return NULL;
|
|
|
|
|
*s = '\0';
|
|
|
|
|
s_port = &s[1];
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-12-29 13:01:28 +01:00
|
|
|
if (!NM_STRCHAR_ALL(s_port, ch, (ch >= '0' && ch <= '9')))
|
|
|
|
|
return NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-12-29 13:01:28 +01:00
|
|
|
port = _nm_utils_ascii_str_to_int64(s_port, 10, 1, G_MAXUINT16, 0);
|
|
|
|
|
if (port == 0)
|
|
|
|
|
return NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-12-29 13:01:28 +01:00
|
|
|
*out_port = port;
|
|
|
|
|
return str;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_sock_addr_endpoint_new:
|
|
|
|
|
* @endpoint: the endpoint string.
|
|
|
|
|
*
|
|
|
|
|
* This function cannot fail, even if the @endpoint is invalid.
|
|
|
|
|
* The reason is to allow NMSockAddrEndpoint also to be used
|
|
|
|
|
* for tracking invalid endpoints. Use nm_sock_addr_endpoint_get_host()
|
|
|
|
|
* to determine whether the endpoint is valid.
|
|
|
|
|
*
|
|
|
|
|
* Returns: (transfer full): the new #NMSockAddrEndpoint endpoint.
|
|
|
|
|
*/
|
|
|
|
|
NMSockAddrEndpoint *
|
|
|
|
|
nm_sock_addr_endpoint_new(const char *endpoint)
|
|
|
|
|
{
|
|
|
|
|
NMSockAddrEndpoint *ep;
|
|
|
|
|
gsize l_endpoint;
|
|
|
|
|
gsize l_host = 0;
|
|
|
|
|
gsize i;
|
2021-11-09 13:28:54 +01:00
|
|
|
gs_free char *host_clone = NULL;
|
|
|
|
|
const char *host;
|
2022-11-30 08:47:14 +01:00
|
|
|
guint16 port = 0;
|
2018-12-29 13:01:28 +01:00
|
|
|
|
|
|
|
|
g_return_val_if_fail(endpoint, NULL);
|
|
|
|
|
|
|
|
|
|
l_endpoint = strlen(endpoint) + 1;
|
|
|
|
|
|
|
|
|
|
host = _parse_endpoint(nm_strndup_a(200, endpoint, l_endpoint - 1, &host_clone), &port);
|
|
|
|
|
|
|
|
|
|
if (host)
|
|
|
|
|
l_host = strlen(host) + 1;
|
|
|
|
|
|
|
|
|
|
ep = g_malloc(sizeof(NMSockAddrEndpoint) + l_endpoint + l_host);
|
|
|
|
|
ep->refcount = 1;
|
|
|
|
|
memcpy(ep->endpoint, endpoint, l_endpoint);
|
|
|
|
|
if (host) {
|
|
|
|
|
i = l_endpoint;
|
|
|
|
|
memcpy(&ep->endpoint[i], host, l_host);
|
|
|
|
|
ep->host = &ep->endpoint[i];
|
|
|
|
|
ep->port = port;
|
|
|
|
|
} else {
|
|
|
|
|
ep->host = NULL;
|
|
|
|
|
ep->port = 0;
|
|
|
|
|
}
|
|
|
|
|
return ep;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_sock_addr_endpoint_ref:
|
2023-03-01 01:21:38 +01:00
|
|
|
* @self: (nullable): the #NMSockAddrEndpoint
|
2018-12-29 13:01:28 +01:00
|
|
|
*/
|
|
|
|
|
NMSockAddrEndpoint *
|
|
|
|
|
nm_sock_addr_endpoint_ref(NMSockAddrEndpoint *self)
|
|
|
|
|
{
|
|
|
|
|
if (!self)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail(NM_IS_SOCK_ADDR_ENDPOINT(self), NULL);
|
|
|
|
|
|
|
|
|
|
nm_assert(self->refcount < G_MAXUINT);
|
|
|
|
|
|
|
|
|
|
self->refcount++;
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_sock_addr_endpoint_unref:
|
2023-03-01 01:21:38 +01:00
|
|
|
* @self: (nullable): the #NMSockAddrEndpoint
|
2018-12-29 13:01:28 +01:00
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
nm_sock_addr_endpoint_unref(NMSockAddrEndpoint *self)
|
|
|
|
|
{
|
|
|
|
|
if (!self)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
g_return_if_fail(NM_IS_SOCK_ADDR_ENDPOINT(self));
|
|
|
|
|
|
|
|
|
|
if (--self->refcount == 0)
|
|
|
|
|
g_free(self);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_sock_addr_endpoint_get_endpoint:
|
|
|
|
|
* @self: the #NMSockAddrEndpoint
|
|
|
|
|
*
|
|
|
|
|
* Gives the endpoint string. Since #NMSockAddrEndpoint's only
|
|
|
|
|
* information is the endpoint string, this can be used for comparing
|
|
|
|
|
* to instances for equality and order them lexically.
|
|
|
|
|
*
|
|
|
|
|
* Returns: (transfer none): the endpoint.
|
|
|
|
|
*/
|
|
|
|
|
const char *
|
|
|
|
|
nm_sock_addr_endpoint_get_endpoint(NMSockAddrEndpoint *self)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail(NM_IS_SOCK_ADDR_ENDPOINT(self), NULL);
|
|
|
|
|
|
|
|
|
|
return self->endpoint;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_sock_addr_endpoint_get_host:
|
|
|
|
|
* @self: the #NMSockAddrEndpoint
|
|
|
|
|
*
|
|
|
|
|
* Returns: (transfer none): the parsed host part of the endpoint.
|
|
|
|
|
* If the endpoint is invalid, %NULL will be returned.
|
|
|
|
|
*/
|
|
|
|
|
const char *
|
|
|
|
|
nm_sock_addr_endpoint_get_host(NMSockAddrEndpoint *self)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail(NM_IS_SOCK_ADDR_ENDPOINT(self), NULL);
|
|
|
|
|
|
|
|
|
|
return self->host;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_sock_addr_endpoint_get_port:
|
|
|
|
|
* @self: the #NMSockAddrEndpoint
|
|
|
|
|
*
|
|
|
|
|
* Returns: the parsed port part of the endpoint (the service).
|
|
|
|
|
* If the endpoint is invalid, -1 will be returned.
|
|
|
|
|
*/
|
|
|
|
|
gint32
|
|
|
|
|
nm_sock_addr_endpoint_get_port(NMSockAddrEndpoint *self)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail(NM_IS_SOCK_ADDR_ENDPOINT(self), -1);
|
|
|
|
|
|
|
|
|
|
return self->host ? (int) self->port : -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
|
nm_sock_addr_endpoint_get_fixed_sockaddr(NMSockAddrEndpoint *self, gpointer sockaddr)
|
|
|
|
|
{
|
|
|
|
|
int addr_family;
|
|
|
|
|
NMIPAddr addrbin;
|
|
|
|
|
const char *s;
|
|
|
|
|
guint scope_id = 0;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail(NM_IS_SOCK_ADDR_ENDPOINT(self), FALSE);
|
|
|
|
|
g_return_val_if_fail(sockaddr, FALSE);
|
|
|
|
|
|
|
|
|
|
if (!self->host)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
glib-aux: rename IP address related helpers from "nm-inet-utils.h"
- name things related to `in_addr_t`, `struct in6_addr`, `NMIPAddr` as
`nm_ip4_addr_*()`, `nm_ip6_addr_*()`, `nm_ip_addr_*()`, respectively.
- we have a wrapper `nm_inet_ntop()` for `inet_ntop()`. This name
of our wrapper is chosen to be familiar with the libc underlying
function. With this, also name functions that are about string
representations of addresses `nm_inet_*()`, `nm_inet4_*()`,
`nm_inet6_*()`. For example, `nm_inet_parse_str()`,
`nm_inet_is_normalized()`.
<<<<
R() {
git grep -l "$1" | xargs sed -i "s/\<$1\>/$2/g"
}
R NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX NM_CMP_DIRECT_IP4_ADDR_SAME_PREFIX
R NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX NM_CMP_DIRECT_IP6_ADDR_SAME_PREFIX
R NM_UTILS_INET_ADDRSTRLEN NM_INET_ADDRSTRLEN
R _nm_utils_inet4_ntop nm_inet4_ntop
R _nm_utils_inet6_ntop nm_inet6_ntop
R _nm_utils_ip4_get_default_prefix nm_ip4_addr_get_default_prefix
R _nm_utils_ip4_get_default_prefix0 nm_ip4_addr_get_default_prefix0
R _nm_utils_ip4_netmask_to_prefix nm_ip4_addr_netmask_to_prefix
R _nm_utils_ip4_prefix_to_netmask nm_ip4_addr_netmask_from_prefix
R nm_utils_inet4_ntop_dup nm_inet4_ntop_dup
R nm_utils_inet6_ntop_dup nm_inet6_ntop_dup
R nm_utils_inet_ntop nm_inet_ntop
R nm_utils_inet_ntop_dup nm_inet_ntop_dup
R nm_utils_ip4_address_clear_host_address nm_ip4_addr_clear_host_address
R nm_utils_ip4_address_is_link_local nm_ip4_addr_is_link_local
R nm_utils_ip4_address_is_loopback nm_ip4_addr_is_loopback
R nm_utils_ip4_address_is_zeronet nm_ip4_addr_is_zeronet
R nm_utils_ip4_address_same_prefix nm_ip4_addr_same_prefix
R nm_utils_ip4_address_same_prefix_cmp nm_ip4_addr_same_prefix_cmp
R nm_utils_ip6_address_clear_host_address nm_ip6_addr_clear_host_address
R nm_utils_ip6_address_same_prefix nm_ip6_addr_same_prefix
R nm_utils_ip6_address_same_prefix_cmp nm_ip6_addr_same_prefix_cmp
R nm_utils_ip6_is_ula nm_ip6_addr_is_ula
R nm_utils_ip_address_same_prefix nm_ip_addr_same_prefix
R nm_utils_ip_address_same_prefix_cmp nm_ip_addr_same_prefix_cmp
R nm_utils_ip_is_site_local nm_ip_addr_is_site_local
R nm_utils_ipaddr_is_normalized nm_inet_is_normalized
R nm_utils_ipaddr_is_valid nm_inet_is_valid
R nm_utils_ipx_address_clear_host_address nm_ip_addr_clear_host_address
R nm_utils_parse_inaddr nm_inet_parse_str
R nm_utils_parse_inaddr_bin nm_inet_parse_bin
R nm_utils_parse_inaddr_bin_full nm_inet_parse_bin_full
R nm_utils_parse_inaddr_prefix nm_inet_parse_with_prefix_str
R nm_utils_parse_inaddr_prefix_bin nm_inet_parse_with_prefix_bin
R test_nm_utils_ip6_address_same_prefix test_nm_ip_addr_same_prefix
./contrib/scripts/nm-code-format.sh -F
2022-08-19 13:15:20 +02:00
|
|
|
if (nm_inet_parse_bin(AF_UNSPEC, self->host, &addr_family, &addrbin))
|
2018-12-29 13:01:28 +01:00
|
|
|
goto good;
|
|
|
|
|
|
|
|
|
|
/* See if there is an IPv6 scope-id...
|
|
|
|
|
*
|
|
|
|
|
* Note that it does not make sense to persist connection profiles to disk,
|
|
|
|
|
* that refenrence a scope-id (because the interface's ifindex changes on
|
|
|
|
|
* reboot). However, we also support runtime only changes like `nmcli device modify`
|
|
|
|
|
* where nothing is persisted to disk. At least in that case, passing a scope-id
|
|
|
|
|
* might be reasonable. So, parse that too. */
|
|
|
|
|
s = strchr(self->host, '%');
|
|
|
|
|
if (!s)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (s[1] == '\0' || !NM_STRCHAR_ALL(&s[1], ch, (ch >= '0' && ch <= '9')))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
scope_id = _nm_utils_ascii_str_to_int64(&s[1], 10, 0, G_MAXINT32, G_MAXUINT);
|
|
|
|
|
if (scope_id == G_MAXUINT && errno)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
gs_free char *tmp_str = NULL;
|
2021-11-09 13:28:54 +01:00
|
|
|
const char *host_part;
|
2018-12-29 13:01:28 +01:00
|
|
|
|
|
|
|
|
host_part = nm_strndup_a(200, self->host, s - self->host, &tmp_str);
|
glib-aux: rename IP address related helpers from "nm-inet-utils.h"
- name things related to `in_addr_t`, `struct in6_addr`, `NMIPAddr` as
`nm_ip4_addr_*()`, `nm_ip6_addr_*()`, `nm_ip_addr_*()`, respectively.
- we have a wrapper `nm_inet_ntop()` for `inet_ntop()`. This name
of our wrapper is chosen to be familiar with the libc underlying
function. With this, also name functions that are about string
representations of addresses `nm_inet_*()`, `nm_inet4_*()`,
`nm_inet6_*()`. For example, `nm_inet_parse_str()`,
`nm_inet_is_normalized()`.
<<<<
R() {
git grep -l "$1" | xargs sed -i "s/\<$1\>/$2/g"
}
R NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX NM_CMP_DIRECT_IP4_ADDR_SAME_PREFIX
R NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX NM_CMP_DIRECT_IP6_ADDR_SAME_PREFIX
R NM_UTILS_INET_ADDRSTRLEN NM_INET_ADDRSTRLEN
R _nm_utils_inet4_ntop nm_inet4_ntop
R _nm_utils_inet6_ntop nm_inet6_ntop
R _nm_utils_ip4_get_default_prefix nm_ip4_addr_get_default_prefix
R _nm_utils_ip4_get_default_prefix0 nm_ip4_addr_get_default_prefix0
R _nm_utils_ip4_netmask_to_prefix nm_ip4_addr_netmask_to_prefix
R _nm_utils_ip4_prefix_to_netmask nm_ip4_addr_netmask_from_prefix
R nm_utils_inet4_ntop_dup nm_inet4_ntop_dup
R nm_utils_inet6_ntop_dup nm_inet6_ntop_dup
R nm_utils_inet_ntop nm_inet_ntop
R nm_utils_inet_ntop_dup nm_inet_ntop_dup
R nm_utils_ip4_address_clear_host_address nm_ip4_addr_clear_host_address
R nm_utils_ip4_address_is_link_local nm_ip4_addr_is_link_local
R nm_utils_ip4_address_is_loopback nm_ip4_addr_is_loopback
R nm_utils_ip4_address_is_zeronet nm_ip4_addr_is_zeronet
R nm_utils_ip4_address_same_prefix nm_ip4_addr_same_prefix
R nm_utils_ip4_address_same_prefix_cmp nm_ip4_addr_same_prefix_cmp
R nm_utils_ip6_address_clear_host_address nm_ip6_addr_clear_host_address
R nm_utils_ip6_address_same_prefix nm_ip6_addr_same_prefix
R nm_utils_ip6_address_same_prefix_cmp nm_ip6_addr_same_prefix_cmp
R nm_utils_ip6_is_ula nm_ip6_addr_is_ula
R nm_utils_ip_address_same_prefix nm_ip_addr_same_prefix
R nm_utils_ip_address_same_prefix_cmp nm_ip_addr_same_prefix_cmp
R nm_utils_ip_is_site_local nm_ip_addr_is_site_local
R nm_utils_ipaddr_is_normalized nm_inet_is_normalized
R nm_utils_ipaddr_is_valid nm_inet_is_valid
R nm_utils_ipx_address_clear_host_address nm_ip_addr_clear_host_address
R nm_utils_parse_inaddr nm_inet_parse_str
R nm_utils_parse_inaddr_bin nm_inet_parse_bin
R nm_utils_parse_inaddr_bin_full nm_inet_parse_bin_full
R nm_utils_parse_inaddr_prefix nm_inet_parse_with_prefix_str
R nm_utils_parse_inaddr_prefix_bin nm_inet_parse_with_prefix_bin
R test_nm_utils_ip6_address_same_prefix test_nm_ip_addr_same_prefix
./contrib/scripts/nm-code-format.sh -F
2022-08-19 13:15:20 +02:00
|
|
|
if (nm_inet_parse_bin(AF_INET6, host_part, &addr_family, &addrbin))
|
2018-12-29 13:01:28 +01:00
|
|
|
goto good;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
good:
|
|
|
|
|
switch (addr_family) {
|
|
|
|
|
case AF_INET:
|
2024-10-04 10:45:56 +02:00
|
|
|
*((struct sockaddr_in *) sockaddr) = (struct sockaddr_in) {
|
2018-12-29 13:01:28 +01:00
|
|
|
.sin_family = AF_INET,
|
|
|
|
|
.sin_addr = addrbin.addr4_struct,
|
|
|
|
|
.sin_port = htons(self->port),
|
|
|
|
|
};
|
|
|
|
|
return TRUE;
|
|
|
|
|
case AF_INET6:
|
2024-10-04 10:45:56 +02:00
|
|
|
*((struct sockaddr_in6 *) sockaddr) = (struct sockaddr_in6) {
|
2018-12-29 13:01:28 +01:00
|
|
|
.sin6_family = AF_INET6,
|
|
|
|
|
.sin6_addr = addrbin.addr6,
|
|
|
|
|
.sin6_port = htons(self->port),
|
|
|
|
|
.sin6_scope_id = scope_id,
|
|
|
|
|
.sin6_flowinfo = 0,
|
|
|
|
|
};
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-12-29 13:01:28 +01:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2022-01-02 20:43:09 +01:00
|
|
|
typedef const char *const StrvArray4Type[4];
|
2014-07-24 08:53:33 -04:00
|
|
|
|
2024-05-28 17:27:47 +02:00
|
|
|
#define LL(l, ...) \
|
|
|
|
|
{ \
|
|
|
|
|
.name = l, \
|
|
|
|
|
.value = {__VA_ARGS__, NULL}, \
|
2018-11-30 11:37:21 +01:00
|
|
|
}
|
2017-09-10 10:31:44 +02:00
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
/* 5-letter language codes */
|
2022-01-02 20:43:09 +01:00
|
|
|
static _NM_UTILS_STRING_TABLE_LOOKUP_DEFINE(
|
|
|
|
|
_iso_lang_entries_5_lookup,
|
|
|
|
|
StrvArray4Type,
|
|
|
|
|
const char *const *,
|
|
|
|
|
{ nm_assert(name); },
|
|
|
|
|
{ return NULL; },
|
|
|
|
|
,
|
|
|
|
|
LL("zh_cn", "euc-cn", "gb2312", "gb18030"), /* Simplified Chinese, PRC */
|
|
|
|
|
LL("zh_hk", "big5", "euc-tw", "big5-hkcs"), /* Traditional Chinese, Hong Kong */
|
|
|
|
|
LL("zh_mo", "big5", "euc-tw"), /* Traditional Chinese, Macau */
|
|
|
|
|
LL("zh_sg", "euc-cn", "gb2312", "gb18030"), /* Simplified Chinese, Singapore */
|
|
|
|
|
LL("zh_tw", "big5", "euc-tw"), /* Traditional Chinese, Taiwan */
|
|
|
|
|
);
|
2014-07-24 08:53:33 -04:00
|
|
|
|
|
|
|
|
/* 2-letter language codes; we don't care about the other 3 in this table */
|
2022-01-02 20:43:09 +01:00
|
|
|
static _NM_UTILS_STRING_TABLE_LOOKUP_DEFINE(
|
|
|
|
|
_iso_lang_entries_2_lookup,
|
|
|
|
|
StrvArray4Type,
|
|
|
|
|
const char *const *,
|
|
|
|
|
{ nm_assert(name); },
|
|
|
|
|
{ return NULL; },
|
|
|
|
|
,
|
|
|
|
|
LL("ar", "iso-8859-6", "windows-1256"), /* Arabic */
|
|
|
|
|
LL("be", "koi8-r", "windows-1251", "iso-8859-5"), /* Cyrillic, Belorussian */
|
|
|
|
|
LL("bg", "windows-1251", "koi8-r", "iso-8859-5"), /* Cyrillic, Bulgarian */
|
|
|
|
|
LL("cs", "iso-8859-2", "windows-1250"), /* Central European, Czech */
|
|
|
|
|
LL("el", "iso-8859-7", "windows-1253"), /* Greek */
|
|
|
|
|
LL("et", "iso-8859-4", "windows-1257"), /* Baltic, Estonian */
|
|
|
|
|
LL("he", "iso-8859-8", "windows-1255"), /* Hebrew */
|
|
|
|
|
LL("hr", "iso-8859-2", "windows-1250"), /* Central European, Croatian */
|
|
|
|
|
LL("hu", "iso-8859-2", "windows-1250"), /* Central European, Hungarian */
|
|
|
|
|
LL("iw", "iso-8859-8", "windows-1255"), /* Hebrew */
|
|
|
|
|
LL("ja", "euc-jp", "shift_jis", "iso-2022-jp"), /* Japanese */
|
|
|
|
|
LL("ko", "euc-kr", "iso-2022-kr", "johab"), /* Korean */
|
|
|
|
|
LL("lt", "iso-8859-4", "windows-1257"), /* Baltic, Lithuanian */
|
|
|
|
|
LL("lv", "iso-8859-4", "windows-1257"), /* Baltic, Latvian */
|
|
|
|
|
LL("mk", "koi8-r", "windows-1251", "iso-8859-5"), /* Cyrillic, Macedonian */
|
|
|
|
|
LL("pl", "iso-8859-2", "windows-1250"), /* Central European, Polish */
|
|
|
|
|
LL("ro", "iso-8859-2", "windows-1250"), /* Central European, Romanian */
|
|
|
|
|
LL("ru", "koi8-r", "windows-1251", "iso-8859-5"), /* Cyrillic, Russian */
|
|
|
|
|
LL("sh", "iso-8859-2", "windows-1250"), /* Central European, Serbo-Croatian */
|
|
|
|
|
LL("sk", "iso-8859-2", "windows-1250"), /* Central European, Slovakian */
|
|
|
|
|
LL("sl", "iso-8859-2", "windows-1250"), /* Central European, Slovenian */
|
|
|
|
|
LL("sr", "koi8-r", "windows-1251", "iso-8859-5"), /* Cyrillic, Serbian */
|
|
|
|
|
LL("th", "iso-8859-11", "windows-874"), /* Thai */
|
|
|
|
|
LL("tr", "iso-8859-9", "windows-1254"), /* Turkish */
|
|
|
|
|
LL("uk", "koi8-u", "koi8-r", "windows-1251"), /* Cyrillic, Ukrainian */
|
|
|
|
|
);
|
2014-07-24 08:53:33 -04:00
|
|
|
|
2022-01-02 20:43:09 +01:00
|
|
|
static const char *const *
|
|
|
|
|
_system_encodings_for_lang(const char *lang)
|
2014-07-24 08:53:33 -04:00
|
|
|
{
|
2022-01-02 20:43:09 +01:00
|
|
|
char tmp_lang[3];
|
|
|
|
|
const char *const *e;
|
2014-07-24 08:53:33 -04:00
|
|
|
|
2022-01-02 20:43:09 +01:00
|
|
|
nm_assert(lang);
|
|
|
|
|
|
|
|
|
|
if (lang[0] == '\0' || lang[1] == '\0') {
|
|
|
|
|
/* need at least two characters. */
|
|
|
|
|
nm_assert(!_iso_lang_entries_5_lookup(lang));
|
|
|
|
|
nm_assert(!_iso_lang_entries_2_lookup(lang));
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2014-07-24 08:53:33 -04:00
|
|
|
|
2022-01-02 20:43:09 +01:00
|
|
|
if (lang[2] != '\0') {
|
|
|
|
|
nm_assert(!_iso_lang_entries_2_lookup(lang));
|
2014-07-24 08:53:33 -04:00
|
|
|
|
2022-01-02 20:43:09 +01:00
|
|
|
if (lang[3] != '\0' && lang[4] != '\0' && lang[5] == '\0') {
|
|
|
|
|
/* lang is 5 characters long. Try it. */
|
|
|
|
|
if ((e = _iso_lang_entries_5_lookup(lang)))
|
|
|
|
|
return e;
|
|
|
|
|
} else
|
|
|
|
|
nm_assert(!_iso_lang_entries_5_lookup(lang));
|
2014-07-24 08:53:33 -04:00
|
|
|
|
2022-01-02 20:43:09 +01:00
|
|
|
/* extract the first 2 characters and ignore the rest. */
|
|
|
|
|
tmp_lang[0] = lang[0];
|
|
|
|
|
tmp_lang[1] = lang[1];
|
2014-07-24 08:53:33 -04:00
|
|
|
tmp_lang[2] = '\0';
|
2022-01-02 20:43:09 +01:00
|
|
|
lang = tmp_lang;
|
2017-09-10 10:31:44 +02:00
|
|
|
}
|
|
|
|
|
|
2022-01-02 20:43:09 +01:00
|
|
|
if ((e = _iso_lang_entries_2_lookup(lang)))
|
|
|
|
|
return e;
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *const *
|
|
|
|
|
nmtst_system_encodings_for_lang(const char *lang)
|
|
|
|
|
{
|
|
|
|
|
return _system_encodings_for_lang(lang);
|
2017-09-10 10:31:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const char *const *
|
2022-01-02 20:43:09 +01:00
|
|
|
_system_encodings_get_default(void)
|
2017-09-10 10:31:44 +02:00
|
|
|
{
|
2022-01-02 20:43:09 +01:00
|
|
|
static gsize init_once = 0;
|
|
|
|
|
static const char *default_encodings[4];
|
|
|
|
|
|
|
|
|
|
if (g_once_init_enter(&init_once)) {
|
|
|
|
|
const char *e_default = NULL;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
g_get_charset(&e_default);
|
|
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
|
if (e_default)
|
|
|
|
|
default_encodings[i++] = e_default;
|
|
|
|
|
if (!nm_streq0(e_default, "iso-8859-1"))
|
|
|
|
|
default_encodings[i++] = "iso-8859-1";
|
|
|
|
|
if (!nm_streq0(e_default, "windows-1251"))
|
|
|
|
|
default_encodings[i++] = "windows-1251";
|
|
|
|
|
default_encodings[i++] = NULL;
|
|
|
|
|
nm_assert(i <= G_N_ELEMENTS(default_encodings));
|
|
|
|
|
|
|
|
|
|
g_once_init_leave(&init_once, 1);
|
2017-09-10 10:31:44 +02:00
|
|
|
}
|
2022-01-02 20:43:09 +01:00
|
|
|
|
|
|
|
|
return default_encodings;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *const *
|
|
|
|
|
nmtst_system_encodings_get_default(void)
|
|
|
|
|
{
|
|
|
|
|
return _system_encodings_get_default();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const char *const *
|
|
|
|
|
_system_encodings_get(void)
|
|
|
|
|
{
|
|
|
|
|
static const char *const *cached = NULL;
|
|
|
|
|
const char *const *e;
|
|
|
|
|
|
|
|
|
|
again:
|
|
|
|
|
if (!(e = g_atomic_pointer_get(&cached))) {
|
|
|
|
|
const char *lang;
|
|
|
|
|
|
|
|
|
|
/* Use environment variables as encoding hint */
|
|
|
|
|
lang = getenv("LC_ALL") ?: getenv("LC_CTYPE") ?: getenv("LANG");
|
|
|
|
|
|
|
|
|
|
if (lang) {
|
|
|
|
|
gs_free char *lang_down = NULL;
|
|
|
|
|
char *dot;
|
|
|
|
|
|
|
|
|
|
lang_down = g_ascii_strdown(lang, -1);
|
|
|
|
|
if ((dot = strchr(lang_down, '.')))
|
|
|
|
|
*dot = '\0';
|
|
|
|
|
e = _system_encodings_for_lang(lang_down);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!e)
|
|
|
|
|
e = _system_encodings_get_default();
|
|
|
|
|
|
|
|
|
|
/* in any case, @e is now a static buffer, that we may cache. */
|
|
|
|
|
nm_assert(e);
|
|
|
|
|
|
|
|
|
|
if (!g_atomic_pointer_compare_and_exchange(&cached, NULL, e))
|
|
|
|
|
goto again;
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2022-01-02 20:43:09 +01:00
|
|
|
return e;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *const *
|
|
|
|
|
nmtst_system_encodings_get(void)
|
|
|
|
|
{
|
|
|
|
|
return _system_encodings_get();
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
|
|
|
|
|
2018-06-30 11:25:38 +02:00
|
|
|
/*****************************************************************************/
|
2014-12-01 14:43:01 -05:00
|
|
|
|
2024-04-05 08:20:02 +02:00
|
|
|
static void __attribute__((constructor))
|
|
|
|
|
_nm_utils_init(void)
|
2014-07-25 17:50:14 -04:00
|
|
|
{
|
2018-06-30 11:25:38 +02:00
|
|
|
static int initialized = 0;
|
2014-07-25 17:50:14 -04:00
|
|
|
|
2018-06-30 11:25:38 +02:00
|
|
|
if (g_atomic_int_get(&initialized) != 0)
|
2014-12-01 14:43:01 -05:00
|
|
|
return;
|
2018-06-30 11:25:38 +02:00
|
|
|
|
|
|
|
|
/* we don't expect this code to run multiple times, nor on multiple threads.
|
|
|
|
|
*
|
|
|
|
|
* In practice, it would not be a problem if two threads concurrently try to
|
|
|
|
|
* run the initialization code below, all code below itself is thread-safe,
|
|
|
|
|
* Hence, a poor-man guard "initialized" above is more than sufficient,
|
|
|
|
|
* although it does not guarantee that the code is not run concurrently. */
|
2014-12-01 14:43:01 -05:00
|
|
|
|
2018-05-30 10:51:23 +02:00
|
|
|
bindtextdomain(GETTEXT_PACKAGE, NMLOCALEDIR);
|
2014-12-01 14:43:01 -05:00
|
|
|
bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
|
2014-07-24 08:53:33 -04:00
|
|
|
|
2014-12-01 14:43:01 -05:00
|
|
|
_nm_dbus_errors_init();
|
2018-06-30 11:25:38 +02:00
|
|
|
|
|
|
|
|
g_atomic_int_set(&initialized, 1);
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
|
|
|
|
|
2018-06-30 11:25:38 +02:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2014-11-14 11:46:19 -05:00
|
|
|
gboolean _nm_utils_is_manager_process;
|
|
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
/* ssid helpers */
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_utils_ssid_to_utf8:
|
2014-11-15 09:27:22 -05:00
|
|
|
* @ssid: (array length=len): pointer to a buffer containing the SSID data
|
2014-06-26 09:25:06 -04:00
|
|
|
* @len: length of the SSID data in @ssid
|
2014-07-24 08:53:33 -04:00
|
|
|
*
|
|
|
|
|
* Wi-Fi SSIDs are byte arrays, they are _not_ strings. Thus, an SSID may
|
|
|
|
|
* contain embedded NULLs and other unprintable characters. Often it is
|
|
|
|
|
* useful to print the SSID out for debugging purposes, but that should be the
|
|
|
|
|
* _only_ use of this function. Do not use this function for any persistent
|
|
|
|
|
* storage of the SSID, since the printable SSID returned from this function
|
|
|
|
|
* cannot be converted back into the real SSID of the access point.
|
|
|
|
|
*
|
|
|
|
|
* This function does almost everything humanly possible to convert the input
|
|
|
|
|
* into a printable UTF-8 string, using roughly the following procedure:
|
|
|
|
|
*
|
|
|
|
|
* 1) if the input data is already UTF-8 safe, no conversion is performed
|
|
|
|
|
* 2) attempts to get the current system language from the LANG environment
|
|
|
|
|
* variable, and depending on the language, uses a table of alternative
|
|
|
|
|
* encodings to try. For example, if LANG=hu_HU, the table may first try
|
|
|
|
|
* the ISO-8859-2 encoding, and if that fails, try the Windows-1250 encoding.
|
|
|
|
|
* If all fallback encodings fail, replaces non-UTF-8 characters with '?'.
|
|
|
|
|
* 3) If the system language was unable to be determined, falls back to the
|
|
|
|
|
* ISO-8859-1 encoding, then to the Windows-1251 encoding.
|
|
|
|
|
* 4) If step 3 fails, replaces non-UTF-8 characters with '?'.
|
|
|
|
|
*
|
|
|
|
|
* Again, this function should be used for debugging and display purposes
|
|
|
|
|
* _only_.
|
|
|
|
|
*
|
|
|
|
|
* Returns: (transfer full): an allocated string containing a UTF-8
|
|
|
|
|
* representation of the SSID, which must be freed by the caller using g_free().
|
|
|
|
|
* Returns %NULL on errors.
|
|
|
|
|
**/
|
|
|
|
|
char *
|
2014-06-26 09:25:06 -04:00
|
|
|
nm_utils_ssid_to_utf8(const guint8 *ssid, gsize len)
|
2014-07-24 08:53:33 -04:00
|
|
|
{
|
2017-09-10 10:31:44 +02:00
|
|
|
const char *const *encodings;
|
|
|
|
|
const char *const *e;
|
2021-11-09 13:28:54 +01:00
|
|
|
char *converted = NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
g_return_val_if_fail(ssid != NULL, NULL);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
all: don't use gchar/gshort/gint/glong but C types
We commonly don't use the glib typedefs for char/short/int/long,
but their C types directly.
$ git grep '\<g\(char\|short\|int\|long\|float\|double\)\>' | wc -l
587
$ git grep '\<\(char\|short\|int\|long\|float\|double\)\>' | wc -l
21114
One could argue that using the glib typedefs is preferable in
public API (of our glib based libnm library) or where it clearly
is related to glib, like during
g_object_set (obj, PROPERTY, (gint) value, NULL);
However, that argument does not seem strong, because in practice we don't
follow that argument today, and seldomly use the glib typedefs.
Also, the style guide for this would be hard to formalize, because
"using them where clearly related to a glib" is a very loose suggestion.
Also note that glib typedefs will always just be typedefs of the
underlying C types. There is no danger of glib changing the meaning
of these typedefs (because that would be a major API break of glib).
A simple style guide is instead: don't use these typedefs.
No manual actions, I only ran the bash script:
FILES=($(git ls-files '*.[hc]'))
sed -i \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\>\( [^ ]\)/\1\2/g' \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\> /\1 /g' \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\>/\1/g' \
"${FILES[@]}"
2018-07-11 07:40:19 +02:00
|
|
|
if (g_utf8_validate((const char *) ssid, len, NULL))
|
|
|
|
|
return g_strndup((const char *) ssid, len);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2022-01-02 20:43:09 +01:00
|
|
|
encodings = _system_encodings_get();
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-09-10 10:31:44 +02:00
|
|
|
for (e = encodings; *e; e++) {
|
all: don't use gchar/gshort/gint/glong but C types
We commonly don't use the glib typedefs for char/short/int/long,
but their C types directly.
$ git grep '\<g\(char\|short\|int\|long\|float\|double\)\>' | wc -l
587
$ git grep '\<\(char\|short\|int\|long\|float\|double\)\>' | wc -l
21114
One could argue that using the glib typedefs is preferable in
public API (of our glib based libnm library) or where it clearly
is related to glib, like during
g_object_set (obj, PROPERTY, (gint) value, NULL);
However, that argument does not seem strong, because in practice we don't
follow that argument today, and seldomly use the glib typedefs.
Also, the style guide for this would be hard to formalize, because
"using them where clearly related to a glib" is a very loose suggestion.
Also note that glib typedefs will always just be typedefs of the
underlying C types. There is no danger of glib changing the meaning
of these typedefs (because that would be a major API break of glib).
A simple style guide is instead: don't use these typedefs.
No manual actions, I only ran the bash script:
FILES=($(git ls-files '*.[hc]'))
sed -i \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\>\( [^ ]\)/\1\2/g' \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\> /\1 /g' \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\>/\1/g' \
"${FILES[@]}"
2018-07-11 07:40:19 +02:00
|
|
|
converted = g_convert((const char *) ssid, len, "UTF-8", *e, NULL, NULL, NULL);
|
2017-09-10 10:31:44 +02:00
|
|
|
if (converted)
|
|
|
|
|
break;
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
if (!converted) {
|
all: don't use gchar/gshort/gint/glong but C types
We commonly don't use the glib typedefs for char/short/int/long,
but their C types directly.
$ git grep '\<g\(char\|short\|int\|long\|float\|double\)\>' | wc -l
587
$ git grep '\<\(char\|short\|int\|long\|float\|double\)\>' | wc -l
21114
One could argue that using the glib typedefs is preferable in
public API (of our glib based libnm library) or where it clearly
is related to glib, like during
g_object_set (obj, PROPERTY, (gint) value, NULL);
However, that argument does not seem strong, because in practice we don't
follow that argument today, and seldomly use the glib typedefs.
Also, the style guide for this would be hard to formalize, because
"using them where clearly related to a glib" is a very loose suggestion.
Also note that glib typedefs will always just be typedefs of the
underlying C types. There is no danger of glib changing the meaning
of these typedefs (because that would be a major API break of glib).
A simple style guide is instead: don't use these typedefs.
No manual actions, I only ran the bash script:
FILES=($(git ls-files '*.[hc]'))
sed -i \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\>\( [^ ]\)/\1\2/g' \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\> /\1 /g' \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\>/\1/g' \
"${FILES[@]}"
2018-07-11 07:40:19 +02:00
|
|
|
converted = g_convert_with_fallback((const char *) ssid,
|
|
|
|
|
len,
|
2017-09-10 10:31:44 +02:00
|
|
|
"UTF-8",
|
|
|
|
|
encodings[0],
|
|
|
|
|
"?",
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL);
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-07-14 15:25:52 -04:00
|
|
|
if (!converted) {
|
|
|
|
|
/* If there is still no converted string, the SSID probably
|
|
|
|
|
* contains characters not valid in the current locale. Convert
|
|
|
|
|
* the string to ASCII instead.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* Use the printable range of 0x20-0x7E */
|
all: don't use gchar/gshort/gint/glong but C types
We commonly don't use the glib typedefs for char/short/int/long,
but their C types directly.
$ git grep '\<g\(char\|short\|int\|long\|float\|double\)\>' | wc -l
587
$ git grep '\<\(char\|short\|int\|long\|float\|double\)\>' | wc -l
21114
One could argue that using the glib typedefs is preferable in
public API (of our glib based libnm library) or where it clearly
is related to glib, like during
g_object_set (obj, PROPERTY, (gint) value, NULL);
However, that argument does not seem strong, because in practice we don't
follow that argument today, and seldomly use the glib typedefs.
Also, the style guide for this would be hard to formalize, because
"using them where clearly related to a glib" is a very loose suggestion.
Also note that glib typedefs will always just be typedefs of the
underlying C types. There is no danger of glib changing the meaning
of these typedefs (because that would be a major API break of glib).
A simple style guide is instead: don't use these typedefs.
No manual actions, I only ran the bash script:
FILES=($(git ls-files '*.[hc]'))
sed -i \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\>\( [^ ]\)/\1\2/g' \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\> /\1 /g' \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\>/\1/g' \
"${FILES[@]}"
2018-07-11 07:40:19 +02:00
|
|
|
char *valid_chars = " !\"#$%&'()*+,-./0123456789:;<=>?@"
|
2015-07-14 15:25:52 -04:00
|
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`"
|
|
|
|
|
"abcdefghijklmnopqrstuvwxyz{|}~";
|
|
|
|
|
|
2017-09-10 10:31:44 +02:00
|
|
|
converted = g_strndup((const char *) ssid, len);
|
2015-07-14 15:25:52 -04:00
|
|
|
g_strcanon(converted, valid_chars, '?');
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
return converted;
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-12 12:15:38 +02:00
|
|
|
char *
|
|
|
|
|
_nm_utils_ssid_to_utf8(GBytes *ssid)
|
|
|
|
|
{
|
|
|
|
|
const guint8 *p;
|
|
|
|
|
gsize l;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail(ssid, NULL);
|
|
|
|
|
|
|
|
|
|
p = g_bytes_get_data(ssid, &l);
|
|
|
|
|
return nm_utils_ssid_to_utf8(p, l);
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
/* Shamelessly ripped from the Linux kernel ieee80211 stack */
|
|
|
|
|
/**
|
|
|
|
|
* nm_utils_is_empty_ssid:
|
2014-11-15 09:27:22 -05:00
|
|
|
* @ssid: (array length=len): pointer to a buffer containing the SSID data
|
2014-07-24 08:53:33 -04:00
|
|
|
* @len: length of the SSID data in @ssid
|
|
|
|
|
*
|
|
|
|
|
* Different manufacturers use different mechanisms for not broadcasting the
|
|
|
|
|
* AP's SSID. This function attempts to detect blank/empty SSIDs using a
|
|
|
|
|
* number of known SSID-cloaking methods.
|
|
|
|
|
*
|
|
|
|
|
* Returns: %TRUE if the SSID is "empty", %FALSE if it is not
|
|
|
|
|
**/
|
|
|
|
|
gboolean
|
2014-06-26 09:25:06 -04:00
|
|
|
nm_utils_is_empty_ssid(const guint8 *ssid, gsize len)
|
2014-07-24 08:53:33 -04:00
|
|
|
{
|
2021-03-03 08:00:15 +01:00
|
|
|
return _nm_utils_is_empty_ssid_arr(ssid, len);
|
2018-08-12 12:15:38 +02:00
|
|
|
}
|
|
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
/**
|
|
|
|
|
* nm_utils_escape_ssid:
|
2014-11-15 09:27:22 -05:00
|
|
|
* @ssid: (array length=len): pointer to a buffer containing the SSID data
|
2014-07-24 08:53:33 -04:00
|
|
|
* @len: length of the SSID data in @ssid
|
|
|
|
|
*
|
|
|
|
|
* This function does a quick printable character conversion of the SSID, simply
|
|
|
|
|
* replacing embedded NULLs and non-printable characters with the hexadecimal
|
|
|
|
|
* representation of that character. Intended for debugging only, should not
|
|
|
|
|
* be used for display of SSIDs.
|
|
|
|
|
*
|
libnm: deprecate nm_utils_escape_ssid()
nm_utils_escape_ssid() uses a static buffer, which makes it non
thread-safe. We shouldn't have such API in libnm. We could improve that
by using a thread-local storage, but that brings overhead, for a
function that really isn't useful.
It's not useful, because the escaping is very naive. You are better
served with:
- nm_utils_ssid_to_utf8(): gives UTF-8, but looses information.
- nm_utils_bin2hexstr(): does not loose information, but makes the
name unreadable.
Maybe the best way to escape the SSID (which can be binary, but usually
is UTF-8), are the utf8safe functions. That is because it makes the
blob UFT-8, while not loosing/hiding any bytes (the escaping can be
reversed). This API is currently not exposed to the users, if there were
a need, then this could be done as a 3rd way for printing SSIDs.
However, nm_utils_escape_ssid() is bad either way. Deprecate.
2023-12-06 10:43:01 +01:00
|
|
|
* Warning: this function uses a static buffer. It is not thread-safe. Don't
|
|
|
|
|
* use this function.
|
|
|
|
|
*
|
2014-07-24 08:53:33 -04:00
|
|
|
* Returns: pointer to the escaped SSID, which uses an internal static buffer
|
|
|
|
|
* and will be overwritten by subsequent calls to this function
|
libnm: deprecate nm_utils_escape_ssid()
nm_utils_escape_ssid() uses a static buffer, which makes it non
thread-safe. We shouldn't have such API in libnm. We could improve that
by using a thread-local storage, but that brings overhead, for a
function that really isn't useful.
It's not useful, because the escaping is very naive. You are better
served with:
- nm_utils_ssid_to_utf8(): gives UTF-8, but looses information.
- nm_utils_bin2hexstr(): does not loose information, but makes the
name unreadable.
Maybe the best way to escape the SSID (which can be binary, but usually
is UTF-8), are the utf8safe functions. That is because it makes the
blob UFT-8, while not loosing/hiding any bytes (the escaping can be
reversed). This API is currently not exposed to the users, if there were
a need, then this could be done as a 3rd way for printing SSIDs.
However, nm_utils_escape_ssid() is bad either way. Deprecate.
2023-12-06 10:43:01 +01:00
|
|
|
*
|
|
|
|
|
* Deprecated: 1.46: use nm_utils_ssid_to_utf8() or nm_utils_bin2hexstr().
|
2014-07-24 08:53:33 -04:00
|
|
|
**/
|
|
|
|
|
const char *
|
2014-06-26 09:25:06 -04:00
|
|
|
nm_utils_escape_ssid(const guint8 *ssid, gsize len)
|
2014-07-24 08:53:33 -04:00
|
|
|
{
|
2021-03-18 11:29:45 +01:00
|
|
|
static char escaped[NM_IW_ESSID_MAX_SIZE * 2 + 1];
|
2014-07-24 08:53:33 -04:00
|
|
|
const guint8 *s = ssid;
|
2021-11-09 13:28:54 +01:00
|
|
|
char *d = escaped;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
if (nm_utils_is_empty_ssid(ssid, len)) {
|
|
|
|
|
memcpy(escaped, "<hidden>", sizeof("<hidden>"));
|
|
|
|
|
return escaped;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2023-10-27 14:36:56 +02:00
|
|
|
len = NM_MIN(len, (guint32) NM_IW_ESSID_MAX_SIZE);
|
2014-07-24 08:53:33 -04:00
|
|
|
while (len--) {
|
|
|
|
|
if (*s == '\0') {
|
|
|
|
|
*d++ = '\\';
|
|
|
|
|
*d++ = '0';
|
|
|
|
|
s++;
|
|
|
|
|
} else {
|
|
|
|
|
*d++ = *s++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
*d = '\0';
|
|
|
|
|
return escaped;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_utils_same_ssid:
|
2014-11-15 09:27:22 -05:00
|
|
|
* @ssid1: (array length=len1): the first SSID to compare
|
2014-06-26 09:25:06 -04:00
|
|
|
* @len1: length of the SSID data in @ssid1
|
2014-11-15 09:27:22 -05:00
|
|
|
* @ssid2: (array length=len2): the second SSID to compare
|
2014-06-26 09:25:06 -04:00
|
|
|
* @len2: length of the SSID data in @ssid2
|
2014-07-24 08:53:33 -04:00
|
|
|
* @ignore_trailing_null: %TRUE to ignore one trailing NULL byte
|
|
|
|
|
*
|
|
|
|
|
* Earlier versions of the Linux kernel added a NULL byte to the end of the
|
|
|
|
|
* SSID to enable easy printing of the SSID on the console or in a terminal,
|
|
|
|
|
* but this behavior was problematic (SSIDs are simply byte arrays, not strings)
|
|
|
|
|
* and thus was changed. This function compensates for that behavior at the
|
|
|
|
|
* cost of some compatibility with odd SSIDs that may legitimately have trailing
|
|
|
|
|
* NULLs, even though that is functionally pointless.
|
|
|
|
|
*
|
|
|
|
|
* Returns: %TRUE if the SSIDs are the same, %FALSE if they are not
|
|
|
|
|
**/
|
|
|
|
|
gboolean
|
2014-06-26 09:25:06 -04:00
|
|
|
nm_utils_same_ssid(const guint8 *ssid1,
|
|
|
|
|
gsize len1,
|
|
|
|
|
const guint8 *ssid2,
|
|
|
|
|
gsize len2,
|
2014-07-24 08:53:33 -04:00
|
|
|
gboolean ignore_trailing_null)
|
|
|
|
|
{
|
2014-06-26 09:25:06 -04:00
|
|
|
g_return_val_if_fail(ssid1 != NULL || len1 == 0, FALSE);
|
|
|
|
|
g_return_val_if_fail(ssid2 != NULL || len2 == 0, FALSE);
|
2014-07-24 08:53:33 -04:00
|
|
|
|
2014-06-26 09:25:06 -04:00
|
|
|
if (ssid1 == ssid2 && len1 == len2)
|
2014-07-24 08:53:33 -04:00
|
|
|
return TRUE;
|
|
|
|
|
if (!ssid1 || !ssid2)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2014-06-26 09:25:06 -04:00
|
|
|
if (ignore_trailing_null) {
|
|
|
|
|
if (len1 && ssid1[len1 - 1] == '\0')
|
|
|
|
|
len1--;
|
|
|
|
|
if (len2 && ssid2[len2 - 1] == '\0')
|
|
|
|
|
len2--;
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
|
|
|
|
|
2014-06-26 09:25:06 -04:00
|
|
|
if (len1 != len2)
|
2014-07-24 08:53:33 -04:00
|
|
|
return FALSE;
|
|
|
|
|
|
2014-06-26 09:25:06 -04:00
|
|
|
return memcmp(ssid1, ssid2, len1) == 0 ? TRUE : FALSE;
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
|
_nm_utils_string_slist_validate(GSList *list, const char **valid_values)
|
|
|
|
|
{
|
|
|
|
|
GSList *iter;
|
|
|
|
|
|
|
|
|
|
for (iter = list; iter; iter = iter->next) {
|
2016-06-17 11:40:50 +02:00
|
|
|
if (!g_strv_contains(valid_values, (char *) iter->data))
|
2014-07-24 08:53:33 -04:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-27 23:33:16 +02:00
|
|
|
/**
|
|
|
|
|
* _nm_utils_hash_values_to_slist:
|
|
|
|
|
* @hash: a #GHashTable
|
|
|
|
|
*
|
|
|
|
|
* Utility function to iterate over a hash table and return
|
2018-04-18 14:13:28 +02:00
|
|
|
* its values as a #GSList.
|
2014-07-27 23:33:16 +02:00
|
|
|
*
|
|
|
|
|
* Returns: (element-type gpointer) (transfer container): a newly allocated #GSList
|
|
|
|
|
* containing the values of the hash table. The caller must free the
|
|
|
|
|
* returned list with g_slist_free(). The hash values are not owned
|
|
|
|
|
* by the returned list.
|
|
|
|
|
**/
|
|
|
|
|
GSList *
|
|
|
|
|
_nm_utils_hash_values_to_slist(GHashTable *hash)
|
|
|
|
|
{
|
2021-11-09 13:28:54 +01:00
|
|
|
GSList *list = NULL;
|
2014-07-27 23:33:16 +02:00
|
|
|
GHashTableIter iter;
|
2021-11-09 13:28:54 +01:00
|
|
|
void *value;
|
2014-07-27 23:33:16 +02:00
|
|
|
|
|
|
|
|
g_return_val_if_fail(hash, NULL);
|
|
|
|
|
|
|
|
|
|
g_hash_table_iter_init(&iter, hash);
|
|
|
|
|
while (g_hash_table_iter_next(&iter, NULL, &value))
|
|
|
|
|
list = g_slist_prepend(list, value);
|
|
|
|
|
|
|
|
|
|
return list;
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-24 17:40:08 -04:00
|
|
|
void
|
libnm: use macros function arguments for NMSettInfoPropertType
These functions tend to have many arguments. They are also quite som
boilerplate to implement the hundereds of properties we have, while
we want that properties have common behaviors and similarities.
Instead of repeatedly spelling out the function arguments, use a macro.
Advantages:
- the usage of a _NM_SETT_INFO_PROP_*_FCN_ARGS macro signals that this
is an implementation of a property. You can now grep for these macros
to find all implementation. That was previously rather imprecise, you
could only `git grep '\.to_dbus_fcn'` to find the uses, but not the
implementations.
As the goal is to keep properties "similar", there is a desire to
reduce the number of similar implementations and to find them.
- changing the arguments now no longer will require you to go through
all implementations. At least not, if you merely add an argument that
has a reasonable default behavior and does not require explicit
handling by most implementation.
- it's convenient to be able to patch the argument list to let the
compiler help to reason about something. For example, the
"connection_dict" argument to from_dbus_fcn() is usually unused.
If you'd like to find who uses it, rename the parameter, and
review the (few) compiler errors.
- it does save 573 LOC of boilerplate with no actual logic or useful
information. I argue, that this simplifies the code and review, by
increasing the relative amount of actually meaningful code.
Disadvantages:
- the user no longer directly sees the argument list. They would need
cscope/ctags or an IDE to jump to the macro definition and conveniently
see all arguments.
Also use _nm_nil, so that clang-format interprets this as a function
parameter list. Otherwise, it formats the function differently.
2021-07-26 23:45:31 +02:00
|
|
|
_nm_utils_strdict_from_dbus(_NM_SETT_INFO_PROP_FROM_DBUS_GPROP_FCN_ARGS _nm_nil)
|
2014-06-24 17:40:08 -04:00
|
|
|
{
|
2014-08-16 10:09:48 -04:00
|
|
|
GVariantIter iter;
|
2021-11-09 13:28:54 +01:00
|
|
|
const char *key, *value;
|
|
|
|
|
GHashTable *hash;
|
2014-08-16 10:09:48 -04:00
|
|
|
|
2017-11-15 16:06:43 +01:00
|
|
|
hash = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, g_free);
|
libnm: use macros function arguments for NMSettInfoPropertType
These functions tend to have many arguments. They are also quite som
boilerplate to implement the hundereds of properties we have, while
we want that properties have common behaviors and similarities.
Instead of repeatedly spelling out the function arguments, use a macro.
Advantages:
- the usage of a _NM_SETT_INFO_PROP_*_FCN_ARGS macro signals that this
is an implementation of a property. You can now grep for these macros
to find all implementation. That was previously rather imprecise, you
could only `git grep '\.to_dbus_fcn'` to find the uses, but not the
implementations.
As the goal is to keep properties "similar", there is a desire to
reduce the number of similar implementations and to find them.
- changing the arguments now no longer will require you to go through
all implementations. At least not, if you merely add an argument that
has a reasonable default behavior and does not require explicit
handling by most implementation.
- it's convenient to be able to patch the argument list to let the
compiler help to reason about something. For example, the
"connection_dict" argument to from_dbus_fcn() is usually unused.
If you'd like to find who uses it, rename the parameter, and
review the (few) compiler errors.
- it does save 573 LOC of boilerplate with no actual logic or useful
information. I argue, that this simplifies the code and review, by
increasing the relative amount of actually meaningful code.
Disadvantages:
- the user no longer directly sees the argument list. They would need
cscope/ctags or an IDE to jump to the macro definition and conveniently
see all arguments.
Also use _nm_nil, so that clang-format interprets this as a function
parameter list. Otherwise, it formats the function differently.
2021-07-26 23:45:31 +02:00
|
|
|
g_variant_iter_init(&iter, from);
|
2014-08-16 10:09:48 -04:00
|
|
|
while (g_variant_iter_next(&iter, "{&s&s}", &key, &value))
|
|
|
|
|
g_hash_table_insert(hash, g_strdup(key), g_strdup(value));
|
|
|
|
|
|
libnm: use macros function arguments for NMSettInfoPropertType
These functions tend to have many arguments. They are also quite som
boilerplate to implement the hundereds of properties we have, while
we want that properties have common behaviors and similarities.
Instead of repeatedly spelling out the function arguments, use a macro.
Advantages:
- the usage of a _NM_SETT_INFO_PROP_*_FCN_ARGS macro signals that this
is an implementation of a property. You can now grep for these macros
to find all implementation. That was previously rather imprecise, you
could only `git grep '\.to_dbus_fcn'` to find the uses, but not the
implementations.
As the goal is to keep properties "similar", there is a desire to
reduce the number of similar implementations and to find them.
- changing the arguments now no longer will require you to go through
all implementations. At least not, if you merely add an argument that
has a reasonable default behavior and does not require explicit
handling by most implementation.
- it's convenient to be able to patch the argument list to let the
compiler help to reason about something. For example, the
"connection_dict" argument to from_dbus_fcn() is usually unused.
If you'd like to find who uses it, rename the parameter, and
review the (few) compiler errors.
- it does save 573 LOC of boilerplate with no actual logic or useful
information. I argue, that this simplifies the code and review, by
increasing the relative amount of actually meaningful code.
Disadvantages:
- the user no longer directly sees the argument list. They would need
cscope/ctags or an IDE to jump to the macro definition and conveniently
see all arguments.
Also use _nm_nil, so that clang-format interprets this as a function
parameter list. Otherwise, it formats the function differently.
2021-07-26 23:45:31 +02:00
|
|
|
g_value_take_boxed(to, hash);
|
2014-06-24 17:40:08 -04:00
|
|
|
}
|
|
|
|
|
|
2021-06-18 09:59:40 +02:00
|
|
|
const NMSettInfoPropertType nm_sett_info_propert_type_strdict =
|
|
|
|
|
NM_SETT_INFO_PROPERT_TYPE_GPROP_INIT(NM_G_VARIANT_TYPE("a{ss}"),
|
2021-06-30 00:05:49 +02:00
|
|
|
.typdata_from_dbus.gprop_fcn = _nm_utils_strdict_from_dbus,
|
2021-06-18 12:27:12 +02:00
|
|
|
.typdata_to_dbus.gprop_type =
|
2021-06-29 14:23:16 +02:00
|
|
|
NM_SETTING_PROPERTY_TO_DBUS_FCN_GPROP_TYPE_STRDICT,
|
2021-06-30 00:05:49 +02:00
|
|
|
.compare_fcn = _nm_setting_property_compare_fcn_default,
|
|
|
|
|
.from_dbus_fcn = _nm_setting_property_from_dbus_fcn_gprop,
|
|
|
|
|
.from_dbus_is_full = TRUE);
|
2019-09-22 10:57:57 +02:00
|
|
|
|
2014-06-24 17:40:08 -04:00
|
|
|
GHashTable *
|
|
|
|
|
_nm_utils_copy_strdict(GHashTable *strdict)
|
|
|
|
|
{
|
2021-11-09 13:28:54 +01:00
|
|
|
GHashTable *copy;
|
2014-06-24 17:40:08 -04:00
|
|
|
GHashTableIter iter;
|
|
|
|
|
gpointer key, value;
|
|
|
|
|
|
2017-11-15 16:06:43 +01:00
|
|
|
copy = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, g_free);
|
2014-06-24 17:40:08 -04:00
|
|
|
if (strdict) {
|
|
|
|
|
g_hash_table_iter_init(&iter, strdict);
|
|
|
|
|
while (g_hash_table_iter_next(&iter, &key, &value))
|
|
|
|
|
g_hash_table_insert(copy, g_strdup(key), g_strdup(value));
|
|
|
|
|
}
|
|
|
|
|
return copy;
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-26 08:31:04 -04:00
|
|
|
GPtrArray *
|
|
|
|
|
_nm_utils_copy_array(const GPtrArray *array, NMUtilsCopyFunc copy_func, GDestroyNotify free_func)
|
|
|
|
|
{
|
|
|
|
|
GPtrArray *copy;
|
2020-10-29 12:36:22 +01:00
|
|
|
guint i;
|
2014-08-26 08:31:04 -04:00
|
|
|
|
2014-09-15 15:58:16 -04:00
|
|
|
if (!array)
|
|
|
|
|
return g_ptr_array_new_with_free_func(free_func);
|
|
|
|
|
|
2014-08-26 08:31:04 -04:00
|
|
|
copy = g_ptr_array_new_full(array->len, free_func);
|
|
|
|
|
for (i = 0; i < array->len; i++)
|
|
|
|
|
g_ptr_array_add(copy, copy_func(array->pdata[i]));
|
|
|
|
|
return copy;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GPtrArray *
|
|
|
|
|
_nm_utils_copy_object_array(const GPtrArray *array)
|
|
|
|
|
{
|
|
|
|
|
return _nm_utils_copy_array(array, g_object_ref, g_object_unref);
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-26 10:42:11 -04:00
|
|
|
void
|
2014-08-16 10:09:48 -04:00
|
|
|
_nm_utils_bytes_from_dbus(GVariant *dbus_value, GValue *prop_value)
|
2014-06-26 10:42:11 -04:00
|
|
|
{
|
2014-08-16 10:09:48 -04:00
|
|
|
GBytes *bytes;
|
2014-06-26 10:42:11 -04:00
|
|
|
|
2014-08-16 10:09:48 -04:00
|
|
|
if (g_variant_n_children(dbus_value)) {
|
|
|
|
|
gconstpointer data;
|
|
|
|
|
gsize length;
|
|
|
|
|
|
|
|
|
|
data = g_variant_get_fixed_array(dbus_value, &length, 1);
|
|
|
|
|
bytes = g_bytes_new(data, length);
|
|
|
|
|
} else
|
|
|
|
|
bytes = NULL;
|
2014-06-26 10:42:11 -04:00
|
|
|
g_value_take_boxed(prop_value, bytes);
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-27 16:16:41 +02:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2014-08-21 13:19:53 -04:00
|
|
|
GSList *
|
2021-07-29 10:02:11 +02:00
|
|
|
nm_strv_to_gslist(char **strv, gboolean deep_copy)
|
2014-08-21 13:19:53 -04:00
|
|
|
{
|
|
|
|
|
GSList *list = NULL;
|
2019-05-27 16:16:41 +02:00
|
|
|
gsize i;
|
2014-08-21 13:19:53 -04:00
|
|
|
|
2019-05-27 16:16:41 +02:00
|
|
|
if (!strv)
|
|
|
|
|
return NULL;
|
2014-08-21 13:19:53 -04:00
|
|
|
|
2019-05-27 16:16:41 +02:00
|
|
|
if (deep_copy) {
|
|
|
|
|
for (i = 0; strv[i]; i++)
|
|
|
|
|
list = g_slist_prepend(list, g_strdup(strv[i]));
|
|
|
|
|
} else {
|
|
|
|
|
for (i = 0; strv[i]; i++)
|
|
|
|
|
list = g_slist_prepend(list, strv[i]);
|
|
|
|
|
}
|
2014-08-21 13:19:53 -04:00
|
|
|
return g_slist_reverse(list);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char **
|
2019-05-27 16:16:41 +02:00
|
|
|
_nm_utils_slist_to_strv(const GSList *slist, gboolean deep_copy)
|
2014-08-21 13:19:53 -04:00
|
|
|
{
|
2019-05-27 16:16:41 +02:00
|
|
|
const GSList *iter;
|
2021-11-09 13:28:54 +01:00
|
|
|
char **strv;
|
2019-05-27 16:16:41 +02:00
|
|
|
guint len, i;
|
2014-08-21 13:19:53 -04:00
|
|
|
|
2019-05-27 16:16:41 +02:00
|
|
|
if (!slist)
|
2017-01-23 14:26:06 +01:00
|
|
|
return NULL;
|
2019-05-27 16:16:41 +02:00
|
|
|
|
|
|
|
|
len = g_slist_length((GSList *) slist);
|
|
|
|
|
|
2014-08-21 13:19:53 -04:00
|
|
|
strv = g_new(char *, len + 1);
|
|
|
|
|
|
2015-07-01 14:08:51 +02:00
|
|
|
if (deep_copy) {
|
2019-05-27 16:16:41 +02:00
|
|
|
for (i = 0, iter = slist; iter; iter = iter->next, i++) {
|
|
|
|
|
nm_assert(iter->data);
|
2015-07-01 14:08:51 +02:00
|
|
|
strv[i] = g_strdup(iter->data);
|
2019-05-27 16:16:41 +02:00
|
|
|
}
|
2015-07-01 14:08:51 +02:00
|
|
|
} else {
|
2019-05-27 16:16:41 +02:00
|
|
|
for (i = 0, iter = slist; iter; iter = iter->next, i++) {
|
|
|
|
|
nm_assert(iter->data);
|
2015-07-01 14:08:51 +02:00
|
|
|
strv[i] = iter->data;
|
2019-05-27 16:16:41 +02:00
|
|
|
}
|
2015-07-01 14:08:51 +02:00
|
|
|
}
|
2014-08-21 13:19:53 -04:00
|
|
|
strv[i] = NULL;
|
|
|
|
|
|
|
|
|
|
return strv;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-27 16:16:41 +02:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
static gboolean
|
|
|
|
|
device_supports_ap_ciphers(guint32 dev_caps, guint32 ap_flags, gboolean static_wep)
|
|
|
|
|
{
|
|
|
|
|
gboolean have_pair = FALSE;
|
|
|
|
|
gboolean have_group = FALSE;
|
|
|
|
|
/* Device needs to support at least one pairwise and one group cipher */
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
/* Pairwise */
|
|
|
|
|
if (static_wep) {
|
|
|
|
|
/* Static WEP only uses group ciphers */
|
|
|
|
|
have_pair = TRUE;
|
|
|
|
|
} else {
|
|
|
|
|
if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_WEP40)
|
|
|
|
|
if (ap_flags & NM_802_11_AP_SEC_PAIR_WEP40)
|
|
|
|
|
have_pair = TRUE;
|
|
|
|
|
if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_WEP104)
|
|
|
|
|
if (ap_flags & NM_802_11_AP_SEC_PAIR_WEP104)
|
|
|
|
|
have_pair = TRUE;
|
|
|
|
|
if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP)
|
|
|
|
|
if (ap_flags & NM_802_11_AP_SEC_PAIR_TKIP)
|
|
|
|
|
have_pair = TRUE;
|
|
|
|
|
if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP)
|
|
|
|
|
if (ap_flags & NM_802_11_AP_SEC_PAIR_CCMP)
|
|
|
|
|
have_pair = TRUE;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
/* Group */
|
|
|
|
|
if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_WEP40)
|
|
|
|
|
if (ap_flags & NM_802_11_AP_SEC_GROUP_WEP40)
|
|
|
|
|
have_group = TRUE;
|
|
|
|
|
if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_WEP104)
|
|
|
|
|
if (ap_flags & NM_802_11_AP_SEC_GROUP_WEP104)
|
|
|
|
|
have_group = TRUE;
|
|
|
|
|
if (!static_wep) {
|
|
|
|
|
if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP)
|
|
|
|
|
if (ap_flags & NM_802_11_AP_SEC_GROUP_TKIP)
|
|
|
|
|
have_group = TRUE;
|
|
|
|
|
if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP)
|
|
|
|
|
if (ap_flags & NM_802_11_AP_SEC_GROUP_CCMP)
|
|
|
|
|
have_group = TRUE;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
return (have_pair && have_group);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_utils_ap_mode_security_valid:
|
2018-09-15 07:20:54 -04:00
|
|
|
* @type: the security type to check device capabilities against,
|
2014-07-24 08:53:33 -04:00
|
|
|
* e.g. #NMU_SEC_STATIC_WEP
|
|
|
|
|
* @wifi_caps: bitfield of the capabilities of the specific Wi-Fi device, e.g.
|
|
|
|
|
* #NM_WIFI_DEVICE_CAP_CIPHER_WEP40
|
|
|
|
|
*
|
|
|
|
|
* Given a set of device capabilities, and a desired security type to check
|
|
|
|
|
* against, determines whether the combination of device capabilities and
|
|
|
|
|
* desired security type are valid for AP/Hotspot connections.
|
|
|
|
|
*
|
|
|
|
|
* Returns: %TRUE if the device capabilities are compatible with the desired
|
|
|
|
|
* @type, %FALSE if they are not.
|
|
|
|
|
**/
|
|
|
|
|
gboolean
|
|
|
|
|
nm_utils_ap_mode_security_valid(NMUtilsSecurityType type, NMDeviceWifiCapabilities wifi_caps)
|
|
|
|
|
{
|
|
|
|
|
if (!(wifi_caps & NM_WIFI_DEVICE_CAP_AP))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* Return TRUE for any security that wpa_supplicant's lightweight AP
|
|
|
|
|
* mode can handle: which is open, WEP, and WPA/WPA2 PSK.
|
|
|
|
|
*/
|
|
|
|
|
switch (type) {
|
|
|
|
|
case NMU_SEC_NONE:
|
|
|
|
|
case NMU_SEC_STATIC_WEP:
|
|
|
|
|
case NMU_SEC_WPA_PSK:
|
|
|
|
|
case NMU_SEC_WPA2_PSK:
|
2019-10-04 11:37:45 +02:00
|
|
|
case NMU_SEC_SAE:
|
2019-11-17 23:57:15 +01:00
|
|
|
case NMU_SEC_OWE:
|
2014-07-24 08:53:33 -04:00
|
|
|
return TRUE;
|
2020-01-02 14:42:28 +01:00
|
|
|
case NMU_SEC_LEAP:
|
|
|
|
|
case NMU_SEC_DYNAMIC_WEP:
|
|
|
|
|
case NMU_SEC_WPA_ENTERPRISE:
|
|
|
|
|
case NMU_SEC_WPA2_ENTERPRISE:
|
2020-12-15 19:05:11 +01:00
|
|
|
case NMU_SEC_WPA3_SUITE_B_192:
|
2020-01-02 14:42:28 +01:00
|
|
|
return FALSE;
|
|
|
|
|
case NMU_SEC_INVALID:
|
2014-07-24 08:53:33 -04:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_utils_security_valid:
|
2018-09-15 07:20:54 -04:00
|
|
|
* @type: the security type to check AP flags and device capabilities against,
|
2014-07-24 08:53:33 -04:00
|
|
|
* e.g. #NMU_SEC_STATIC_WEP
|
|
|
|
|
* @wifi_caps: bitfield of the capabilities of the specific Wi-Fi device, e.g.
|
|
|
|
|
* #NM_WIFI_DEVICE_CAP_CIPHER_WEP40
|
|
|
|
|
* @have_ap: whether the @ap_flags, @ap_wpa, and @ap_rsn arguments are valid
|
|
|
|
|
* @adhoc: whether the capabilities being tested are from an Ad-Hoc AP (IBSS)
|
|
|
|
|
* @ap_flags: bitfield of AP capabilities, e.g. #NM_802_11_AP_FLAGS_PRIVACY
|
2018-09-15 07:20:54 -04:00
|
|
|
* @ap_wpa: bitfield of AP capabilities derived from the AP's WPA beacon,
|
2014-07-24 08:53:33 -04:00
|
|
|
* e.g. (#NM_802_11_AP_SEC_PAIR_TKIP | #NM_802_11_AP_SEC_KEY_MGMT_PSK)
|
2018-09-15 07:20:54 -04:00
|
|
|
* @ap_rsn: bitfield of AP capabilities derived from the AP's RSN/WPA2 beacon,
|
2014-07-24 08:53:33 -04:00
|
|
|
* e.g. (#NM_802_11_AP_SEC_PAIR_CCMP | #NM_802_11_AP_SEC_PAIR_TKIP)
|
|
|
|
|
*
|
|
|
|
|
* Given a set of device capabilities, and a desired security type to check
|
|
|
|
|
* against, determines whether the combination of device, desired security
|
|
|
|
|
* type, and AP capabilities intersect.
|
|
|
|
|
*
|
|
|
|
|
* NOTE: this function cannot handle checking security for AP/Hotspot mode;
|
|
|
|
|
* use nm_utils_ap_mode_security_valid() instead.
|
|
|
|
|
*
|
2018-09-15 07:20:54 -04:00
|
|
|
* Returns: %TRUE if the device capabilities and AP capabilities intersect and are
|
2014-07-24 08:53:33 -04:00
|
|
|
* compatible with the desired @type, %FALSE if they are not
|
|
|
|
|
**/
|
|
|
|
|
gboolean
|
|
|
|
|
nm_utils_security_valid(NMUtilsSecurityType type,
|
|
|
|
|
NMDeviceWifiCapabilities wifi_caps,
|
|
|
|
|
gboolean have_ap,
|
|
|
|
|
gboolean adhoc,
|
|
|
|
|
NM80211ApFlags ap_flags,
|
|
|
|
|
NM80211ApSecurityFlags ap_wpa,
|
|
|
|
|
NM80211ApSecurityFlags ap_rsn)
|
|
|
|
|
{
|
|
|
|
|
switch (type) {
|
|
|
|
|
case NMU_SEC_NONE:
|
2020-01-02 15:03:39 +01:00
|
|
|
if (!have_ap)
|
|
|
|
|
return TRUE;
|
2014-07-24 08:53:33 -04:00
|
|
|
if (ap_flags & NM_802_11_AP_FLAGS_PRIVACY)
|
|
|
|
|
return FALSE;
|
2020-01-02 15:09:34 +01:00
|
|
|
if (ap_wpa || ap_rsn)
|
2014-07-24 08:53:33 -04:00
|
|
|
return FALSE;
|
2020-01-02 14:42:28 +01:00
|
|
|
return TRUE;
|
2014-07-24 08:53:33 -04:00
|
|
|
case NMU_SEC_LEAP: /* require PRIVACY bit for LEAP? */
|
|
|
|
|
if (adhoc)
|
|
|
|
|
return FALSE;
|
2020-02-21 12:56:03 +01:00
|
|
|
/* fall-through */
|
2014-07-24 08:53:33 -04:00
|
|
|
case NMU_SEC_STATIC_WEP:
|
2020-01-02 15:03:39 +01:00
|
|
|
if (!have_ap) {
|
|
|
|
|
if (wifi_caps & (NM_WIFI_DEVICE_CAP_CIPHER_WEP40 | NM_WIFI_DEVICE_CAP_CIPHER_WEP104))
|
|
|
|
|
return TRUE;
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2014-07-24 08:53:33 -04:00
|
|
|
if (!(ap_flags & NM_802_11_AP_FLAGS_PRIVACY))
|
|
|
|
|
return FALSE;
|
2020-01-02 15:09:34 +01:00
|
|
|
if (ap_wpa || ap_rsn) {
|
2020-01-02 15:03:39 +01:00
|
|
|
if (!device_supports_ap_ciphers(wifi_caps, ap_wpa, TRUE)) {
|
2014-07-24 08:53:33 -04:00
|
|
|
if (!device_supports_ap_ciphers(wifi_caps, ap_rsn, TRUE))
|
|
|
|
|
return FALSE;
|
2020-09-28 16:03:33 +02:00
|
|
|
}
|
2020-01-02 15:03:39 +01:00
|
|
|
}
|
2020-01-02 14:42:28 +01:00
|
|
|
return TRUE;
|
2014-07-24 08:53:33 -04:00
|
|
|
case NMU_SEC_DYNAMIC_WEP:
|
|
|
|
|
if (adhoc)
|
|
|
|
|
return FALSE;
|
2020-01-02 15:03:39 +01:00
|
|
|
if (!have_ap) {
|
|
|
|
|
if (wifi_caps & (NM_WIFI_DEVICE_CAP_CIPHER_WEP40 | NM_WIFI_DEVICE_CAP_CIPHER_WEP104))
|
|
|
|
|
return TRUE;
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2020-01-02 15:09:34 +01:00
|
|
|
if (ap_rsn || !(ap_flags & NM_802_11_AP_FLAGS_PRIVACY))
|
2014-07-24 08:53:33 -04:00
|
|
|
return FALSE;
|
|
|
|
|
/* Some APs broadcast minimal WPA-enabled beacons that must be handled */
|
|
|
|
|
if (ap_wpa) {
|
|
|
|
|
if (!(ap_wpa & NM_802_11_AP_SEC_KEY_MGMT_802_1X))
|
|
|
|
|
return FALSE;
|
|
|
|
|
if (!device_supports_ap_ciphers(wifi_caps, ap_wpa, FALSE))
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2020-01-02 14:42:28 +01:00
|
|
|
return TRUE;
|
2014-07-24 08:53:33 -04:00
|
|
|
case NMU_SEC_WPA_PSK:
|
|
|
|
|
if (adhoc)
|
2019-08-19 18:04:48 +02:00
|
|
|
return FALSE;
|
2014-07-24 08:53:33 -04:00
|
|
|
if (!(wifi_caps & NM_WIFI_DEVICE_CAP_WPA))
|
|
|
|
|
return FALSE;
|
2020-01-02 15:12:15 +01:00
|
|
|
if (!have_ap)
|
|
|
|
|
return TRUE;
|
|
|
|
|
if (ap_wpa & NM_802_11_AP_SEC_KEY_MGMT_PSK) {
|
|
|
|
|
if ((ap_wpa & NM_802_11_AP_SEC_PAIR_TKIP)
|
|
|
|
|
&& (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP))
|
|
|
|
|
return TRUE;
|
|
|
|
|
if ((ap_wpa & NM_802_11_AP_SEC_PAIR_CCMP)
|
|
|
|
|
&& (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP))
|
|
|
|
|
return TRUE;
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
2020-01-02 15:12:15 +01:00
|
|
|
return FALSE;
|
2014-07-24 08:53:33 -04:00
|
|
|
case NMU_SEC_WPA2_PSK:
|
|
|
|
|
if (!(wifi_caps & NM_WIFI_DEVICE_CAP_RSN))
|
|
|
|
|
return FALSE;
|
2020-01-02 15:12:15 +01:00
|
|
|
if (!have_ap)
|
|
|
|
|
return TRUE;
|
|
|
|
|
if (adhoc) {
|
|
|
|
|
if (!(wifi_caps & NM_WIFI_DEVICE_CAP_IBSS_RSN))
|
|
|
|
|
return FALSE;
|
|
|
|
|
if ((ap_rsn & NM_802_11_AP_SEC_PAIR_CCMP)
|
|
|
|
|
&& (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP))
|
|
|
|
|
return TRUE;
|
2014-07-24 08:53:33 -04:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
2020-01-02 15:12:15 +01:00
|
|
|
if (ap_rsn & NM_802_11_AP_SEC_KEY_MGMT_PSK) {
|
|
|
|
|
if ((ap_rsn & NM_802_11_AP_SEC_PAIR_TKIP)
|
|
|
|
|
&& (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP))
|
|
|
|
|
return TRUE;
|
|
|
|
|
if ((ap_rsn & NM_802_11_AP_SEC_PAIR_CCMP)
|
|
|
|
|
&& (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP))
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
return FALSE;
|
2014-07-24 08:53:33 -04:00
|
|
|
case NMU_SEC_WPA_ENTERPRISE:
|
|
|
|
|
if (adhoc)
|
|
|
|
|
return FALSE;
|
|
|
|
|
if (!(wifi_caps & NM_WIFI_DEVICE_CAP_WPA))
|
|
|
|
|
return FALSE;
|
2020-01-02 15:12:15 +01:00
|
|
|
if (!have_ap)
|
|
|
|
|
return TRUE;
|
|
|
|
|
if (!(ap_wpa & NM_802_11_AP_SEC_KEY_MGMT_802_1X))
|
|
|
|
|
return FALSE;
|
|
|
|
|
/* Ensure at least one WPA cipher is supported */
|
|
|
|
|
if (!device_supports_ap_ciphers(wifi_caps, ap_wpa, FALSE))
|
|
|
|
|
return FALSE;
|
2020-01-02 14:42:28 +01:00
|
|
|
return TRUE;
|
2014-07-24 08:53:33 -04:00
|
|
|
case NMU_SEC_WPA2_ENTERPRISE:
|
|
|
|
|
if (adhoc)
|
|
|
|
|
return FALSE;
|
|
|
|
|
if (!(wifi_caps & NM_WIFI_DEVICE_CAP_RSN))
|
|
|
|
|
return FALSE;
|
2020-01-02 15:12:15 +01:00
|
|
|
if (!have_ap)
|
|
|
|
|
return TRUE;
|
|
|
|
|
if (!(ap_rsn & NM_802_11_AP_SEC_KEY_MGMT_802_1X))
|
|
|
|
|
return FALSE;
|
|
|
|
|
/* Ensure at least one WPA cipher is supported */
|
|
|
|
|
if (!device_supports_ap_ciphers(wifi_caps, ap_rsn, FALSE))
|
|
|
|
|
return FALSE;
|
2020-01-02 14:42:28 +01:00
|
|
|
return TRUE;
|
2019-10-04 11:37:45 +02:00
|
|
|
case NMU_SEC_SAE:
|
|
|
|
|
if (!(wifi_caps & NM_WIFI_DEVICE_CAP_RSN))
|
|
|
|
|
return FALSE;
|
2020-01-07 11:28:25 +01:00
|
|
|
if (adhoc)
|
|
|
|
|
return FALSE;
|
2020-01-02 15:12:15 +01:00
|
|
|
if (!have_ap)
|
|
|
|
|
return TRUE;
|
|
|
|
|
if (ap_rsn & NM_802_11_AP_SEC_KEY_MGMT_SAE) {
|
|
|
|
|
if ((ap_rsn & NM_802_11_AP_SEC_PAIR_CCMP)
|
|
|
|
|
&& (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP))
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
return FALSE;
|
2019-11-17 23:57:15 +01:00
|
|
|
case NMU_SEC_OWE:
|
|
|
|
|
if (adhoc)
|
|
|
|
|
return FALSE;
|
|
|
|
|
if (!(wifi_caps & NM_WIFI_DEVICE_CAP_RSN))
|
|
|
|
|
return FALSE;
|
2020-01-02 15:12:15 +01:00
|
|
|
if (!have_ap)
|
|
|
|
|
return TRUE;
|
2020-05-09 03:30:21 +02:00
|
|
|
if (!NM_FLAGS_ANY(ap_rsn, NM_802_11_AP_SEC_KEY_MGMT_OWE | NM_802_11_AP_SEC_KEY_MGMT_OWE_TM))
|
2020-01-02 15:12:15 +01:00
|
|
|
return FALSE;
|
2020-01-02 14:42:28 +01:00
|
|
|
return TRUE;
|
2020-12-15 19:05:11 +01:00
|
|
|
case NMU_SEC_WPA3_SUITE_B_192:
|
|
|
|
|
if (adhoc)
|
|
|
|
|
return FALSE;
|
|
|
|
|
if (!(wifi_caps & NM_WIFI_DEVICE_CAP_RSN))
|
|
|
|
|
return FALSE;
|
|
|
|
|
if (!have_ap)
|
|
|
|
|
return TRUE;
|
|
|
|
|
if (ap_rsn & NM_802_11_AP_SEC_KEY_MGMT_EAP_SUITE_B_192)
|
|
|
|
|
return TRUE;
|
|
|
|
|
return FALSE;
|
2020-01-02 14:42:28 +01:00
|
|
|
case NMU_SEC_INVALID:
|
2014-07-24 08:53:33 -04:00
|
|
|
break;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-01-02 14:42:28 +01:00
|
|
|
return FALSE;
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_utils_wep_key_valid:
|
|
|
|
|
* @key: a string that might be a WEP key
|
|
|
|
|
* @wep_type: the #NMWepKeyType type of the WEP key
|
|
|
|
|
*
|
|
|
|
|
* Checks if @key is a valid WEP key
|
|
|
|
|
*
|
|
|
|
|
* Returns: %TRUE if @key is a WEP key, %FALSE if not
|
|
|
|
|
*/
|
|
|
|
|
gboolean
|
|
|
|
|
nm_utils_wep_key_valid(const char *key, NMWepKeyType wep_type)
|
|
|
|
|
{
|
2020-10-29 12:36:22 +01:00
|
|
|
gsize keylen;
|
|
|
|
|
gsize i;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
if (!key)
|
|
|
|
|
return FALSE;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-03-09 12:22:39 +01:00
|
|
|
if (wep_type == NM_WEP_KEY_TYPE_UNKNOWN) {
|
|
|
|
|
return nm_utils_wep_key_valid(key, NM_WEP_KEY_TYPE_KEY)
|
|
|
|
|
|| nm_utils_wep_key_valid(key, NM_WEP_KEY_TYPE_PASSPHRASE);
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
keylen = strlen(key);
|
2015-03-09 12:22:39 +01:00
|
|
|
if (wep_type == NM_WEP_KEY_TYPE_KEY) {
|
2014-07-24 08:53:33 -04:00
|
|
|
if (keylen == 10 || keylen == 26) {
|
|
|
|
|
/* Hex key */
|
|
|
|
|
for (i = 0; i < keylen; i++) {
|
|
|
|
|
if (!g_ascii_isxdigit(key[i]))
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
} else if (keylen == 5 || keylen == 13) {
|
|
|
|
|
/* ASCII key */
|
|
|
|
|
for (i = 0; i < keylen; i++) {
|
|
|
|
|
if (!g_ascii_isprint(key[i]))
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
} else
|
|
|
|
|
return FALSE;
|
|
|
|
|
} else if (wep_type == NM_WEP_KEY_TYPE_PASSPHRASE) {
|
|
|
|
|
if (!keylen || keylen > 64)
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_utils_wpa_psk_valid:
|
|
|
|
|
* @psk: a string that might be a WPA PSK
|
|
|
|
|
*
|
|
|
|
|
* Checks if @psk is a valid WPA PSK
|
|
|
|
|
*
|
|
|
|
|
* Returns: %TRUE if @psk is a WPA PSK, %FALSE if not
|
|
|
|
|
*/
|
|
|
|
|
gboolean
|
|
|
|
|
nm_utils_wpa_psk_valid(const char *psk)
|
|
|
|
|
{
|
2020-10-29 12:36:22 +01:00
|
|
|
gsize psklen;
|
|
|
|
|
gsize i;
|
2014-07-24 08:53:33 -04:00
|
|
|
|
|
|
|
|
if (!psk)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
psklen = strlen(psk);
|
|
|
|
|
if (psklen < 8 || psklen > 64)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (psklen == 64) {
|
|
|
|
|
/* Hex PSK */
|
|
|
|
|
for (i = 0; i < psklen; i++) {
|
|
|
|
|
if (!g_ascii_isxdigit(psk[i]))
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-06 17:57:39 -04:00
|
|
|
/**
|
|
|
|
|
* nm_utils_ip4_dns_to_variant:
|
|
|
|
|
* @dns: (type utf8): an array of IP address strings
|
|
|
|
|
*
|
|
|
|
|
* Utility function to convert an array of IP address strings int a #GVariant of
|
|
|
|
|
* type 'au' representing an array of IPv4 addresses.
|
|
|
|
|
*
|
|
|
|
|
* Returns: (transfer none): a new floating #GVariant representing @dns.
|
|
|
|
|
**/
|
|
|
|
|
GVariant *
|
|
|
|
|
nm_utils_ip4_dns_to_variant(char **dns)
|
2021-06-29 21:53:55 +02:00
|
|
|
{
|
2022-10-24 18:36:29 +02:00
|
|
|
return nm_utils_dns_to_variant(AF_INET, NM_CAST_STRV_CC(dns), -1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_utils_ip6_dns_to_variant:
|
|
|
|
|
* @dns: (type utf8): an array of IP address strings
|
|
|
|
|
*
|
|
|
|
|
* Utility function to convert an array of IP address strings int a #GVariant of
|
|
|
|
|
* type 'aay' representing an array of IPv6 addresses.
|
|
|
|
|
*
|
|
|
|
|
* If a string cannot be parsed, it will be silently ignored.
|
|
|
|
|
*
|
|
|
|
|
* Returns: (transfer none): a new floating #GVariant representing @dns.
|
|
|
|
|
**/
|
|
|
|
|
GVariant *
|
|
|
|
|
nm_utils_ip6_dns_to_variant(char **dns)
|
|
|
|
|
{
|
|
|
|
|
return nm_utils_dns_to_variant(AF_INET6, NM_CAST_STRV_CC(dns), -1);
|
2021-06-29 21:53:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GVariant *
|
2022-10-24 18:36:29 +02:00
|
|
|
nm_utils_dns_to_variant(int addr_family, const char *const *dns, gssize len)
|
2014-09-06 17:57:39 -04:00
|
|
|
{
|
2022-10-24 18:36:29 +02:00
|
|
|
const int IS_IPv4 = NM_IS_IPv4(addr_family);
|
2014-09-06 17:57:39 -04:00
|
|
|
GVariantBuilder builder;
|
2021-06-29 21:53:55 +02:00
|
|
|
gsize l;
|
2020-10-29 12:36:22 +01:00
|
|
|
gsize i;
|
2014-09-06 17:57:39 -04:00
|
|
|
|
2021-06-29 21:53:55 +02:00
|
|
|
if (len < 0)
|
|
|
|
|
l = NM_PTRARRAY_LEN(dns);
|
|
|
|
|
else
|
|
|
|
|
l = len;
|
|
|
|
|
|
2022-10-24 18:36:29 +02:00
|
|
|
g_variant_builder_init(&builder, IS_IPv4 ? G_VARIANT_TYPE("au") : G_VARIANT_TYPE("aay"));
|
2014-09-06 17:57:39 -04:00
|
|
|
|
2021-06-29 21:53:55 +02:00
|
|
|
for (i = 0; i < l; i++) {
|
2022-10-24 18:36:29 +02:00
|
|
|
NMIPAddr ip;
|
2014-09-06 17:57:39 -04:00
|
|
|
|
2022-10-24 18:36:29 +02:00
|
|
|
/* We can only represent the IP address on the legacy property "ipv[46].dns".
|
2022-10-17 09:28:04 +02:00
|
|
|
* Expose what we can. */
|
2024-12-17 11:05:37 +01:00
|
|
|
if (!nm_dns_uri_parse_plain(addr_family, dns[i], NULL, &ip))
|
2022-10-17 09:28:04 +02:00
|
|
|
continue;
|
|
|
|
|
|
2022-10-24 18:36:29 +02:00
|
|
|
if (IS_IPv4)
|
2024-12-17 11:05:37 +01:00
|
|
|
g_variant_builder_add(&builder, "u", ip.addr4);
|
2022-10-24 18:36:29 +02:00
|
|
|
else
|
|
|
|
|
g_variant_builder_add(&builder, "@ay", nm_g_variant_new_ay_in6addr(&ip.addr6));
|
2014-09-06 17:57:39 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return g_variant_builder_end(&builder);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_utils_ip4_dns_from_variant:
|
|
|
|
|
* @value: a #GVariant of type 'au'
|
|
|
|
|
*
|
|
|
|
|
* Utility function to convert a #GVariant of type 'au' representing a list of
|
|
|
|
|
* IPv4 addresses into an array of IP address strings.
|
|
|
|
|
*
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
* Since 1.46, an empty list is returned if the variant type is not valid
|
|
|
|
|
* (before it was checked as assertion)
|
|
|
|
|
*
|
2014-09-06 17:57:39 -04:00
|
|
|
* Returns: (transfer full) (type utf8): a %NULL-terminated array of IP address strings.
|
|
|
|
|
**/
|
|
|
|
|
char **
|
|
|
|
|
nm_utils_ip4_dns_from_variant(GVariant *value)
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
{
|
|
|
|
|
return _nm_utils_ip4_dns_from_variant(value, FALSE, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* _nm_utils_ip4_dns_from_variant:
|
|
|
|
|
* @value: a #GVariant of type 'au'
|
|
|
|
|
* @strict: whether to parse in strict mode or best-effort mode
|
|
|
|
|
* @error: the error location
|
|
|
|
|
*
|
2025-02-28 17:56:00 +01:00
|
|
|
* Like #nm_utils_ip4_dns_from_variant, but allows one to parse in strict mode. In
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
* strict mode, parsing is aborted on first error and %NULL is returned.
|
|
|
|
|
*
|
|
|
|
|
* Returns: (transfer full) (type utf8): a %NULL-terminated array of IP address
|
|
|
|
|
* strings. In strict mode, %NULL is returned on error.
|
|
|
|
|
*/
|
|
|
|
|
char **
|
|
|
|
|
_nm_utils_ip4_dns_from_variant(GVariant *value, bool strict, GError **error)
|
2014-09-06 17:57:39 -04:00
|
|
|
{
|
|
|
|
|
const guint32 *array;
|
|
|
|
|
gsize length;
|
2021-11-09 13:28:54 +01:00
|
|
|
char **dns;
|
2020-10-29 12:36:22 +01:00
|
|
|
gsize i;
|
2014-09-06 17:57:39 -04:00
|
|
|
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
if (!g_variant_is_of_type(value, G_VARIANT_TYPE("au"))) {
|
|
|
|
|
if (strict) {
|
|
|
|
|
g_set_error_literal(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("Expected value of type \"au\""));
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
dns = g_new(char *, 1);
|
|
|
|
|
dns[0] = NULL;
|
|
|
|
|
return dns;
|
|
|
|
|
}
|
2014-09-06 17:57:39 -04:00
|
|
|
|
|
|
|
|
array = g_variant_get_fixed_array(value, &length, sizeof(guint32));
|
2020-10-29 12:36:22 +01:00
|
|
|
dns = g_new(char *, length + 1u);
|
2014-09-06 17:57:39 -04:00
|
|
|
for (i = 0; i < length; i++)
|
glib-aux: rename IP address related helpers from "nm-inet-utils.h"
- name things related to `in_addr_t`, `struct in6_addr`, `NMIPAddr` as
`nm_ip4_addr_*()`, `nm_ip6_addr_*()`, `nm_ip_addr_*()`, respectively.
- we have a wrapper `nm_inet_ntop()` for `inet_ntop()`. This name
of our wrapper is chosen to be familiar with the libc underlying
function. With this, also name functions that are about string
representations of addresses `nm_inet_*()`, `nm_inet4_*()`,
`nm_inet6_*()`. For example, `nm_inet_parse_str()`,
`nm_inet_is_normalized()`.
<<<<
R() {
git grep -l "$1" | xargs sed -i "s/\<$1\>/$2/g"
}
R NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX NM_CMP_DIRECT_IP4_ADDR_SAME_PREFIX
R NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX NM_CMP_DIRECT_IP6_ADDR_SAME_PREFIX
R NM_UTILS_INET_ADDRSTRLEN NM_INET_ADDRSTRLEN
R _nm_utils_inet4_ntop nm_inet4_ntop
R _nm_utils_inet6_ntop nm_inet6_ntop
R _nm_utils_ip4_get_default_prefix nm_ip4_addr_get_default_prefix
R _nm_utils_ip4_get_default_prefix0 nm_ip4_addr_get_default_prefix0
R _nm_utils_ip4_netmask_to_prefix nm_ip4_addr_netmask_to_prefix
R _nm_utils_ip4_prefix_to_netmask nm_ip4_addr_netmask_from_prefix
R nm_utils_inet4_ntop_dup nm_inet4_ntop_dup
R nm_utils_inet6_ntop_dup nm_inet6_ntop_dup
R nm_utils_inet_ntop nm_inet_ntop
R nm_utils_inet_ntop_dup nm_inet_ntop_dup
R nm_utils_ip4_address_clear_host_address nm_ip4_addr_clear_host_address
R nm_utils_ip4_address_is_link_local nm_ip4_addr_is_link_local
R nm_utils_ip4_address_is_loopback nm_ip4_addr_is_loopback
R nm_utils_ip4_address_is_zeronet nm_ip4_addr_is_zeronet
R nm_utils_ip4_address_same_prefix nm_ip4_addr_same_prefix
R nm_utils_ip4_address_same_prefix_cmp nm_ip4_addr_same_prefix_cmp
R nm_utils_ip6_address_clear_host_address nm_ip6_addr_clear_host_address
R nm_utils_ip6_address_same_prefix nm_ip6_addr_same_prefix
R nm_utils_ip6_address_same_prefix_cmp nm_ip6_addr_same_prefix_cmp
R nm_utils_ip6_is_ula nm_ip6_addr_is_ula
R nm_utils_ip_address_same_prefix nm_ip_addr_same_prefix
R nm_utils_ip_address_same_prefix_cmp nm_ip_addr_same_prefix_cmp
R nm_utils_ip_is_site_local nm_ip_addr_is_site_local
R nm_utils_ipaddr_is_normalized nm_inet_is_normalized
R nm_utils_ipaddr_is_valid nm_inet_is_valid
R nm_utils_ipx_address_clear_host_address nm_ip_addr_clear_host_address
R nm_utils_parse_inaddr nm_inet_parse_str
R nm_utils_parse_inaddr_bin nm_inet_parse_bin
R nm_utils_parse_inaddr_bin_full nm_inet_parse_bin_full
R nm_utils_parse_inaddr_prefix nm_inet_parse_with_prefix_str
R nm_utils_parse_inaddr_prefix_bin nm_inet_parse_with_prefix_bin
R test_nm_utils_ip6_address_same_prefix test_nm_ip_addr_same_prefix
./contrib/scripts/nm-code-format.sh -F
2022-08-19 13:15:20 +02:00
|
|
|
dns[i] = nm_inet4_ntop_dup(array[i]);
|
2014-09-06 17:57:39 -04:00
|
|
|
dns[i] = NULL;
|
|
|
|
|
|
|
|
|
|
return dns;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_utils_ip4_addresses_to_variant:
|
2014-09-16 16:42:46 -04:00
|
|
|
* @addresses: (element-type NMIPAddress): an array of #NMIPAddress objects
|
2023-03-01 01:21:38 +01:00
|
|
|
* @gateway: (nullable): the gateway IP address
|
2014-09-06 17:57:39 -04:00
|
|
|
*
|
2014-09-16 16:42:46 -04:00
|
|
|
* Utility function to convert a #GPtrArray of #NMIPAddress objects representing
|
|
|
|
|
* IPv4 addresses into a #GVariant of type 'aau' representing an array of
|
|
|
|
|
* NetworkManager IPv4 addresses (which are tuples of address, prefix, and
|
2014-10-20 21:30:56 -04:00
|
|
|
* gateway). The "gateway" field of the first address will get the value of
|
|
|
|
|
* @gateway (if non-%NULL). In all of the other addresses, that field will be 0.
|
2014-09-06 17:57:39 -04:00
|
|
|
*
|
|
|
|
|
* Returns: (transfer none): a new floating #GVariant representing @addresses.
|
|
|
|
|
**/
|
|
|
|
|
GVariant *
|
2014-10-20 21:30:56 -04:00
|
|
|
nm_utils_ip4_addresses_to_variant(GPtrArray *addresses, const char *gateway)
|
2014-09-06 17:57:39 -04:00
|
|
|
{
|
|
|
|
|
GVariantBuilder builder;
|
2020-10-29 12:36:22 +01:00
|
|
|
guint i;
|
2014-09-06 17:57:39 -04:00
|
|
|
|
|
|
|
|
g_variant_builder_init(&builder, G_VARIANT_TYPE("aau"));
|
|
|
|
|
|
|
|
|
|
if (addresses) {
|
|
|
|
|
for (i = 0; i < addresses->len; i++) {
|
2014-09-16 16:42:46 -04:00
|
|
|
NMIPAddress *addr = addresses->pdata[i];
|
2014-09-06 17:57:39 -04:00
|
|
|
guint32 array[3];
|
2020-10-29 12:00:30 +01:00
|
|
|
in_addr_t gw;
|
2014-09-06 17:57:39 -04:00
|
|
|
|
2014-09-16 16:42:46 -04:00
|
|
|
if (nm_ip_address_get_family(addr) != AF_INET)
|
|
|
|
|
continue;
|
|
|
|
|
|
2020-10-29 12:00:30 +01:00
|
|
|
gw = 0u;
|
|
|
|
|
if (gateway) {
|
|
|
|
|
in_addr_t a;
|
|
|
|
|
|
|
|
|
|
if (inet_pton(AF_INET, gateway, &a) == 1)
|
|
|
|
|
gw = a;
|
|
|
|
|
gateway = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-16 16:42:46 -04:00
|
|
|
nm_ip_address_get_address_binary(addr, &array[0]);
|
|
|
|
|
array[1] = nm_ip_address_get_prefix(addr);
|
2020-10-29 12:00:30 +01:00
|
|
|
array[2] = gw;
|
2014-09-06 17:57:39 -04:00
|
|
|
|
2021-04-15 09:43:42 +02:00
|
|
|
g_variant_builder_add(&builder, "@au", nm_g_variant_new_au(array, 3));
|
2014-09-06 17:57:39 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return g_variant_builder_end(&builder);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_utils_ip4_addresses_from_variant:
|
|
|
|
|
* @value: a #GVariant of type 'aau'
|
2023-03-01 01:21:38 +01:00
|
|
|
* @out_gateway: (out) (optional) (nullable) (transfer full): on return, will
|
|
|
|
|
* contain the IP gateway
|
2014-09-06 17:57:39 -04:00
|
|
|
*
|
|
|
|
|
* Utility function to convert a #GVariant of type 'aau' representing a list of
|
|
|
|
|
* NetworkManager IPv4 addresses (which are tuples of address, prefix, and
|
2014-10-20 21:30:56 -04:00
|
|
|
* gateway) into a #GPtrArray of #NMIPAddress objects. The "gateway" field of
|
|
|
|
|
* the first address (if set) will be returned in @out_gateway; the "gateway" fields
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
* of the other addresses are ignored. Note that invalid addresses are discarded
|
|
|
|
|
* but the valid addresses are still returned.
|
|
|
|
|
*
|
|
|
|
|
* Since 1.46, an empty list is returned if the variant type is not valid
|
|
|
|
|
* (before it was checked as assertion)
|
2014-09-06 17:57:39 -04:00
|
|
|
*
|
2014-09-16 16:42:46 -04:00
|
|
|
* Returns: (transfer full) (element-type NMIPAddress): a newly allocated
|
|
|
|
|
* #GPtrArray of #NMIPAddress objects
|
2014-09-06 17:57:39 -04:00
|
|
|
**/
|
|
|
|
|
GPtrArray *
|
2014-10-20 21:30:56 -04:00
|
|
|
nm_utils_ip4_addresses_from_variant(GVariant *value, char **out_gateway)
|
2014-09-06 17:57:39 -04:00
|
|
|
{
|
2023-11-17 11:23:07 +01:00
|
|
|
return _nm_utils_ip4_addresses_from_variant(value, NULL, out_gateway, FALSE, NULL);
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
}
|
2014-09-06 17:57:39 -04:00
|
|
|
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
/**
|
|
|
|
|
* _nm_utils_ip4_addresses_from_variant:
|
|
|
|
|
* @value: a #GVariant of type 'aau'
|
2023-11-17 11:23:07 +01:00
|
|
|
* @labels: (optional) (nullable): a #GVariant of the type 'as'. If not-NULL,
|
|
|
|
|
* each element must contain a string with the labels that corresponds to each
|
|
|
|
|
* IP address in @value.
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
* @out_gateway: (out) (optional) (nullable) (transfer full): on return, will
|
|
|
|
|
* contain the IP gateway
|
|
|
|
|
* @strict: whether to parse in strict mode or best-effort mode
|
|
|
|
|
* @error: the error location
|
|
|
|
|
*
|
2025-02-28 17:56:00 +01:00
|
|
|
* Like #nm_utils_ip4_addresses_from_variant, but allows one to parse in strict mode. In
|
2023-11-17 11:23:07 +01:00
|
|
|
* strict mode, parsing is aborted on first error and %NULL is returned. It also
|
2025-02-28 17:56:00 +01:00
|
|
|
* allows one to parse the address-labels at the same time than the addresses.
|
2023-11-17 11:23:07 +01:00
|
|
|
*
|
|
|
|
|
* The labels need to be processed at the same time than the addresses, inside
|
|
|
|
|
* this function, because if there are invalid addresses they are filtered out,
|
|
|
|
|
* and the returned array of addresses contains less elements than the original
|
|
|
|
|
* array. If that happens, the caller don't know what label corresponds to what
|
|
|
|
|
* address, because they are matched by position in the array. If you are not
|
|
|
|
|
* interested in the labels, just set @labels to NULL.
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
*
|
|
|
|
|
* Returns: (transfer full) (element-type NMIPAddress): a newly allocated
|
|
|
|
|
* #GPtrArray of #NMIPAddress objects. In strict mode, %NULL is returned on error.
|
|
|
|
|
*/
|
|
|
|
|
GPtrArray *
|
|
|
|
|
_nm_utils_ip4_addresses_from_variant(GVariant *value,
|
2023-11-17 11:23:07 +01:00
|
|
|
GVariant *labels,
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
char **out_gateway,
|
|
|
|
|
bool strict,
|
|
|
|
|
GError **error)
|
|
|
|
|
{
|
|
|
|
|
gs_unref_ptrarray GPtrArray *addresses = NULL;
|
|
|
|
|
GVariantIter iter;
|
|
|
|
|
GVariant *item;
|
|
|
|
|
const guint32 *addr_array;
|
|
|
|
|
gsize length;
|
|
|
|
|
NMIPAddress *addr;
|
2023-11-17 11:23:07 +01:00
|
|
|
const char *label;
|
|
|
|
|
gsize n_labels = 0;
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
guint i;
|
2014-09-06 17:57:39 -04:00
|
|
|
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
addresses = g_ptr_array_new_with_free_func((GDestroyNotify) nm_ip_address_unref);
|
2014-10-20 21:30:56 -04:00
|
|
|
if (out_gateway)
|
|
|
|
|
*out_gateway = NULL;
|
|
|
|
|
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
if (!g_variant_is_of_type(value, G_VARIANT_TYPE("aau"))) {
|
|
|
|
|
if (strict) {
|
|
|
|
|
g_set_error_literal(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("Expected value of type \"aau\""));
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
return g_steal_pointer(&addresses);
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-17 11:23:07 +01:00
|
|
|
if (labels && !g_variant_is_of_type(labels, G_VARIANT_TYPE("as"))) {
|
|
|
|
|
if (strict) {
|
|
|
|
|
g_set_error_literal(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("Expected \"address-labels\" of type \"as\""));
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
/* We still can parse the addresses, without the labels */
|
|
|
|
|
labels = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (labels)
|
|
|
|
|
n_labels = g_variant_n_children(labels);
|
|
|
|
|
|
2014-09-06 17:57:39 -04:00
|
|
|
g_variant_iter_init(&iter, value);
|
|
|
|
|
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
for (i = 0; g_variant_iter_next(&iter, "@au", &item); i++) {
|
|
|
|
|
gs_unref_variant GVariant *addr_var = item;
|
|
|
|
|
gs_free_error GError *local_error = NULL;
|
2014-09-06 17:57:39 -04:00
|
|
|
|
|
|
|
|
addr_array = g_variant_get_fixed_array(addr_var, &length, sizeof(guint32));
|
|
|
|
|
if (length < 3) {
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
if (strict) {
|
|
|
|
|
g_set_error(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("Incomplete IPv4 address (idx=%u)"),
|
|
|
|
|
i);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2014-09-06 17:57:39 -04:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
addr = nm_ip_address_new_binary(AF_INET, &addr_array[0], addr_array[1], &local_error);
|
|
|
|
|
if (!addr) {
|
|
|
|
|
if (strict) {
|
|
|
|
|
g_set_error(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("%s (idx=%u)"),
|
|
|
|
|
local_error->message,
|
|
|
|
|
i);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
continue;
|
2014-09-16 16:42:46 -04:00
|
|
|
}
|
2014-10-20 21:30:56 -04:00
|
|
|
|
2023-11-17 11:23:07 +01:00
|
|
|
/* We were accepting address-labels to be shorter than addresses, so
|
|
|
|
|
* let's continue doing so and not consider it as an error */
|
|
|
|
|
if (labels && i < n_labels) {
|
|
|
|
|
g_variant_get_child(labels, i, "&s", &label);
|
|
|
|
|
|
|
|
|
|
if (label && label[0]) {
|
|
|
|
|
nm_ip_address_set_attribute(addr,
|
|
|
|
|
NM_IP_ADDRESS_ATTRIBUTE_LABEL,
|
|
|
|
|
g_variant_new_string(label));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
g_ptr_array_add(addresses, addr);
|
|
|
|
|
if (addr_array[2] && out_gateway && !*out_gateway)
|
|
|
|
|
*out_gateway = nm_inet4_ntop_dup(addr_array[2]);
|
2014-09-06 17:57:39 -04:00
|
|
|
}
|
|
|
|
|
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
return g_steal_pointer(&addresses);
|
2014-09-06 17:57:39 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_utils_ip4_routes_to_variant:
|
2014-09-16 16:42:46 -04:00
|
|
|
* @routes: (element-type NMIPRoute): an array of #NMIP4Route objects
|
2014-09-06 17:57:39 -04:00
|
|
|
*
|
2014-09-16 16:42:46 -04:00
|
|
|
* Utility function to convert a #GPtrArray of #NMIPRoute objects representing
|
|
|
|
|
* IPv4 routes into a #GVariant of type 'aau' representing an array of
|
|
|
|
|
* NetworkManager IPv4 routes (which are tuples of route, prefix, next hop, and
|
|
|
|
|
* metric).
|
2014-09-06 17:57:39 -04:00
|
|
|
*
|
|
|
|
|
* Returns: (transfer none): a new floating #GVariant representing @routes.
|
|
|
|
|
**/
|
|
|
|
|
GVariant *
|
|
|
|
|
nm_utils_ip4_routes_to_variant(GPtrArray *routes)
|
|
|
|
|
{
|
|
|
|
|
GVariantBuilder builder;
|
2020-10-29 12:36:22 +01:00
|
|
|
guint i;
|
2014-09-06 17:57:39 -04:00
|
|
|
|
|
|
|
|
g_variant_builder_init(&builder, G_VARIANT_TYPE("aau"));
|
|
|
|
|
|
|
|
|
|
if (routes) {
|
|
|
|
|
for (i = 0; i < routes->len; i++) {
|
2014-09-16 16:42:46 -04:00
|
|
|
NMIPRoute *route = routes->pdata[i];
|
2014-09-06 17:57:39 -04:00
|
|
|
guint32 array[4];
|
|
|
|
|
|
2014-09-16 16:42:46 -04:00
|
|
|
if (nm_ip_route_get_family(route) != AF_INET)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
nm_ip_route_get_dest_binary(route, &array[0]);
|
|
|
|
|
array[1] = nm_ip_route_get_prefix(route);
|
|
|
|
|
nm_ip_route_get_next_hop_binary(route, &array[2]);
|
2014-11-04 15:48:48 -05:00
|
|
|
/* The old routes format uses "0" for default, not "-1" */
|
2023-10-27 14:36:56 +02:00
|
|
|
array[3] = NM_MAX(0, nm_ip_route_get_metric(route));
|
2014-09-06 17:57:39 -04:00
|
|
|
|
2021-04-15 09:43:42 +02:00
|
|
|
g_variant_builder_add(&builder, "@au", nm_g_variant_new_au(array, 4));
|
2014-09-06 17:57:39 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return g_variant_builder_end(&builder);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_utils_ip4_routes_from_variant:
|
|
|
|
|
* @value: #GVariant of type 'aau'
|
|
|
|
|
*
|
|
|
|
|
* Utility function to convert a #GVariant of type 'aau' representing an array
|
|
|
|
|
* of NetworkManager IPv4 routes (which are tuples of route, prefix, next hop,
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
* and metric) into a #GPtrArray of #NMIPRoute objects. Note that invalid routes
|
|
|
|
|
* are discarded but the valid routes are still returned.
|
|
|
|
|
*
|
|
|
|
|
* Since 1.46, an empty list is returned if the variant type is not valid
|
|
|
|
|
* (before it was checked as assertion)
|
2014-09-06 17:57:39 -04:00
|
|
|
*
|
2014-09-16 16:42:46 -04:00
|
|
|
* Returns: (transfer full) (element-type NMIPRoute): a newly allocated
|
|
|
|
|
* #GPtrArray of #NMIPRoute objects
|
2014-09-06 17:57:39 -04:00
|
|
|
**/
|
|
|
|
|
GPtrArray *
|
|
|
|
|
nm_utils_ip4_routes_from_variant(GVariant *value)
|
|
|
|
|
{
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
return _nm_utils_ip4_routes_from_variant(value, FALSE, NULL);
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
/**
|
|
|
|
|
* _nm_utils_ip4_routes_from_variant:
|
|
|
|
|
* @value: #GVariant of type 'aau'
|
|
|
|
|
* @strict: whether to parse in strict mode or best-effort mode
|
|
|
|
|
* @error: the error location
|
|
|
|
|
*
|
2025-02-28 17:56:00 +01:00
|
|
|
* Like #nm_utils_ip4_routes_from_variant, but allows one to parse in strict mode. In
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
* strict mode, parsing is aborted on first error and %NULL is returned.
|
|
|
|
|
*
|
|
|
|
|
* Returns: (transfer full) (element-type NMIPRoute): a newly allocated
|
|
|
|
|
* #GPtrArray of #NMIPRoute objects. In strict mode, NULL is returned on error.
|
|
|
|
|
*/
|
|
|
|
|
GPtrArray *
|
|
|
|
|
_nm_utils_ip4_routes_from_variant(GVariant *value, bool strict, GError **error)
|
|
|
|
|
{
|
|
|
|
|
gs_unref_ptrarray GPtrArray *routes = NULL;
|
|
|
|
|
GVariantIter iter;
|
|
|
|
|
GVariant *item;
|
|
|
|
|
const guint32 *route_array;
|
|
|
|
|
gsize length;
|
|
|
|
|
NMIPRoute *route;
|
|
|
|
|
guint i;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-09-16 16:42:46 -04:00
|
|
|
routes = g_ptr_array_new_with_free_func((GDestroyNotify) nm_ip_route_unref);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
if (!g_variant_is_of_type(value, G_VARIANT_TYPE("aau"))) {
|
|
|
|
|
if (strict) {
|
|
|
|
|
g_set_error_literal(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("Expected value of type \"aau\""));
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
return g_steal_pointer(&routes);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_variant_iter_init(&iter, value);
|
|
|
|
|
|
|
|
|
|
for (i = 0; g_variant_iter_next(&iter, "@au", &item); i++) {
|
|
|
|
|
gs_unref_variant GVariant *route_var = item;
|
|
|
|
|
gs_free_error GError *local_error = NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-09-06 17:57:39 -04:00
|
|
|
route_array = g_variant_get_fixed_array(route_var, &length, sizeof(guint32));
|
|
|
|
|
if (length < 4) {
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
if (strict) {
|
|
|
|
|
g_set_error(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("Incomplete IPv4 route (idx=%u)"),
|
|
|
|
|
i);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2014-09-06 17:57:39 -04:00
|
|
|
continue;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-09-16 16:42:46 -04:00
|
|
|
route = nm_ip_route_new_binary(AF_INET,
|
2014-11-04 15:48:48 -05:00
|
|
|
&route_array[0],
|
|
|
|
|
route_array[1],
|
|
|
|
|
&route_array[2],
|
|
|
|
|
/* The old routes format uses "0" for default, not "-1" */
|
|
|
|
|
route_array[3] ? (gint64) route_array[3] : -1,
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
&local_error);
|
|
|
|
|
if (!route) {
|
|
|
|
|
if (strict) {
|
|
|
|
|
g_set_error(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("%s (idx=%u)"),
|
|
|
|
|
local_error->message,
|
|
|
|
|
i);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
continue;
|
2014-09-16 16:42:46 -04:00
|
|
|
}
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
|
|
|
|
|
g_ptr_array_add(routes, route);
|
2014-09-06 17:57:39 -04:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
return g_steal_pointer(&routes);
|
2014-09-06 17:57:39 -04:00
|
|
|
}
|
|
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
/**
|
|
|
|
|
* nm_utils_ip4_netmask_to_prefix:
|
2022-06-23 07:35:13 +02:00
|
|
|
* @netmask: an IPv4 netmask in network byte order.
|
|
|
|
|
* Usually the netmask has all leading bits up to the prefix
|
|
|
|
|
* set so that the netmask is identical to having the first
|
|
|
|
|
* prefix bits of the address set.
|
|
|
|
|
* If that is not the case and there are "holes" in the
|
|
|
|
|
* mask, the prefix is determined based on the lowest bit
|
|
|
|
|
* set.
|
2014-07-24 08:53:33 -04:00
|
|
|
*
|
|
|
|
|
* Returns: the CIDR prefix represented by the netmask
|
|
|
|
|
**/
|
|
|
|
|
guint32
|
|
|
|
|
nm_utils_ip4_netmask_to_prefix(guint32 netmask)
|
|
|
|
|
{
|
glib-aux: rename IP address related helpers from "nm-inet-utils.h"
- name things related to `in_addr_t`, `struct in6_addr`, `NMIPAddr` as
`nm_ip4_addr_*()`, `nm_ip6_addr_*()`, `nm_ip_addr_*()`, respectively.
- we have a wrapper `nm_inet_ntop()` for `inet_ntop()`. This name
of our wrapper is chosen to be familiar with the libc underlying
function. With this, also name functions that are about string
representations of addresses `nm_inet_*()`, `nm_inet4_*()`,
`nm_inet6_*()`. For example, `nm_inet_parse_str()`,
`nm_inet_is_normalized()`.
<<<<
R() {
git grep -l "$1" | xargs sed -i "s/\<$1\>/$2/g"
}
R NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX NM_CMP_DIRECT_IP4_ADDR_SAME_PREFIX
R NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX NM_CMP_DIRECT_IP6_ADDR_SAME_PREFIX
R NM_UTILS_INET_ADDRSTRLEN NM_INET_ADDRSTRLEN
R _nm_utils_inet4_ntop nm_inet4_ntop
R _nm_utils_inet6_ntop nm_inet6_ntop
R _nm_utils_ip4_get_default_prefix nm_ip4_addr_get_default_prefix
R _nm_utils_ip4_get_default_prefix0 nm_ip4_addr_get_default_prefix0
R _nm_utils_ip4_netmask_to_prefix nm_ip4_addr_netmask_to_prefix
R _nm_utils_ip4_prefix_to_netmask nm_ip4_addr_netmask_from_prefix
R nm_utils_inet4_ntop_dup nm_inet4_ntop_dup
R nm_utils_inet6_ntop_dup nm_inet6_ntop_dup
R nm_utils_inet_ntop nm_inet_ntop
R nm_utils_inet_ntop_dup nm_inet_ntop_dup
R nm_utils_ip4_address_clear_host_address nm_ip4_addr_clear_host_address
R nm_utils_ip4_address_is_link_local nm_ip4_addr_is_link_local
R nm_utils_ip4_address_is_loopback nm_ip4_addr_is_loopback
R nm_utils_ip4_address_is_zeronet nm_ip4_addr_is_zeronet
R nm_utils_ip4_address_same_prefix nm_ip4_addr_same_prefix
R nm_utils_ip4_address_same_prefix_cmp nm_ip4_addr_same_prefix_cmp
R nm_utils_ip6_address_clear_host_address nm_ip6_addr_clear_host_address
R nm_utils_ip6_address_same_prefix nm_ip6_addr_same_prefix
R nm_utils_ip6_address_same_prefix_cmp nm_ip6_addr_same_prefix_cmp
R nm_utils_ip6_is_ula nm_ip6_addr_is_ula
R nm_utils_ip_address_same_prefix nm_ip_addr_same_prefix
R nm_utils_ip_address_same_prefix_cmp nm_ip_addr_same_prefix_cmp
R nm_utils_ip_is_site_local nm_ip_addr_is_site_local
R nm_utils_ipaddr_is_normalized nm_inet_is_normalized
R nm_utils_ipaddr_is_valid nm_inet_is_valid
R nm_utils_ipx_address_clear_host_address nm_ip_addr_clear_host_address
R nm_utils_parse_inaddr nm_inet_parse_str
R nm_utils_parse_inaddr_bin nm_inet_parse_bin
R nm_utils_parse_inaddr_bin_full nm_inet_parse_bin_full
R nm_utils_parse_inaddr_prefix nm_inet_parse_with_prefix_str
R nm_utils_parse_inaddr_prefix_bin nm_inet_parse_with_prefix_bin
R test_nm_utils_ip6_address_same_prefix test_nm_ip_addr_same_prefix
./contrib/scripts/nm-code-format.sh -F
2022-08-19 13:15:20 +02:00
|
|
|
return nm_ip4_addr_netmask_to_prefix(netmask);
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_utils_ip4_prefix_to_netmask:
|
2022-06-23 07:35:13 +02:00
|
|
|
* @prefix: a CIDR prefix, must be not larger than 32.
|
2014-07-24 08:53:33 -04:00
|
|
|
*
|
|
|
|
|
* Returns: the netmask represented by the prefix, in network byte order
|
|
|
|
|
**/
|
|
|
|
|
guint32
|
|
|
|
|
nm_utils_ip4_prefix_to_netmask(guint32 prefix)
|
|
|
|
|
{
|
2022-06-23 07:35:13 +02:00
|
|
|
g_return_val_if_fail(prefix <= 32, 0xffffffffu);
|
|
|
|
|
|
glib-aux: rename IP address related helpers from "nm-inet-utils.h"
- name things related to `in_addr_t`, `struct in6_addr`, `NMIPAddr` as
`nm_ip4_addr_*()`, `nm_ip6_addr_*()`, `nm_ip_addr_*()`, respectively.
- we have a wrapper `nm_inet_ntop()` for `inet_ntop()`. This name
of our wrapper is chosen to be familiar with the libc underlying
function. With this, also name functions that are about string
representations of addresses `nm_inet_*()`, `nm_inet4_*()`,
`nm_inet6_*()`. For example, `nm_inet_parse_str()`,
`nm_inet_is_normalized()`.
<<<<
R() {
git grep -l "$1" | xargs sed -i "s/\<$1\>/$2/g"
}
R NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX NM_CMP_DIRECT_IP4_ADDR_SAME_PREFIX
R NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX NM_CMP_DIRECT_IP6_ADDR_SAME_PREFIX
R NM_UTILS_INET_ADDRSTRLEN NM_INET_ADDRSTRLEN
R _nm_utils_inet4_ntop nm_inet4_ntop
R _nm_utils_inet6_ntop nm_inet6_ntop
R _nm_utils_ip4_get_default_prefix nm_ip4_addr_get_default_prefix
R _nm_utils_ip4_get_default_prefix0 nm_ip4_addr_get_default_prefix0
R _nm_utils_ip4_netmask_to_prefix nm_ip4_addr_netmask_to_prefix
R _nm_utils_ip4_prefix_to_netmask nm_ip4_addr_netmask_from_prefix
R nm_utils_inet4_ntop_dup nm_inet4_ntop_dup
R nm_utils_inet6_ntop_dup nm_inet6_ntop_dup
R nm_utils_inet_ntop nm_inet_ntop
R nm_utils_inet_ntop_dup nm_inet_ntop_dup
R nm_utils_ip4_address_clear_host_address nm_ip4_addr_clear_host_address
R nm_utils_ip4_address_is_link_local nm_ip4_addr_is_link_local
R nm_utils_ip4_address_is_loopback nm_ip4_addr_is_loopback
R nm_utils_ip4_address_is_zeronet nm_ip4_addr_is_zeronet
R nm_utils_ip4_address_same_prefix nm_ip4_addr_same_prefix
R nm_utils_ip4_address_same_prefix_cmp nm_ip4_addr_same_prefix_cmp
R nm_utils_ip6_address_clear_host_address nm_ip6_addr_clear_host_address
R nm_utils_ip6_address_same_prefix nm_ip6_addr_same_prefix
R nm_utils_ip6_address_same_prefix_cmp nm_ip6_addr_same_prefix_cmp
R nm_utils_ip6_is_ula nm_ip6_addr_is_ula
R nm_utils_ip_address_same_prefix nm_ip_addr_same_prefix
R nm_utils_ip_address_same_prefix_cmp nm_ip_addr_same_prefix_cmp
R nm_utils_ip_is_site_local nm_ip_addr_is_site_local
R nm_utils_ipaddr_is_normalized nm_inet_is_normalized
R nm_utils_ipaddr_is_valid nm_inet_is_valid
R nm_utils_ipx_address_clear_host_address nm_ip_addr_clear_host_address
R nm_utils_parse_inaddr nm_inet_parse_str
R nm_utils_parse_inaddr_bin nm_inet_parse_bin
R nm_utils_parse_inaddr_bin_full nm_inet_parse_bin_full
R nm_utils_parse_inaddr_prefix nm_inet_parse_with_prefix_str
R nm_utils_parse_inaddr_prefix_bin nm_inet_parse_with_prefix_bin
R test_nm_utils_ip6_address_same_prefix test_nm_ip_addr_same_prefix
./contrib/scripts/nm-code-format.sh -F
2022-08-19 13:15:20 +02:00
|
|
|
return nm_ip4_addr_netmask_from_prefix(prefix);
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_utils_ip4_get_default_prefix:
|
|
|
|
|
* @ip: an IPv4 address (in network byte order)
|
|
|
|
|
*
|
|
|
|
|
* When the Internet was originally set up, various ranges of IP addresses were
|
|
|
|
|
* segmented into three network classes: A, B, and C. This function will return
|
|
|
|
|
* a prefix that is associated with the IP address specified defining where it
|
|
|
|
|
* falls in the predefined classes.
|
|
|
|
|
*
|
|
|
|
|
* Returns: the default class prefix for the given IP
|
|
|
|
|
**/
|
|
|
|
|
/* The function is originally from ipcalc.c of Red Hat's initscripts. */
|
|
|
|
|
guint32
|
|
|
|
|
nm_utils_ip4_get_default_prefix(guint32 ip)
|
|
|
|
|
{
|
glib-aux: rename IP address related helpers from "nm-inet-utils.h"
- name things related to `in_addr_t`, `struct in6_addr`, `NMIPAddr` as
`nm_ip4_addr_*()`, `nm_ip6_addr_*()`, `nm_ip_addr_*()`, respectively.
- we have a wrapper `nm_inet_ntop()` for `inet_ntop()`. This name
of our wrapper is chosen to be familiar with the libc underlying
function. With this, also name functions that are about string
representations of addresses `nm_inet_*()`, `nm_inet4_*()`,
`nm_inet6_*()`. For example, `nm_inet_parse_str()`,
`nm_inet_is_normalized()`.
<<<<
R() {
git grep -l "$1" | xargs sed -i "s/\<$1\>/$2/g"
}
R NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX NM_CMP_DIRECT_IP4_ADDR_SAME_PREFIX
R NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX NM_CMP_DIRECT_IP6_ADDR_SAME_PREFIX
R NM_UTILS_INET_ADDRSTRLEN NM_INET_ADDRSTRLEN
R _nm_utils_inet4_ntop nm_inet4_ntop
R _nm_utils_inet6_ntop nm_inet6_ntop
R _nm_utils_ip4_get_default_prefix nm_ip4_addr_get_default_prefix
R _nm_utils_ip4_get_default_prefix0 nm_ip4_addr_get_default_prefix0
R _nm_utils_ip4_netmask_to_prefix nm_ip4_addr_netmask_to_prefix
R _nm_utils_ip4_prefix_to_netmask nm_ip4_addr_netmask_from_prefix
R nm_utils_inet4_ntop_dup nm_inet4_ntop_dup
R nm_utils_inet6_ntop_dup nm_inet6_ntop_dup
R nm_utils_inet_ntop nm_inet_ntop
R nm_utils_inet_ntop_dup nm_inet_ntop_dup
R nm_utils_ip4_address_clear_host_address nm_ip4_addr_clear_host_address
R nm_utils_ip4_address_is_link_local nm_ip4_addr_is_link_local
R nm_utils_ip4_address_is_loopback nm_ip4_addr_is_loopback
R nm_utils_ip4_address_is_zeronet nm_ip4_addr_is_zeronet
R nm_utils_ip4_address_same_prefix nm_ip4_addr_same_prefix
R nm_utils_ip4_address_same_prefix_cmp nm_ip4_addr_same_prefix_cmp
R nm_utils_ip6_address_clear_host_address nm_ip6_addr_clear_host_address
R nm_utils_ip6_address_same_prefix nm_ip6_addr_same_prefix
R nm_utils_ip6_address_same_prefix_cmp nm_ip6_addr_same_prefix_cmp
R nm_utils_ip6_is_ula nm_ip6_addr_is_ula
R nm_utils_ip_address_same_prefix nm_ip_addr_same_prefix
R nm_utils_ip_address_same_prefix_cmp nm_ip_addr_same_prefix_cmp
R nm_utils_ip_is_site_local nm_ip_addr_is_site_local
R nm_utils_ipaddr_is_normalized nm_inet_is_normalized
R nm_utils_ipaddr_is_valid nm_inet_is_valid
R nm_utils_ipx_address_clear_host_address nm_ip_addr_clear_host_address
R nm_utils_parse_inaddr nm_inet_parse_str
R nm_utils_parse_inaddr_bin nm_inet_parse_bin
R nm_utils_parse_inaddr_bin_full nm_inet_parse_bin_full
R nm_utils_parse_inaddr_prefix nm_inet_parse_with_prefix_str
R nm_utils_parse_inaddr_prefix_bin nm_inet_parse_with_prefix_bin
R test_nm_utils_ip6_address_same_prefix test_nm_ip_addr_same_prefix
./contrib/scripts/nm-code-format.sh -F
2022-08-19 13:15:20 +02:00
|
|
|
return nm_ip4_addr_get_default_prefix(ip);
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
|
|
|
|
|
2014-09-06 17:57:39 -04:00
|
|
|
/**
|
|
|
|
|
* nm_utils_ip6_dns_from_variant:
|
|
|
|
|
* @value: a #GVariant of type 'aay'
|
|
|
|
|
*
|
|
|
|
|
* Utility function to convert a #GVariant of type 'aay' representing a list of
|
2019-10-21 13:14:50 +02:00
|
|
|
* IPv6 addresses into an array of IP address strings. Each "ay" entry must be
|
|
|
|
|
* a IPv6 address in binary form (16 bytes long). Invalid entries are silently
|
|
|
|
|
* ignored.
|
2014-09-06 17:57:39 -04:00
|
|
|
*
|
2023-11-17 14:41:45 +01:00
|
|
|
* Since 1.46, an empty list is returned if the variant type is not valid
|
|
|
|
|
* (before it was checked as assertion)
|
|
|
|
|
*
|
2014-09-06 17:57:39 -04:00
|
|
|
* Returns: (transfer full) (type utf8): a %NULL-terminated array of IP address strings.
|
|
|
|
|
**/
|
|
|
|
|
char **
|
|
|
|
|
nm_utils_ip6_dns_from_variant(GVariant *value)
|
|
|
|
|
{
|
2023-11-17 14:41:45 +01:00
|
|
|
return _nm_utils_ip6_dns_from_variant(value, FALSE, NULL);
|
|
|
|
|
}
|
2014-09-06 17:57:39 -04:00
|
|
|
|
2023-11-17 14:41:45 +01:00
|
|
|
/**
|
|
|
|
|
* _nm_utils_ip6_dns_from_variant:
|
|
|
|
|
* @value: a #GVariant of type 'aay'
|
|
|
|
|
* @strict: whether to parse in strict mode or best-effort mode
|
|
|
|
|
* @error: the error location
|
|
|
|
|
*
|
2025-02-28 17:56:00 +01:00
|
|
|
* Like #nm_utils_ip6_dns_from_variant, but allows one to parse in strict mode. In
|
2023-11-17 14:41:45 +01:00
|
|
|
* strict mode, parsing is aborted on first error and %NULL is returned.
|
|
|
|
|
*
|
|
|
|
|
* Returns: (transfer full) (type utf8): a %NULL-terminated array of IP address
|
|
|
|
|
* strings. In strict mode, %NULL is returned on error.
|
|
|
|
|
**/
|
|
|
|
|
char **
|
|
|
|
|
_nm_utils_ip6_dns_from_variant(GVariant *value, bool strict, GError **error)
|
|
|
|
|
{
|
|
|
|
|
gs_strfreev char **dns = NULL;
|
|
|
|
|
GVariantIter iter;
|
|
|
|
|
GVariant *item;
|
|
|
|
|
guint i, j;
|
|
|
|
|
|
|
|
|
|
if (!g_variant_is_of_type(value, G_VARIANT_TYPE("aay"))) {
|
|
|
|
|
if (strict) {
|
|
|
|
|
g_set_error_literal(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("Expected value of type \"aay\""));
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
dns = g_new(char *, 1);
|
|
|
|
|
dns[0] = NULL;
|
|
|
|
|
return g_steal_pointer(&dns);
|
|
|
|
|
}
|
2014-09-06 17:57:39 -04:00
|
|
|
|
2023-11-17 14:41:45 +01:00
|
|
|
dns = g_new(char *, g_variant_n_children(value) + 1);
|
|
|
|
|
dns[0] = NULL;
|
2014-09-06 17:57:39 -04:00
|
|
|
|
|
|
|
|
g_variant_iter_init(&iter, value);
|
|
|
|
|
|
2023-11-17 14:41:45 +01:00
|
|
|
for (i = 0, j = 0; g_variant_iter_next(&iter, "@ay", &item); i++) {
|
|
|
|
|
gs_unref_variant GVariant *ip_var = item;
|
|
|
|
|
const struct in6_addr *ip;
|
|
|
|
|
gsize length;
|
|
|
|
|
|
|
|
|
|
ip = g_variant_get_fixed_array(ip_var, &length, 1);
|
2014-09-06 17:57:39 -04:00
|
|
|
|
2023-11-17 14:41:45 +01:00
|
|
|
if (length != sizeof(struct in6_addr)) {
|
|
|
|
|
if (strict) {
|
|
|
|
|
g_set_error(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("Invalid IPv6 DNS address length (idx=%u)"),
|
|
|
|
|
i);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dns[j] = nm_inet6_ntop_dup(ip);
|
|
|
|
|
dns[++j] = NULL;
|
2014-09-06 17:57:39 -04:00
|
|
|
}
|
|
|
|
|
|
2023-11-17 14:41:45 +01:00
|
|
|
return g_steal_pointer(&dns);
|
2014-09-06 17:57:39 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_utils_ip6_addresses_to_variant:
|
2014-09-16 16:42:46 -04:00
|
|
|
* @addresses: (element-type NMIPAddress): an array of #NMIPAddress objects
|
2023-03-01 01:21:38 +01:00
|
|
|
* @gateway: (nullable): the gateway IP address
|
2014-09-06 17:57:39 -04:00
|
|
|
*
|
2014-09-16 16:42:46 -04:00
|
|
|
* Utility function to convert a #GPtrArray of #NMIPAddress objects representing
|
|
|
|
|
* IPv6 addresses into a #GVariant of type 'a(ayuay)' representing an array of
|
|
|
|
|
* NetworkManager IPv6 addresses (which are tuples of address, prefix, and
|
2014-10-20 21:30:56 -04:00
|
|
|
* gateway). The "gateway" field of the first address will get the value of
|
|
|
|
|
* @gateway (if non-%NULL). In all of the other addresses, that field will be
|
|
|
|
|
* all 0s.
|
2014-09-06 17:57:39 -04:00
|
|
|
*
|
|
|
|
|
* Returns: (transfer none): a new floating #GVariant representing @addresses.
|
|
|
|
|
**/
|
|
|
|
|
GVariant *
|
2014-10-20 21:30:56 -04:00
|
|
|
nm_utils_ip6_addresses_to_variant(GPtrArray *addresses, const char *gateway)
|
2014-09-06 17:57:39 -04:00
|
|
|
{
|
|
|
|
|
GVariantBuilder builder;
|
2020-10-29 12:36:22 +01:00
|
|
|
guint i;
|
2014-09-06 17:57:39 -04:00
|
|
|
|
|
|
|
|
g_variant_builder_init(&builder, G_VARIANT_TYPE("a(ayuay)"));
|
|
|
|
|
|
|
|
|
|
if (addresses) {
|
|
|
|
|
for (i = 0; i < addresses->len; i++) {
|
2021-11-09 13:28:54 +01:00
|
|
|
NMIPAddress *addr = addresses->pdata[i];
|
2020-10-29 12:00:30 +01:00
|
|
|
struct in6_addr address_bin;
|
|
|
|
|
struct in6_addr gateway_bin_data;
|
|
|
|
|
const struct in6_addr *gateway_bin;
|
2014-09-06 17:57:39 -04:00
|
|
|
|
2014-09-16 16:42:46 -04:00
|
|
|
if (nm_ip_address_get_family(addr) != AF_INET6)
|
|
|
|
|
continue;
|
|
|
|
|
|
2020-10-29 12:00:30 +01:00
|
|
|
nm_ip_address_get_address_binary(addr, &address_bin);
|
2014-10-20 21:30:56 -04:00
|
|
|
|
2020-10-29 12:00:30 +01:00
|
|
|
gateway_bin = &in6addr_any;
|
|
|
|
|
if (gateway) {
|
|
|
|
|
if (inet_pton(AF_INET6, gateway, &gateway_bin_data) == 1)
|
|
|
|
|
gateway_bin = &gateway_bin_data;
|
|
|
|
|
gateway = NULL;
|
|
|
|
|
}
|
2014-09-06 17:57:39 -04:00
|
|
|
|
2020-10-29 12:00:30 +01:00
|
|
|
g_variant_builder_add(&builder,
|
|
|
|
|
"(@ayu@ay)",
|
|
|
|
|
nm_g_variant_new_ay_in6addr(&address_bin),
|
|
|
|
|
(guint32) nm_ip_address_get_prefix(addr),
|
|
|
|
|
nm_g_variant_new_ay_in6addr(gateway_bin));
|
2014-09-06 17:57:39 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return g_variant_builder_end(&builder);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_utils_ip6_addresses_from_variant:
|
|
|
|
|
* @value: a #GVariant of type 'a(ayuay)'
|
2023-03-01 01:21:38 +01:00
|
|
|
* @out_gateway: (out) (optional) (nullable) (transfer full): on return, will
|
|
|
|
|
* contain the IP gateway
|
2014-09-06 17:57:39 -04:00
|
|
|
*
|
|
|
|
|
* Utility function to convert a #GVariant of type 'a(ayuay)' representing a
|
|
|
|
|
* list of NetworkManager IPv6 addresses (which are tuples of address, prefix,
|
2014-10-20 21:30:56 -04:00
|
|
|
* and gateway) into a #GPtrArray of #NMIPAddress objects. The "gateway" field
|
|
|
|
|
* of the first address (if set) will be returned in @out_gateway; the "gateway"
|
2023-11-17 14:41:45 +01:00
|
|
|
* fields of the other addresses are ignored. Note that invalid addresses are
|
|
|
|
|
* discarded but the valid addresses are still returned.
|
|
|
|
|
*
|
|
|
|
|
* Since 1.46, an empty list is returned if the variant type is not valid
|
|
|
|
|
* (before it was checked as assertion)
|
2014-09-06 17:57:39 -04:00
|
|
|
*
|
2014-09-16 16:42:46 -04:00
|
|
|
* Returns: (transfer full) (element-type NMIPAddress): a newly allocated
|
|
|
|
|
* #GPtrArray of #NMIPAddress objects
|
2014-09-06 17:57:39 -04:00
|
|
|
**/
|
|
|
|
|
GPtrArray *
|
2014-10-20 21:30:56 -04:00
|
|
|
nm_utils_ip6_addresses_from_variant(GVariant *value, char **out_gateway)
|
2014-09-06 17:57:39 -04:00
|
|
|
{
|
2023-11-17 14:41:45 +01:00
|
|
|
return _nm_utils_ip6_addresses_from_variant(value, out_gateway, FALSE, NULL);
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2023-11-17 14:41:45 +01:00
|
|
|
/**
|
|
|
|
|
* _nm_utils_ip6_addresses_from_variant:
|
|
|
|
|
* @value: a #GVariant of type 'a(ayuay)'
|
|
|
|
|
* @out_gateway: (out) (optional) (nullable) (transfer full): on return, will
|
|
|
|
|
* contain the IP gateway
|
|
|
|
|
* @strict: whether to parse in strict mode or best-effort mode
|
|
|
|
|
* @error: the error location
|
|
|
|
|
*
|
2025-02-28 17:56:00 +01:00
|
|
|
* Like #nm_utils_ip6_addresses_from_variant, but allows one to parse in strict mode. In
|
2023-11-17 14:41:45 +01:00
|
|
|
* strict mode, parsing is aborted on first error and %NULL is returned.
|
|
|
|
|
*
|
|
|
|
|
* Returns: (transfer full) (element-type NMIPAddress): a newly allocated
|
|
|
|
|
* #GPtrArray of #NMIPAddress objects. In strict mode, %NULL is returned on error.
|
|
|
|
|
**/
|
|
|
|
|
GPtrArray *
|
|
|
|
|
_nm_utils_ip6_addresses_from_variant(GVariant *value,
|
|
|
|
|
char **out_gateway,
|
|
|
|
|
bool strict,
|
|
|
|
|
GError **error)
|
|
|
|
|
{
|
|
|
|
|
gs_unref_ptrarray GPtrArray *addresses = NULL;
|
|
|
|
|
GVariantIter iter;
|
|
|
|
|
GVariant *addr_item;
|
|
|
|
|
GVariant *gateway_item;
|
|
|
|
|
guint32 prefix;
|
|
|
|
|
guint i;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2023-11-17 14:41:45 +01:00
|
|
|
addresses = g_ptr_array_new_with_free_func((GDestroyNotify) nm_ip_address_unref);
|
2014-10-20 21:30:56 -04:00
|
|
|
if (out_gateway)
|
|
|
|
|
*out_gateway = NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2023-11-17 14:41:45 +01:00
|
|
|
if (!g_variant_is_of_type(value, G_VARIANT_TYPE("a(ayuay)"))) {
|
|
|
|
|
if (strict) {
|
|
|
|
|
g_set_error_literal(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("Expected value of type \"a(ayuay)\""));
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
return g_steal_pointer(&addresses);
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-06 17:57:39 -04:00
|
|
|
g_variant_iter_init(&iter, value);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2023-11-17 14:41:45 +01:00
|
|
|
for (i = 0; g_variant_iter_next(&iter, "(@ayu@ay)", &addr_item, &prefix, &gateway_item); i++) {
|
|
|
|
|
gs_unref_variant GVariant *addr_var = addr_item;
|
|
|
|
|
gs_unref_variant GVariant *gateway_var = gateway_item;
|
|
|
|
|
gs_free_error GError *local_error = NULL;
|
|
|
|
|
NMIPAddress *addr;
|
|
|
|
|
const struct in6_addr *addr_bytes, *gateway_bytes;
|
|
|
|
|
gsize addr_len, gateway_len;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-09-06 17:57:39 -04:00
|
|
|
if (!g_variant_is_of_type(addr_var, G_VARIANT_TYPE_BYTESTRING)
|
|
|
|
|
|| !g_variant_is_of_type(gateway_var, G_VARIANT_TYPE_BYTESTRING)) {
|
2023-11-17 14:41:45 +01:00
|
|
|
if (strict) {
|
|
|
|
|
g_set_error(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("Expected value of type \"(ayuay)\" (idx=%u)"),
|
|
|
|
|
i);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
continue;
|
2014-09-06 17:57:39 -04:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-09-06 17:57:39 -04:00
|
|
|
addr_bytes = g_variant_get_fixed_array(addr_var, &addr_len, 1);
|
|
|
|
|
if (addr_len != 16) {
|
2023-11-17 14:41:45 +01:00
|
|
|
if (strict) {
|
|
|
|
|
g_set_error(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("IPv6 address with invalid length (idx=%u)"),
|
|
|
|
|
i);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
continue;
|
2014-09-06 17:57:39 -04:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2023-11-17 14:41:45 +01:00
|
|
|
addr = nm_ip_address_new_binary(AF_INET6, addr_bytes, prefix, &local_error);
|
|
|
|
|
if (!addr) {
|
|
|
|
|
if (strict) {
|
|
|
|
|
g_set_error(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("%s (idx=%u)"),
|
|
|
|
|
local_error->message,
|
|
|
|
|
i);
|
|
|
|
|
return NULL;
|
2014-12-03 11:10:17 -05:00
|
|
|
}
|
2023-11-17 14:41:45 +01:00
|
|
|
continue;
|
2014-09-16 16:42:46 -04:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2023-11-17 14:41:45 +01:00
|
|
|
g_ptr_array_add(addresses, addr);
|
|
|
|
|
|
|
|
|
|
if (out_gateway && !*out_gateway) {
|
|
|
|
|
gateway_bytes = g_variant_get_fixed_array(gateway_var, &gateway_len, 1);
|
|
|
|
|
if (gateway_len != 16) {
|
|
|
|
|
if (strict) {
|
|
|
|
|
g_set_error(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("IPv6 gateway with invalid length (idx=%u)"),
|
|
|
|
|
i);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!IN6_IS_ADDR_UNSPECIFIED(gateway_bytes))
|
|
|
|
|
NM_SET_OUT(out_gateway, nm_inet6_ntop_dup(gateway_bytes));
|
|
|
|
|
}
|
2014-09-06 17:57:39 -04:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2023-11-17 14:41:45 +01:00
|
|
|
return g_steal_pointer(&addresses);
|
2014-09-06 17:57:39 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_utils_ip6_routes_to_variant:
|
2014-09-16 16:42:46 -04:00
|
|
|
* @routes: (element-type NMIPRoute): an array of #NMIPRoute objects
|
2014-09-06 17:57:39 -04:00
|
|
|
*
|
2014-09-16 16:42:46 -04:00
|
|
|
* Utility function to convert a #GPtrArray of #NMIPRoute objects representing
|
|
|
|
|
* IPv6 routes into a #GVariant of type 'a(ayuayu)' representing an array of
|
|
|
|
|
* NetworkManager IPv6 routes (which are tuples of route, prefix, next hop, and
|
|
|
|
|
* metric).
|
2014-09-06 17:57:39 -04:00
|
|
|
*
|
|
|
|
|
* Returns: (transfer none): a new floating #GVariant representing @routes.
|
|
|
|
|
**/
|
|
|
|
|
GVariant *
|
|
|
|
|
nm_utils_ip6_routes_to_variant(GPtrArray *routes)
|
|
|
|
|
{
|
|
|
|
|
GVariantBuilder builder;
|
2020-10-29 12:36:22 +01:00
|
|
|
guint i;
|
2014-09-06 17:57:39 -04:00
|
|
|
|
|
|
|
|
g_variant_builder_init(&builder, G_VARIANT_TYPE("a(ayuayu)"));
|
|
|
|
|
|
|
|
|
|
if (routes) {
|
|
|
|
|
for (i = 0; i < routes->len; i++) {
|
2021-11-09 13:28:54 +01:00
|
|
|
NMIPRoute *route = routes->pdata[i];
|
2020-10-29 12:00:30 +01:00
|
|
|
struct in6_addr dest_bytes;
|
|
|
|
|
struct in6_addr next_hop_bytes;
|
|
|
|
|
guint32 metric;
|
2014-09-06 17:57:39 -04:00
|
|
|
|
2014-09-16 16:42:46 -04:00
|
|
|
if (nm_ip_route_get_family(route) != AF_INET6)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
nm_ip_route_get_dest_binary(route, &dest_bytes);
|
|
|
|
|
nm_ip_route_get_next_hop_binary(route, &next_hop_bytes);
|
2014-09-06 17:57:39 -04:00
|
|
|
|
2020-10-29 12:00:30 +01:00
|
|
|
/* The old routes format uses "0" for default, not "-1" */
|
|
|
|
|
metric = NM_MAX(0, nm_ip_route_get_metric(route));
|
|
|
|
|
|
|
|
|
|
g_variant_builder_add(&builder,
|
|
|
|
|
"(@ayu@ayu)",
|
|
|
|
|
nm_g_variant_new_ay_in6addr(&dest_bytes),
|
|
|
|
|
(guint32) nm_ip_route_get_prefix(route),
|
|
|
|
|
nm_g_variant_new_ay_in6addr(&next_hop_bytes),
|
|
|
|
|
metric);
|
2014-09-06 17:57:39 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return g_variant_builder_end(&builder);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_utils_ip6_routes_from_variant:
|
|
|
|
|
* @value: #GVariant of type 'a(ayuayu)'
|
|
|
|
|
*
|
|
|
|
|
* Utility function to convert a #GVariant of type 'a(ayuayu)' representing an
|
|
|
|
|
* array of NetworkManager IPv6 routes (which are tuples of route, prefix, next
|
2023-11-17 14:41:45 +01:00
|
|
|
* hop, and metric) into a #GPtrArray of #NMIPRoute objects. Note that invalid
|
|
|
|
|
* routes are ignored but the valid ones are still returned.
|
|
|
|
|
*
|
|
|
|
|
* Since 1.46, an empty list is returned if the variant type is not valid
|
|
|
|
|
* (before it was checked as assertion)
|
2014-09-06 17:57:39 -04:00
|
|
|
*
|
2014-09-16 16:42:46 -04:00
|
|
|
* Returns: (transfer full) (element-type NMIPRoute): a newly allocated
|
|
|
|
|
* #GPtrArray of #NMIPRoute objects
|
2014-09-06 17:57:39 -04:00
|
|
|
**/
|
|
|
|
|
GPtrArray *
|
|
|
|
|
nm_utils_ip6_routes_from_variant(GVariant *value)
|
|
|
|
|
{
|
2023-11-17 14:41:45 +01:00
|
|
|
return _nm_utils_ip6_routes_from_variant(value, FALSE, NULL);
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2023-11-17 14:41:45 +01:00
|
|
|
/**
|
|
|
|
|
* _nm_utils_ip6_routes_from_variant:
|
|
|
|
|
* @value: #GVariant of type 'a(ayuayu)'
|
|
|
|
|
* @strict: whether to parse in strict mode or best-effort mode
|
|
|
|
|
* @error: the error location
|
|
|
|
|
*
|
2025-02-28 17:56:00 +01:00
|
|
|
* Like #nm_utils_ip6_routes_from_variant, but allows one to parse in strict mode. In
|
2023-11-17 14:41:45 +01:00
|
|
|
* strict mode, parsing is aborted on first error and %NULL is returned.
|
|
|
|
|
*
|
|
|
|
|
* Returns: (transfer full) (element-type NMIPRoute): a newly allocated
|
|
|
|
|
* #GPtrArray of #NMIPRoute objects. In strict mode, %NULL is returned on error.
|
|
|
|
|
**/
|
|
|
|
|
GPtrArray *
|
|
|
|
|
_nm_utils_ip6_routes_from_variant(GVariant *value, bool strict, GError **error)
|
|
|
|
|
{
|
|
|
|
|
gs_unref_ptrarray GPtrArray *routes = NULL;
|
|
|
|
|
GVariantIter iter;
|
|
|
|
|
GVariant *dest_item;
|
|
|
|
|
GVariant *next_hop_item;
|
|
|
|
|
guint32 prefix, metric;
|
|
|
|
|
guint i;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-09-16 16:42:46 -04:00
|
|
|
routes = g_ptr_array_new_with_free_func((GDestroyNotify) nm_ip_route_unref);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2023-11-17 14:41:45 +01:00
|
|
|
if (!g_variant_is_of_type(value, G_VARIANT_TYPE("a(ayuayu)"))) {
|
|
|
|
|
if (strict) {
|
|
|
|
|
g_set_error_literal(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("Expected value of type \"a(ayuayu)\""));
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
return g_steal_pointer(&routes);
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-06 17:57:39 -04:00
|
|
|
g_variant_iter_init(&iter, value);
|
2023-11-17 14:41:45 +01:00
|
|
|
|
|
|
|
|
for (i = 0;
|
|
|
|
|
g_variant_iter_next(&iter, "(@ayu@ayu)", &dest_item, &prefix, &next_hop_item, &metric);
|
|
|
|
|
i++) {
|
|
|
|
|
gs_unref_variant GVariant *dest_var = dest_item;
|
|
|
|
|
gs_unref_variant GVariant *next_hop_var = next_hop_item;
|
|
|
|
|
gs_free_error GError *local_error = NULL;
|
|
|
|
|
NMIPRoute *route;
|
|
|
|
|
const struct in6_addr *dest, *next_hop;
|
|
|
|
|
gsize dest_len, next_hop_len;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-09-06 17:57:39 -04:00
|
|
|
if (!g_variant_is_of_type(dest_var, G_VARIANT_TYPE_BYTESTRING)
|
|
|
|
|
|| !g_variant_is_of_type(next_hop_var, G_VARIANT_TYPE_BYTESTRING)) {
|
2023-11-17 14:41:45 +01:00
|
|
|
if (strict) {
|
|
|
|
|
g_set_error(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("Expected value of type \"(ayuayu)\" (idx=%u)"),
|
|
|
|
|
i);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
continue;
|
2014-09-06 17:57:39 -04:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-09-06 17:57:39 -04:00
|
|
|
dest = g_variant_get_fixed_array(dest_var, &dest_len, 1);
|
|
|
|
|
if (dest_len != 16) {
|
2023-11-17 14:41:45 +01:00
|
|
|
if (strict) {
|
|
|
|
|
g_set_error(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("IPv6 dest address with invalid length (idx=%u)"),
|
|
|
|
|
i);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
continue;
|
2014-09-06 17:57:39 -04:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-09-06 17:57:39 -04:00
|
|
|
next_hop = g_variant_get_fixed_array(next_hop_var, &next_hop_len, 1);
|
|
|
|
|
if (next_hop_len != 16) {
|
2023-11-17 14:41:45 +01:00
|
|
|
if (strict) {
|
|
|
|
|
g_set_error(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("IPv6 next-hop address with invalid length (idx=%u)"),
|
|
|
|
|
i);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
continue;
|
2014-09-06 17:57:39 -04:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-11-04 15:48:48 -05:00
|
|
|
route = nm_ip_route_new_binary(AF_INET6,
|
|
|
|
|
dest,
|
|
|
|
|
prefix,
|
|
|
|
|
next_hop,
|
|
|
|
|
metric ? (gint64) metric : -1,
|
2023-11-17 14:41:45 +01:00
|
|
|
&local_error);
|
|
|
|
|
if (!route) {
|
|
|
|
|
if (strict) {
|
|
|
|
|
g_set_error(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("%s (idx=%u)"),
|
|
|
|
|
local_error->message,
|
|
|
|
|
i);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
continue;
|
2014-09-16 16:42:46 -04:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2023-11-17 14:41:45 +01:00
|
|
|
g_ptr_array_add(routes, route);
|
2014-09-06 17:57:39 -04:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2023-11-17 14:41:45 +01:00
|
|
|
return g_steal_pointer(&routes);
|
2014-09-06 17:57:39 -04:00
|
|
|
}
|
|
|
|
|
|
libnm-core, libnm, core: add AddressData and RouteData properties
Add AddressData and RouteData properties to NMSettingIPConfig and
NMIP[46]Config. These are like the existing "addresses" and "routes"
properties, but using strings and containing additional attributes,
like NMIPAddress and NMIPRoute.
This only affects the D-Bus representations; there are no API changes
to NMSettingIP{,4,6}Config or NMIP{4,6}Config as a result of this; the
additional information is just added to the existing 'addresses' and
'routes' properties.
NMSettingIP4Config and NMSettingIP6Config now always generate both
old-style data ('addresses', 'address-labels', 'routes') and new-style
data ('address-data', 'gateway', 'route-data') when serializing to
D-Bus, for backward compatibility. When deserializing, they will fill
in the 'addresses' and 'routes' properties from the new-style data if
it is present (ignoring the old-style data), or from the old-style
data if the new-style isn't present.
The daemon-side NMIP4Config and NMIP6Config always emit changes for
both 'Addresses'/'Routes' and 'AddressData'/'RouteData'. The
libnm-side classes initially listen for changes on both properties,
but start ignoring the 'Addresses' and 'Routes' properties once they
know the daemon is also providing 'AddressData' and 'RouteData'.
2014-10-21 08:33:18 -04:00
|
|
|
/**
|
|
|
|
|
* nm_utils_ip_addresses_to_variant:
|
|
|
|
|
* @addresses: (element-type NMIPAddress): an array of #NMIPAddress objects
|
|
|
|
|
*
|
|
|
|
|
* Utility function to convert a #GPtrArray of #NMIPAddress objects representing
|
|
|
|
|
* IPv4 or IPv6 addresses into a #GVariant of type 'aa{sv}' representing an
|
|
|
|
|
* array of new-style NetworkManager IP addresses. All addresses will include
|
|
|
|
|
* "address" (an IP address string), and "prefix" (a uint). Some addresses may
|
|
|
|
|
* include additional attributes.
|
|
|
|
|
*
|
|
|
|
|
* Returns: (transfer none): a new floating #GVariant representing @addresses.
|
2022-11-07 22:01:58 +01:00
|
|
|
*
|
|
|
|
|
* Since: 1.42
|
libnm-core, libnm, core: add AddressData and RouteData properties
Add AddressData and RouteData properties to NMSettingIPConfig and
NMIP[46]Config. These are like the existing "addresses" and "routes"
properties, but using strings and containing additional attributes,
like NMIPAddress and NMIPRoute.
This only affects the D-Bus representations; there are no API changes
to NMSettingIP{,4,6}Config or NMIP{4,6}Config as a result of this; the
additional information is just added to the existing 'addresses' and
'routes' properties.
NMSettingIP4Config and NMSettingIP6Config now always generate both
old-style data ('addresses', 'address-labels', 'routes') and new-style
data ('address-data', 'gateway', 'route-data') when serializing to
D-Bus, for backward compatibility. When deserializing, they will fill
in the 'addresses' and 'routes' properties from the new-style data if
it is present (ignoring the old-style data), or from the old-style
data if the new-style isn't present.
The daemon-side NMIP4Config and NMIP6Config always emit changes for
both 'Addresses'/'Routes' and 'AddressData'/'RouteData'. The
libnm-side classes initially listen for changes on both properties,
but start ignoring the 'Addresses' and 'Routes' properties once they
know the daemon is also providing 'AddressData' and 'RouteData'.
2014-10-21 08:33:18 -04:00
|
|
|
**/
|
|
|
|
|
GVariant *
|
|
|
|
|
nm_utils_ip_addresses_to_variant(GPtrArray *addresses)
|
|
|
|
|
{
|
|
|
|
|
GVariantBuilder builder;
|
2017-12-11 11:37:21 +01:00
|
|
|
guint i;
|
libnm-core, libnm, core: add AddressData and RouteData properties
Add AddressData and RouteData properties to NMSettingIPConfig and
NMIP[46]Config. These are like the existing "addresses" and "routes"
properties, but using strings and containing additional attributes,
like NMIPAddress and NMIPRoute.
This only affects the D-Bus representations; there are no API changes
to NMSettingIP{,4,6}Config or NMIP{4,6}Config as a result of this; the
additional information is just added to the existing 'addresses' and
'routes' properties.
NMSettingIP4Config and NMSettingIP6Config now always generate both
old-style data ('addresses', 'address-labels', 'routes') and new-style
data ('address-data', 'gateway', 'route-data') when serializing to
D-Bus, for backward compatibility. When deserializing, they will fill
in the 'addresses' and 'routes' properties from the new-style data if
it is present (ignoring the old-style data), or from the old-style
data if the new-style isn't present.
The daemon-side NMIP4Config and NMIP6Config always emit changes for
both 'Addresses'/'Routes' and 'AddressData'/'RouteData'. The
libnm-side classes initially listen for changes on both properties,
but start ignoring the 'Addresses' and 'Routes' properties once they
know the daemon is also providing 'AddressData' and 'RouteData'.
2014-10-21 08:33:18 -04:00
|
|
|
|
|
|
|
|
g_variant_builder_init(&builder, G_VARIANT_TYPE("aa{sv}"));
|
|
|
|
|
|
|
|
|
|
if (addresses) {
|
|
|
|
|
for (i = 0; i < addresses->len; i++) {
|
2021-11-09 13:28:54 +01:00
|
|
|
NMIPAddress *addr = addresses->pdata[i];
|
libnm-core, libnm, core: add AddressData and RouteData properties
Add AddressData and RouteData properties to NMSettingIPConfig and
NMIP[46]Config. These are like the existing "addresses" and "routes"
properties, but using strings and containing additional attributes,
like NMIPAddress and NMIPRoute.
This only affects the D-Bus representations; there are no API changes
to NMSettingIP{,4,6}Config or NMIP{4,6}Config as a result of this; the
additional information is just added to the existing 'addresses' and
'routes' properties.
NMSettingIP4Config and NMSettingIP6Config now always generate both
old-style data ('addresses', 'address-labels', 'routes') and new-style
data ('address-data', 'gateway', 'route-data') when serializing to
D-Bus, for backward compatibility. When deserializing, they will fill
in the 'addresses' and 'routes' properties from the new-style data if
it is present (ignoring the old-style data), or from the old-style
data if the new-style isn't present.
The daemon-side NMIP4Config and NMIP6Config always emit changes for
both 'Addresses'/'Routes' and 'AddressData'/'RouteData'. The
libnm-side classes initially listen for changes on both properties,
but start ignoring the 'Addresses' and 'Routes' properties once they
know the daemon is also providing 'AddressData' and 'RouteData'.
2014-10-21 08:33:18 -04:00
|
|
|
GVariantBuilder addr_builder;
|
2017-12-11 11:37:21 +01:00
|
|
|
gs_free const char **names = NULL;
|
|
|
|
|
guint j, len;
|
libnm-core, libnm, core: add AddressData and RouteData properties
Add AddressData and RouteData properties to NMSettingIPConfig and
NMIP[46]Config. These are like the existing "addresses" and "routes"
properties, but using strings and containing additional attributes,
like NMIPAddress and NMIPRoute.
This only affects the D-Bus representations; there are no API changes
to NMSettingIP{,4,6}Config or NMIP{4,6}Config as a result of this; the
additional information is just added to the existing 'addresses' and
'routes' properties.
NMSettingIP4Config and NMSettingIP6Config now always generate both
old-style data ('addresses', 'address-labels', 'routes') and new-style
data ('address-data', 'gateway', 'route-data') when serializing to
D-Bus, for backward compatibility. When deserializing, they will fill
in the 'addresses' and 'routes' properties from the new-style data if
it is present (ignoring the old-style data), or from the old-style
data if the new-style isn't present.
The daemon-side NMIP4Config and NMIP6Config always emit changes for
both 'Addresses'/'Routes' and 'AddressData'/'RouteData'. The
libnm-side classes initially listen for changes on both properties,
but start ignoring the 'Addresses' and 'Routes' properties once they
know the daemon is also providing 'AddressData' and 'RouteData'.
2014-10-21 08:33:18 -04:00
|
|
|
|
|
|
|
|
g_variant_builder_init(&addr_builder, G_VARIANT_TYPE("a{sv}"));
|
|
|
|
|
g_variant_builder_add(&addr_builder,
|
|
|
|
|
"{sv}",
|
|
|
|
|
"address",
|
|
|
|
|
g_variant_new_string(nm_ip_address_get_address(addr)));
|
|
|
|
|
g_variant_builder_add(&addr_builder,
|
|
|
|
|
"{sv}",
|
|
|
|
|
"prefix",
|
|
|
|
|
g_variant_new_uint32(nm_ip_address_get_prefix(addr)));
|
|
|
|
|
|
2017-12-11 11:37:21 +01:00
|
|
|
names = _nm_ip_address_get_attribute_names(addr, TRUE, &len);
|
|
|
|
|
for (j = 0; j < len; j++) {
|
libnm-core, libnm, core: add AddressData and RouteData properties
Add AddressData and RouteData properties to NMSettingIPConfig and
NMIP[46]Config. These are like the existing "addresses" and "routes"
properties, but using strings and containing additional attributes,
like NMIPAddress and NMIPRoute.
This only affects the D-Bus representations; there are no API changes
to NMSettingIP{,4,6}Config or NMIP{4,6}Config as a result of this; the
additional information is just added to the existing 'addresses' and
'routes' properties.
NMSettingIP4Config and NMSettingIP6Config now always generate both
old-style data ('addresses', 'address-labels', 'routes') and new-style
data ('address-data', 'gateway', 'route-data') when serializing to
D-Bus, for backward compatibility. When deserializing, they will fill
in the 'addresses' and 'routes' properties from the new-style data if
it is present (ignoring the old-style data), or from the old-style
data if the new-style isn't present.
The daemon-side NMIP4Config and NMIP6Config always emit changes for
both 'Addresses'/'Routes' and 'AddressData'/'RouteData'. The
libnm-side classes initially listen for changes on both properties,
but start ignoring the 'Addresses' and 'Routes' properties once they
know the daemon is also providing 'AddressData' and 'RouteData'.
2014-10-21 08:33:18 -04:00
|
|
|
g_variant_builder_add(&addr_builder,
|
|
|
|
|
"{sv}",
|
2017-12-11 11:37:21 +01:00
|
|
|
names[j],
|
|
|
|
|
nm_ip_address_get_attribute(addr, names[j]));
|
libnm-core, libnm, core: add AddressData and RouteData properties
Add AddressData and RouteData properties to NMSettingIPConfig and
NMIP[46]Config. These are like the existing "addresses" and "routes"
properties, but using strings and containing additional attributes,
like NMIPAddress and NMIPRoute.
This only affects the D-Bus representations; there are no API changes
to NMSettingIP{,4,6}Config or NMIP{4,6}Config as a result of this; the
additional information is just added to the existing 'addresses' and
'routes' properties.
NMSettingIP4Config and NMSettingIP6Config now always generate both
old-style data ('addresses', 'address-labels', 'routes') and new-style
data ('address-data', 'gateway', 'route-data') when serializing to
D-Bus, for backward compatibility. When deserializing, they will fill
in the 'addresses' and 'routes' properties from the new-style data if
it is present (ignoring the old-style data), or from the old-style
data if the new-style isn't present.
The daemon-side NMIP4Config and NMIP6Config always emit changes for
both 'Addresses'/'Routes' and 'AddressData'/'RouteData'. The
libnm-side classes initially listen for changes on both properties,
but start ignoring the 'Addresses' and 'Routes' properties once they
know the daemon is also providing 'AddressData' and 'RouteData'.
2014-10-21 08:33:18 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_variant_builder_add(&builder, "a{sv}", &addr_builder);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return g_variant_builder_end(&builder);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_utils_ip_addresses_from_variant:
|
|
|
|
|
* @value: a #GVariant of type 'aa{sv}'
|
|
|
|
|
* @family: an IP address family
|
|
|
|
|
*
|
|
|
|
|
* Utility function to convert a #GVariant representing a list of new-style
|
|
|
|
|
* NetworkManager IPv4 or IPv6 addresses (as described in the documentation for
|
|
|
|
|
* nm_utils_ip_addresses_to_variant()) into a #GPtrArray of #NMIPAddress
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
* objects. Note that invalid addresses are discarded but the valid addresses
|
|
|
|
|
* are still returned.
|
|
|
|
|
*
|
|
|
|
|
* Since 1.46, an empty list is returned if the variant type is not valid
|
|
|
|
|
* (before it was checked as assertion)
|
libnm-core, libnm, core: add AddressData and RouteData properties
Add AddressData and RouteData properties to NMSettingIPConfig and
NMIP[46]Config. These are like the existing "addresses" and "routes"
properties, but using strings and containing additional attributes,
like NMIPAddress and NMIPRoute.
This only affects the D-Bus representations; there are no API changes
to NMSettingIP{,4,6}Config or NMIP{4,6}Config as a result of this; the
additional information is just added to the existing 'addresses' and
'routes' properties.
NMSettingIP4Config and NMSettingIP6Config now always generate both
old-style data ('addresses', 'address-labels', 'routes') and new-style
data ('address-data', 'gateway', 'route-data') when serializing to
D-Bus, for backward compatibility. When deserializing, they will fill
in the 'addresses' and 'routes' properties from the new-style data if
it is present (ignoring the old-style data), or from the old-style
data if the new-style isn't present.
The daemon-side NMIP4Config and NMIP6Config always emit changes for
both 'Addresses'/'Routes' and 'AddressData'/'RouteData'. The
libnm-side classes initially listen for changes on both properties,
but start ignoring the 'Addresses' and 'Routes' properties once they
know the daemon is also providing 'AddressData' and 'RouteData'.
2014-10-21 08:33:18 -04:00
|
|
|
*
|
|
|
|
|
* Returns: (transfer full) (element-type NMIPAddress): a newly allocated
|
|
|
|
|
* #GPtrArray of #NMIPAddress objects
|
2022-11-07 22:01:58 +01:00
|
|
|
*
|
|
|
|
|
* Since: 1.42
|
libnm-core, libnm, core: add AddressData and RouteData properties
Add AddressData and RouteData properties to NMSettingIPConfig and
NMIP[46]Config. These are like the existing "addresses" and "routes"
properties, but using strings and containing additional attributes,
like NMIPAddress and NMIPRoute.
This only affects the D-Bus representations; there are no API changes
to NMSettingIP{,4,6}Config or NMIP{4,6}Config as a result of this; the
additional information is just added to the existing 'addresses' and
'routes' properties.
NMSettingIP4Config and NMSettingIP6Config now always generate both
old-style data ('addresses', 'address-labels', 'routes') and new-style
data ('address-data', 'gateway', 'route-data') when serializing to
D-Bus, for backward compatibility. When deserializing, they will fill
in the 'addresses' and 'routes' properties from the new-style data if
it is present (ignoring the old-style data), or from the old-style
data if the new-style isn't present.
The daemon-side NMIP4Config and NMIP6Config always emit changes for
both 'Addresses'/'Routes' and 'AddressData'/'RouteData'. The
libnm-side classes initially listen for changes on both properties,
but start ignoring the 'Addresses' and 'Routes' properties once they
know the daemon is also providing 'AddressData' and 'RouteData'.
2014-10-21 08:33:18 -04:00
|
|
|
**/
|
|
|
|
|
GPtrArray *
|
|
|
|
|
nm_utils_ip_addresses_from_variant(GVariant *value, int family)
|
|
|
|
|
{
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
return _nm_utils_ip_addresses_from_variant(value, family, FALSE, NULL);
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
/**
|
|
|
|
|
* _nm_utils_ip_addresses_from_variant:
|
|
|
|
|
* @value: a #GVariant of type 'aa{sv}'
|
|
|
|
|
* @family: an IP address family
|
|
|
|
|
* @strict: whether to parse in strict mode or best-effort mode
|
|
|
|
|
* @error: the error location
|
|
|
|
|
*
|
2025-02-28 17:56:00 +01:00
|
|
|
* Like #nm_utils_ip_addresses_from_variant, but allows one to parse in strict mode. In
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
* strict mode, parsing is aborted on first error and %NULL is returned.
|
|
|
|
|
*
|
|
|
|
|
* Returns: (transfer full) (element-type NMIPAddress): a newly allocated
|
|
|
|
|
* #GPtrArray of #NMIPAddress objects. In strict mode, %NULL is returned on error.
|
|
|
|
|
*/
|
|
|
|
|
GPtrArray *
|
|
|
|
|
_nm_utils_ip_addresses_from_variant(GVariant *value, int family, bool strict, GError **error)
|
|
|
|
|
{
|
|
|
|
|
gs_unref_ptrarray GPtrArray *addresses = NULL;
|
|
|
|
|
GVariantIter iter, attrs_iter;
|
|
|
|
|
GVariant *item;
|
|
|
|
|
const char *ip;
|
|
|
|
|
guint32 prefix;
|
|
|
|
|
NMIPAddress *addr;
|
|
|
|
|
const char *attr_name;
|
|
|
|
|
guint i;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm-core, libnm, core: add AddressData and RouteData properties
Add AddressData and RouteData properties to NMSettingIPConfig and
NMIP[46]Config. These are like the existing "addresses" and "routes"
properties, but using strings and containing additional attributes,
like NMIPAddress and NMIPRoute.
This only affects the D-Bus representations; there are no API changes
to NMSettingIP{,4,6}Config or NMIP{4,6}Config as a result of this; the
additional information is just added to the existing 'addresses' and
'routes' properties.
NMSettingIP4Config and NMSettingIP6Config now always generate both
old-style data ('addresses', 'address-labels', 'routes') and new-style
data ('address-data', 'gateway', 'route-data') when serializing to
D-Bus, for backward compatibility. When deserializing, they will fill
in the 'addresses' and 'routes' properties from the new-style data if
it is present (ignoring the old-style data), or from the old-style
data if the new-style isn't present.
The daemon-side NMIP4Config and NMIP6Config always emit changes for
both 'Addresses'/'Routes' and 'AddressData'/'RouteData'. The
libnm-side classes initially listen for changes on both properties,
but start ignoring the 'Addresses' and 'Routes' properties once they
know the daemon is also providing 'AddressData' and 'RouteData'.
2014-10-21 08:33:18 -04:00
|
|
|
addresses = g_ptr_array_new_with_free_func((GDestroyNotify) nm_ip_address_unref);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
if (!g_variant_is_of_type(value, G_VARIANT_TYPE("aa{sv}"))) {
|
|
|
|
|
if (strict) {
|
|
|
|
|
g_set_error_literal(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("Expected value of type \"aa{sv}\""));
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
return g_steal_pointer(&addresses);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_variant_iter_init(&iter, value);
|
|
|
|
|
|
|
|
|
|
for (i = 0; g_variant_iter_next(&iter, "@a{sv}", &item); i++) {
|
|
|
|
|
gs_unref_variant GVariant *addr_var = item;
|
|
|
|
|
gs_free_error GError *local_error = NULL;
|
|
|
|
|
|
libnm-core, libnm, core: add AddressData and RouteData properties
Add AddressData and RouteData properties to NMSettingIPConfig and
NMIP[46]Config. These are like the existing "addresses" and "routes"
properties, but using strings and containing additional attributes,
like NMIPAddress and NMIPRoute.
This only affects the D-Bus representations; there are no API changes
to NMSettingIP{,4,6}Config or NMIP{4,6}Config as a result of this; the
additional information is just added to the existing 'addresses' and
'routes' properties.
NMSettingIP4Config and NMSettingIP6Config now always generate both
old-style data ('addresses', 'address-labels', 'routes') and new-style
data ('address-data', 'gateway', 'route-data') when serializing to
D-Bus, for backward compatibility. When deserializing, they will fill
in the 'addresses' and 'routes' properties from the new-style data if
it is present (ignoring the old-style data), or from the old-style
data if the new-style isn't present.
The daemon-side NMIP4Config and NMIP6Config always emit changes for
both 'Addresses'/'Routes' and 'AddressData'/'RouteData'. The
libnm-side classes initially listen for changes on both properties,
but start ignoring the 'Addresses' and 'Routes' properties once they
know the daemon is also providing 'AddressData' and 'RouteData'.
2014-10-21 08:33:18 -04:00
|
|
|
if (!g_variant_lookup(addr_var, "address", "&s", &ip)
|
|
|
|
|
|| !g_variant_lookup(addr_var, "prefix", "u", &prefix)) {
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
if (strict) {
|
|
|
|
|
g_set_error(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
2025-01-24 13:41:36 +01:00
|
|
|
_("IP address requires fields \"address\" and \"prefix\" (idx=%u)"),
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
i);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
libnm-core, libnm, core: add AddressData and RouteData properties
Add AddressData and RouteData properties to NMSettingIPConfig and
NMIP[46]Config. These are like the existing "addresses" and "routes"
properties, but using strings and containing additional attributes,
like NMIPAddress and NMIPRoute.
This only affects the D-Bus representations; there are no API changes
to NMSettingIP{,4,6}Config or NMIP{4,6}Config as a result of this; the
additional information is just added to the existing 'addresses' and
'routes' properties.
NMSettingIP4Config and NMSettingIP6Config now always generate both
old-style data ('addresses', 'address-labels', 'routes') and new-style
data ('address-data', 'gateway', 'route-data') when serializing to
D-Bus, for backward compatibility. When deserializing, they will fill
in the 'addresses' and 'routes' properties from the new-style data if
it is present (ignoring the old-style data), or from the old-style
data if the new-style isn't present.
The daemon-side NMIP4Config and NMIP6Config always emit changes for
both 'Addresses'/'Routes' and 'AddressData'/'RouteData'. The
libnm-side classes initially listen for changes on both properties,
but start ignoring the 'Addresses' and 'Routes' properties once they
know the daemon is also providing 'AddressData' and 'RouteData'.
2014-10-21 08:33:18 -04:00
|
|
|
continue;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
addr = nm_ip_address_new(family, ip, prefix, &local_error);
|
libnm-core, libnm, core: add AddressData and RouteData properties
Add AddressData and RouteData properties to NMSettingIPConfig and
NMIP[46]Config. These are like the existing "addresses" and "routes"
properties, but using strings and containing additional attributes,
like NMIPAddress and NMIPRoute.
This only affects the D-Bus representations; there are no API changes
to NMSettingIP{,4,6}Config or NMIP{4,6}Config as a result of this; the
additional information is just added to the existing 'addresses' and
'routes' properties.
NMSettingIP4Config and NMSettingIP6Config now always generate both
old-style data ('addresses', 'address-labels', 'routes') and new-style
data ('address-data', 'gateway', 'route-data') when serializing to
D-Bus, for backward compatibility. When deserializing, they will fill
in the 'addresses' and 'routes' properties from the new-style data if
it is present (ignoring the old-style data), or from the old-style
data if the new-style isn't present.
The daemon-side NMIP4Config and NMIP6Config always emit changes for
both 'Addresses'/'Routes' and 'AddressData'/'RouteData'. The
libnm-side classes initially listen for changes on both properties,
but start ignoring the 'Addresses' and 'Routes' properties once they
know the daemon is also providing 'AddressData' and 'RouteData'.
2014-10-21 08:33:18 -04:00
|
|
|
if (!addr) {
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
if (strict) {
|
|
|
|
|
g_set_error(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("%s (idx=%u)"),
|
|
|
|
|
local_error->message,
|
|
|
|
|
i);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
libnm-core, libnm, core: add AddressData and RouteData properties
Add AddressData and RouteData properties to NMSettingIPConfig and
NMIP[46]Config. These are like the existing "addresses" and "routes"
properties, but using strings and containing additional attributes,
like NMIPAddress and NMIPRoute.
This only affects the D-Bus representations; there are no API changes
to NMSettingIP{,4,6}Config or NMIP{4,6}Config as a result of this; the
additional information is just added to the existing 'addresses' and
'routes' properties.
NMSettingIP4Config and NMSettingIP6Config now always generate both
old-style data ('addresses', 'address-labels', 'routes') and new-style
data ('address-data', 'gateway', 'route-data') when serializing to
D-Bus, for backward compatibility. When deserializing, they will fill
in the 'addresses' and 'routes' properties from the new-style data if
it is present (ignoring the old-style data), or from the old-style
data if the new-style isn't present.
The daemon-side NMIP4Config and NMIP6Config always emit changes for
both 'Addresses'/'Routes' and 'AddressData'/'RouteData'. The
libnm-side classes initially listen for changes on both properties,
but start ignoring the 'Addresses' and 'Routes' properties once they
know the daemon is also providing 'AddressData' and 'RouteData'.
2014-10-21 08:33:18 -04:00
|
|
|
continue;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm-core, libnm, core: add AddressData and RouteData properties
Add AddressData and RouteData properties to NMSettingIPConfig and
NMIP[46]Config. These are like the existing "addresses" and "routes"
properties, but using strings and containing additional attributes,
like NMIPAddress and NMIPRoute.
This only affects the D-Bus representations; there are no API changes
to NMSettingIP{,4,6}Config or NMIP{4,6}Config as a result of this; the
additional information is just added to the existing 'addresses' and
'routes' properties.
NMSettingIP4Config and NMSettingIP6Config now always generate both
old-style data ('addresses', 'address-labels', 'routes') and new-style
data ('address-data', 'gateway', 'route-data') when serializing to
D-Bus, for backward compatibility. When deserializing, they will fill
in the 'addresses' and 'routes' properties from the new-style data if
it is present (ignoring the old-style data), or from the old-style
data if the new-style isn't present.
The daemon-side NMIP4Config and NMIP6Config always emit changes for
both 'Addresses'/'Routes' and 'AddressData'/'RouteData'. The
libnm-side classes initially listen for changes on both properties,
but start ignoring the 'Addresses' and 'Routes' properties once they
know the daemon is also providing 'AddressData' and 'RouteData'.
2014-10-21 08:33:18 -04:00
|
|
|
g_variant_iter_init(&attrs_iter, addr_var);
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
while (g_variant_iter_next(&attrs_iter, "{&sv}", &attr_name, &item)) {
|
|
|
|
|
gs_unref_variant GVariant *attr_val = item;
|
|
|
|
|
|
2020-06-21 21:48:59 +02:00
|
|
|
if (!NM_IN_STRSET(attr_name, "address", "prefix"))
|
libnm-core, libnm, core: add AddressData and RouteData properties
Add AddressData and RouteData properties to NMSettingIPConfig and
NMIP[46]Config. These are like the existing "addresses" and "routes"
properties, but using strings and containing additional attributes,
like NMIPAddress and NMIPRoute.
This only affects the D-Bus representations; there are no API changes
to NMSettingIP{,4,6}Config or NMIP{4,6}Config as a result of this; the
additional information is just added to the existing 'addresses' and
'routes' properties.
NMSettingIP4Config and NMSettingIP6Config now always generate both
old-style data ('addresses', 'address-labels', 'routes') and new-style
data ('address-data', 'gateway', 'route-data') when serializing to
D-Bus, for backward compatibility. When deserializing, they will fill
in the 'addresses' and 'routes' properties from the new-style data if
it is present (ignoring the old-style data), or from the old-style
data if the new-style isn't present.
The daemon-side NMIP4Config and NMIP6Config always emit changes for
both 'Addresses'/'Routes' and 'AddressData'/'RouteData'. The
libnm-side classes initially listen for changes on both properties,
but start ignoring the 'Addresses' and 'Routes' properties once they
know the daemon is also providing 'AddressData' and 'RouteData'.
2014-10-21 08:33:18 -04:00
|
|
|
nm_ip_address_set_attribute(addr, attr_name, attr_val);
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm-core, libnm, core: add AddressData and RouteData properties
Add AddressData and RouteData properties to NMSettingIPConfig and
NMIP[46]Config. These are like the existing "addresses" and "routes"
properties, but using strings and containing additional attributes,
like NMIPAddress and NMIPRoute.
This only affects the D-Bus representations; there are no API changes
to NMSettingIP{,4,6}Config or NMIP{4,6}Config as a result of this; the
additional information is just added to the existing 'addresses' and
'routes' properties.
NMSettingIP4Config and NMSettingIP6Config now always generate both
old-style data ('addresses', 'address-labels', 'routes') and new-style
data ('address-data', 'gateway', 'route-data') when serializing to
D-Bus, for backward compatibility. When deserializing, they will fill
in the 'addresses' and 'routes' properties from the new-style data if
it is present (ignoring the old-style data), or from the old-style
data if the new-style isn't present.
The daemon-side NMIP4Config and NMIP6Config always emit changes for
both 'Addresses'/'Routes' and 'AddressData'/'RouteData'. The
libnm-side classes initially listen for changes on both properties,
but start ignoring the 'Addresses' and 'Routes' properties once they
know the daemon is also providing 'AddressData' and 'RouteData'.
2014-10-21 08:33:18 -04:00
|
|
|
g_ptr_array_add(addresses, addr);
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
return g_steal_pointer(&addresses);
|
libnm-core, libnm, core: add AddressData and RouteData properties
Add AddressData and RouteData properties to NMSettingIPConfig and
NMIP[46]Config. These are like the existing "addresses" and "routes"
properties, but using strings and containing additional attributes,
like NMIPAddress and NMIPRoute.
This only affects the D-Bus representations; there are no API changes
to NMSettingIP{,4,6}Config or NMIP{4,6}Config as a result of this; the
additional information is just added to the existing 'addresses' and
'routes' properties.
NMSettingIP4Config and NMSettingIP6Config now always generate both
old-style data ('addresses', 'address-labels', 'routes') and new-style
data ('address-data', 'gateway', 'route-data') when serializing to
D-Bus, for backward compatibility. When deserializing, they will fill
in the 'addresses' and 'routes' properties from the new-style data if
it is present (ignoring the old-style data), or from the old-style
data if the new-style isn't present.
The daemon-side NMIP4Config and NMIP6Config always emit changes for
both 'Addresses'/'Routes' and 'AddressData'/'RouteData'. The
libnm-side classes initially listen for changes on both properties,
but start ignoring the 'Addresses' and 'Routes' properties once they
know the daemon is also providing 'AddressData' and 'RouteData'.
2014-10-21 08:33:18 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_utils_ip_routes_to_variant:
|
|
|
|
|
* @routes: (element-type NMIPRoute): an array of #NMIPRoute objects
|
|
|
|
|
*
|
|
|
|
|
* Utility function to convert a #GPtrArray of #NMIPRoute objects representing
|
|
|
|
|
* IPv4 or IPv6 routes into a #GVariant of type 'aa{sv}' representing an array
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
* of new-style NetworkManager IP routes. All routes will include "dest" (an IP
|
|
|
|
|
* address string), "prefix" (an uint) and optionally "next-hop" (an IP address
|
|
|
|
|
* string) and "metric" (an uint). Some routes may include additional attributes.
|
|
|
|
|
* Note that invalid routes are discarded and only a warning is emitted, but the
|
|
|
|
|
* valid routes are still returned.
|
libnm-core, libnm, core: add AddressData and RouteData properties
Add AddressData and RouteData properties to NMSettingIPConfig and
NMIP[46]Config. These are like the existing "addresses" and "routes"
properties, but using strings and containing additional attributes,
like NMIPAddress and NMIPRoute.
This only affects the D-Bus representations; there are no API changes
to NMSettingIP{,4,6}Config or NMIP{4,6}Config as a result of this; the
additional information is just added to the existing 'addresses' and
'routes' properties.
NMSettingIP4Config and NMSettingIP6Config now always generate both
old-style data ('addresses', 'address-labels', 'routes') and new-style
data ('address-data', 'gateway', 'route-data') when serializing to
D-Bus, for backward compatibility. When deserializing, they will fill
in the 'addresses' and 'routes' properties from the new-style data if
it is present (ignoring the old-style data), or from the old-style
data if the new-style isn't present.
The daemon-side NMIP4Config and NMIP6Config always emit changes for
both 'Addresses'/'Routes' and 'AddressData'/'RouteData'. The
libnm-side classes initially listen for changes on both properties,
but start ignoring the 'Addresses' and 'Routes' properties once they
know the daemon is also providing 'AddressData' and 'RouteData'.
2014-10-21 08:33:18 -04:00
|
|
|
*
|
|
|
|
|
* Returns: (transfer none): a new floating #GVariant representing @routes.
|
2022-11-07 22:01:58 +01:00
|
|
|
*
|
|
|
|
|
* Since: 1.42
|
libnm-core, libnm, core: add AddressData and RouteData properties
Add AddressData and RouteData properties to NMSettingIPConfig and
NMIP[46]Config. These are like the existing "addresses" and "routes"
properties, but using strings and containing additional attributes,
like NMIPAddress and NMIPRoute.
This only affects the D-Bus representations; there are no API changes
to NMSettingIP{,4,6}Config or NMIP{4,6}Config as a result of this; the
additional information is just added to the existing 'addresses' and
'routes' properties.
NMSettingIP4Config and NMSettingIP6Config now always generate both
old-style data ('addresses', 'address-labels', 'routes') and new-style
data ('address-data', 'gateway', 'route-data') when serializing to
D-Bus, for backward compatibility. When deserializing, they will fill
in the 'addresses' and 'routes' properties from the new-style data if
it is present (ignoring the old-style data), or from the old-style
data if the new-style isn't present.
The daemon-side NMIP4Config and NMIP6Config always emit changes for
both 'Addresses'/'Routes' and 'AddressData'/'RouteData'. The
libnm-side classes initially listen for changes on both properties,
but start ignoring the 'Addresses' and 'Routes' properties once they
know the daemon is also providing 'AddressData' and 'RouteData'.
2014-10-21 08:33:18 -04:00
|
|
|
**/
|
|
|
|
|
GVariant *
|
|
|
|
|
nm_utils_ip_routes_to_variant(GPtrArray *routes)
|
|
|
|
|
{
|
|
|
|
|
GVariantBuilder builder;
|
2020-10-29 12:36:22 +01:00
|
|
|
guint i;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm-core, libnm, core: add AddressData and RouteData properties
Add AddressData and RouteData properties to NMSettingIPConfig and
NMIP[46]Config. These are like the existing "addresses" and "routes"
properties, but using strings and containing additional attributes,
like NMIPAddress and NMIPRoute.
This only affects the D-Bus representations; there are no API changes
to NMSettingIP{,4,6}Config or NMIP{4,6}Config as a result of this; the
additional information is just added to the existing 'addresses' and
'routes' properties.
NMSettingIP4Config and NMSettingIP6Config now always generate both
old-style data ('addresses', 'address-labels', 'routes') and new-style
data ('address-data', 'gateway', 'route-data') when serializing to
D-Bus, for backward compatibility. When deserializing, they will fill
in the 'addresses' and 'routes' properties from the new-style data if
it is present (ignoring the old-style data), or from the old-style
data if the new-style isn't present.
The daemon-side NMIP4Config and NMIP6Config always emit changes for
both 'Addresses'/'Routes' and 'AddressData'/'RouteData'. The
libnm-side classes initially listen for changes on both properties,
but start ignoring the 'Addresses' and 'Routes' properties once they
know the daemon is also providing 'AddressData' and 'RouteData'.
2014-10-21 08:33:18 -04:00
|
|
|
g_variant_builder_init(&builder, G_VARIANT_TYPE("aa{sv}"));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm-core, libnm, core: add AddressData and RouteData properties
Add AddressData and RouteData properties to NMSettingIPConfig and
NMIP[46]Config. These are like the existing "addresses" and "routes"
properties, but using strings and containing additional attributes,
like NMIPAddress and NMIPRoute.
This only affects the D-Bus representations; there are no API changes
to NMSettingIP{,4,6}Config or NMIP{4,6}Config as a result of this; the
additional information is just added to the existing 'addresses' and
'routes' properties.
NMSettingIP4Config and NMSettingIP6Config now always generate both
old-style data ('addresses', 'address-labels', 'routes') and new-style
data ('address-data', 'gateway', 'route-data') when serializing to
D-Bus, for backward compatibility. When deserializing, they will fill
in the 'addresses' and 'routes' properties from the new-style data if
it is present (ignoring the old-style data), or from the old-style
data if the new-style isn't present.
The daemon-side NMIP4Config and NMIP6Config always emit changes for
both 'Addresses'/'Routes' and 'AddressData'/'RouteData'. The
libnm-side classes initially listen for changes on both properties,
but start ignoring the 'Addresses' and 'Routes' properties once they
know the daemon is also providing 'AddressData' and 'RouteData'.
2014-10-21 08:33:18 -04:00
|
|
|
if (routes) {
|
|
|
|
|
for (i = 0; i < routes->len; i++) {
|
2021-11-09 13:28:54 +01:00
|
|
|
NMIPRoute *route = routes->pdata[i];
|
libnm-core, libnm, core: add AddressData and RouteData properties
Add AddressData and RouteData properties to NMSettingIPConfig and
NMIP[46]Config. These are like the existing "addresses" and "routes"
properties, but using strings and containing additional attributes,
like NMIPAddress and NMIPRoute.
This only affects the D-Bus representations; there are no API changes
to NMSettingIP{,4,6}Config or NMIP{4,6}Config as a result of this; the
additional information is just added to the existing 'addresses' and
'routes' properties.
NMSettingIP4Config and NMSettingIP6Config now always generate both
old-style data ('addresses', 'address-labels', 'routes') and new-style
data ('address-data', 'gateway', 'route-data') when serializing to
D-Bus, for backward compatibility. When deserializing, they will fill
in the 'addresses' and 'routes' properties from the new-style data if
it is present (ignoring the old-style data), or from the old-style
data if the new-style isn't present.
The daemon-side NMIP4Config and NMIP6Config always emit changes for
both 'Addresses'/'Routes' and 'AddressData'/'RouteData'. The
libnm-side classes initially listen for changes on both properties,
but start ignoring the 'Addresses' and 'Routes' properties once they
know the daemon is also providing 'AddressData' and 'RouteData'.
2014-10-21 08:33:18 -04:00
|
|
|
GVariantBuilder route_builder;
|
2017-10-30 12:23:34 +01:00
|
|
|
gs_free const char **names = NULL;
|
|
|
|
|
guint j, len;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm-core, libnm, core: add AddressData and RouteData properties
Add AddressData and RouteData properties to NMSettingIPConfig and
NMIP[46]Config. These are like the existing "addresses" and "routes"
properties, but using strings and containing additional attributes,
like NMIPAddress and NMIPRoute.
This only affects the D-Bus representations; there are no API changes
to NMSettingIP{,4,6}Config or NMIP{4,6}Config as a result of this; the
additional information is just added to the existing 'addresses' and
'routes' properties.
NMSettingIP4Config and NMSettingIP6Config now always generate both
old-style data ('addresses', 'address-labels', 'routes') and new-style
data ('address-data', 'gateway', 'route-data') when serializing to
D-Bus, for backward compatibility. When deserializing, they will fill
in the 'addresses' and 'routes' properties from the new-style data if
it is present (ignoring the old-style data), or from the old-style
data if the new-style isn't present.
The daemon-side NMIP4Config and NMIP6Config always emit changes for
both 'Addresses'/'Routes' and 'AddressData'/'RouteData'. The
libnm-side classes initially listen for changes on both properties,
but start ignoring the 'Addresses' and 'Routes' properties once they
know the daemon is also providing 'AddressData' and 'RouteData'.
2014-10-21 08:33:18 -04:00
|
|
|
g_variant_builder_init(&route_builder, G_VARIANT_TYPE("a{sv}"));
|
|
|
|
|
g_variant_builder_add(&route_builder,
|
|
|
|
|
"{sv}",
|
|
|
|
|
"dest",
|
|
|
|
|
g_variant_new_string(nm_ip_route_get_dest(route)));
|
|
|
|
|
g_variant_builder_add(&route_builder,
|
|
|
|
|
"{sv}",
|
|
|
|
|
"prefix",
|
|
|
|
|
g_variant_new_uint32(nm_ip_route_get_prefix(route)));
|
|
|
|
|
if (nm_ip_route_get_next_hop(route)) {
|
|
|
|
|
g_variant_builder_add(&route_builder,
|
|
|
|
|
"{sv}",
|
|
|
|
|
"next-hop",
|
|
|
|
|
g_variant_new_string(nm_ip_route_get_next_hop(route)));
|
|
|
|
|
}
|
2014-11-04 15:48:48 -05:00
|
|
|
if (nm_ip_route_get_metric(route) != -1) {
|
libnm-core, libnm, core: add AddressData and RouteData properties
Add AddressData and RouteData properties to NMSettingIPConfig and
NMIP[46]Config. These are like the existing "addresses" and "routes"
properties, but using strings and containing additional attributes,
like NMIPAddress and NMIPRoute.
This only affects the D-Bus representations; there are no API changes
to NMSettingIP{,4,6}Config or NMIP{4,6}Config as a result of this; the
additional information is just added to the existing 'addresses' and
'routes' properties.
NMSettingIP4Config and NMSettingIP6Config now always generate both
old-style data ('addresses', 'address-labels', 'routes') and new-style
data ('address-data', 'gateway', 'route-data') when serializing to
D-Bus, for backward compatibility. When deserializing, they will fill
in the 'addresses' and 'routes' properties from the new-style data if
it is present (ignoring the old-style data), or from the old-style
data if the new-style isn't present.
The daemon-side NMIP4Config and NMIP6Config always emit changes for
both 'Addresses'/'Routes' and 'AddressData'/'RouteData'. The
libnm-side classes initially listen for changes on both properties,
but start ignoring the 'Addresses' and 'Routes' properties once they
know the daemon is also providing 'AddressData' and 'RouteData'.
2014-10-21 08:33:18 -04:00
|
|
|
g_variant_builder_add(
|
|
|
|
|
&route_builder,
|
|
|
|
|
"{sv}",
|
|
|
|
|
"metric",
|
2014-11-04 15:48:48 -05:00
|
|
|
g_variant_new_uint32((guint32) nm_ip_route_get_metric(route)));
|
libnm-core, libnm, core: add AddressData and RouteData properties
Add AddressData and RouteData properties to NMSettingIPConfig and
NMIP[46]Config. These are like the existing "addresses" and "routes"
properties, but using strings and containing additional attributes,
like NMIPAddress and NMIPRoute.
This only affects the D-Bus representations; there are no API changes
to NMSettingIP{,4,6}Config or NMIP{4,6}Config as a result of this; the
additional information is just added to the existing 'addresses' and
'routes' properties.
NMSettingIP4Config and NMSettingIP6Config now always generate both
old-style data ('addresses', 'address-labels', 'routes') and new-style
data ('address-data', 'gateway', 'route-data') when serializing to
D-Bus, for backward compatibility. When deserializing, they will fill
in the 'addresses' and 'routes' properties from the new-style data if
it is present (ignoring the old-style data), or from the old-style
data if the new-style isn't present.
The daemon-side NMIP4Config and NMIP6Config always emit changes for
both 'Addresses'/'Routes' and 'AddressData'/'RouteData'. The
libnm-side classes initially listen for changes on both properties,
but start ignoring the 'Addresses' and 'Routes' properties once they
know the daemon is also providing 'AddressData' and 'RouteData'.
2014-10-21 08:33:18 -04:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-10-30 12:23:34 +01:00
|
|
|
names = _nm_ip_route_get_attribute_names(route, TRUE, &len);
|
|
|
|
|
for (j = 0; j < len; j++) {
|
libnm-core, libnm, core: add AddressData and RouteData properties
Add AddressData and RouteData properties to NMSettingIPConfig and
NMIP[46]Config. These are like the existing "addresses" and "routes"
properties, but using strings and containing additional attributes,
like NMIPAddress and NMIPRoute.
This only affects the D-Bus representations; there are no API changes
to NMSettingIP{,4,6}Config or NMIP{4,6}Config as a result of this; the
additional information is just added to the existing 'addresses' and
'routes' properties.
NMSettingIP4Config and NMSettingIP6Config now always generate both
old-style data ('addresses', 'address-labels', 'routes') and new-style
data ('address-data', 'gateway', 'route-data') when serializing to
D-Bus, for backward compatibility. When deserializing, they will fill
in the 'addresses' and 'routes' properties from the new-style data if
it is present (ignoring the old-style data), or from the old-style
data if the new-style isn't present.
The daemon-side NMIP4Config and NMIP6Config always emit changes for
both 'Addresses'/'Routes' and 'AddressData'/'RouteData'. The
libnm-side classes initially listen for changes on both properties,
but start ignoring the 'Addresses' and 'Routes' properties once they
know the daemon is also providing 'AddressData' and 'RouteData'.
2014-10-21 08:33:18 -04:00
|
|
|
g_variant_builder_add(&route_builder,
|
|
|
|
|
"{sv}",
|
2017-10-30 12:23:34 +01:00
|
|
|
names[j],
|
|
|
|
|
nm_ip_route_get_attribute(route, names[j]));
|
libnm-core, libnm, core: add AddressData and RouteData properties
Add AddressData and RouteData properties to NMSettingIPConfig and
NMIP[46]Config. These are like the existing "addresses" and "routes"
properties, but using strings and containing additional attributes,
like NMIPAddress and NMIPRoute.
This only affects the D-Bus representations; there are no API changes
to NMSettingIP{,4,6}Config or NMIP{4,6}Config as a result of this; the
additional information is just added to the existing 'addresses' and
'routes' properties.
NMSettingIP4Config and NMSettingIP6Config now always generate both
old-style data ('addresses', 'address-labels', 'routes') and new-style
data ('address-data', 'gateway', 'route-data') when serializing to
D-Bus, for backward compatibility. When deserializing, they will fill
in the 'addresses' and 'routes' properties from the new-style data if
it is present (ignoring the old-style data), or from the old-style
data if the new-style isn't present.
The daemon-side NMIP4Config and NMIP6Config always emit changes for
both 'Addresses'/'Routes' and 'AddressData'/'RouteData'. The
libnm-side classes initially listen for changes on both properties,
but start ignoring the 'Addresses' and 'Routes' properties once they
know the daemon is also providing 'AddressData' and 'RouteData'.
2014-10-21 08:33:18 -04:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm-core, libnm, core: add AddressData and RouteData properties
Add AddressData and RouteData properties to NMSettingIPConfig and
NMIP[46]Config. These are like the existing "addresses" and "routes"
properties, but using strings and containing additional attributes,
like NMIPAddress and NMIPRoute.
This only affects the D-Bus representations; there are no API changes
to NMSettingIP{,4,6}Config or NMIP{4,6}Config as a result of this; the
additional information is just added to the existing 'addresses' and
'routes' properties.
NMSettingIP4Config and NMSettingIP6Config now always generate both
old-style data ('addresses', 'address-labels', 'routes') and new-style
data ('address-data', 'gateway', 'route-data') when serializing to
D-Bus, for backward compatibility. When deserializing, they will fill
in the 'addresses' and 'routes' properties from the new-style data if
it is present (ignoring the old-style data), or from the old-style
data if the new-style isn't present.
The daemon-side NMIP4Config and NMIP6Config always emit changes for
both 'Addresses'/'Routes' and 'AddressData'/'RouteData'. The
libnm-side classes initially listen for changes on both properties,
but start ignoring the 'Addresses' and 'Routes' properties once they
know the daemon is also providing 'AddressData' and 'RouteData'.
2014-10-21 08:33:18 -04:00
|
|
|
g_variant_builder_add(&builder, "a{sv}", &route_builder);
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm-core, libnm, core: add AddressData and RouteData properties
Add AddressData and RouteData properties to NMSettingIPConfig and
NMIP[46]Config. These are like the existing "addresses" and "routes"
properties, but using strings and containing additional attributes,
like NMIPAddress and NMIPRoute.
This only affects the D-Bus representations; there are no API changes
to NMSettingIP{,4,6}Config or NMIP{4,6}Config as a result of this; the
additional information is just added to the existing 'addresses' and
'routes' properties.
NMSettingIP4Config and NMSettingIP6Config now always generate both
old-style data ('addresses', 'address-labels', 'routes') and new-style
data ('address-data', 'gateway', 'route-data') when serializing to
D-Bus, for backward compatibility. When deserializing, they will fill
in the 'addresses' and 'routes' properties from the new-style data if
it is present (ignoring the old-style data), or from the old-style
data if the new-style isn't present.
The daemon-side NMIP4Config and NMIP6Config always emit changes for
both 'Addresses'/'Routes' and 'AddressData'/'RouteData'. The
libnm-side classes initially listen for changes on both properties,
but start ignoring the 'Addresses' and 'Routes' properties once they
know the daemon is also providing 'AddressData' and 'RouteData'.
2014-10-21 08:33:18 -04:00
|
|
|
return g_variant_builder_end(&builder);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_utils_ip_routes_from_variant:
|
|
|
|
|
* @value: a #GVariant of type 'aa{sv}'
|
|
|
|
|
* @family: an IP address family
|
|
|
|
|
*
|
|
|
|
|
* Utility function to convert a #GVariant representing a list of new-style
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
* NetworkManager IPv4 or IPv6 addresses (as described in the documentation for
|
|
|
|
|
* nm_utils_ip_routes_to_variant()) into a #GPtrArray of #NMIPRoute objects.
|
|
|
|
|
* Invalid routes are discarded but the valid routes are still returned.
|
|
|
|
|
*
|
|
|
|
|
* Since 1.46, an empty list is returned if the variant type is not valid
|
|
|
|
|
* (before it was checked as assertion)
|
libnm-core, libnm, core: add AddressData and RouteData properties
Add AddressData and RouteData properties to NMSettingIPConfig and
NMIP[46]Config. These are like the existing "addresses" and "routes"
properties, but using strings and containing additional attributes,
like NMIPAddress and NMIPRoute.
This only affects the D-Bus representations; there are no API changes
to NMSettingIP{,4,6}Config or NMIP{4,6}Config as a result of this; the
additional information is just added to the existing 'addresses' and
'routes' properties.
NMSettingIP4Config and NMSettingIP6Config now always generate both
old-style data ('addresses', 'address-labels', 'routes') and new-style
data ('address-data', 'gateway', 'route-data') when serializing to
D-Bus, for backward compatibility. When deserializing, they will fill
in the 'addresses' and 'routes' properties from the new-style data if
it is present (ignoring the old-style data), or from the old-style
data if the new-style isn't present.
The daemon-side NMIP4Config and NMIP6Config always emit changes for
both 'Addresses'/'Routes' and 'AddressData'/'RouteData'. The
libnm-side classes initially listen for changes on both properties,
but start ignoring the 'Addresses' and 'Routes' properties once they
know the daemon is also providing 'AddressData' and 'RouteData'.
2014-10-21 08:33:18 -04:00
|
|
|
*
|
|
|
|
|
* Returns: (transfer full) (element-type NMIPRoute): a newly allocated
|
|
|
|
|
* #GPtrArray of #NMIPRoute objects
|
2022-11-07 22:01:58 +01:00
|
|
|
*
|
|
|
|
|
* Since: 1.42
|
libnm-core, libnm, core: add AddressData and RouteData properties
Add AddressData and RouteData properties to NMSettingIPConfig and
NMIP[46]Config. These are like the existing "addresses" and "routes"
properties, but using strings and containing additional attributes,
like NMIPAddress and NMIPRoute.
This only affects the D-Bus representations; there are no API changes
to NMSettingIP{,4,6}Config or NMIP{4,6}Config as a result of this; the
additional information is just added to the existing 'addresses' and
'routes' properties.
NMSettingIP4Config and NMSettingIP6Config now always generate both
old-style data ('addresses', 'address-labels', 'routes') and new-style
data ('address-data', 'gateway', 'route-data') when serializing to
D-Bus, for backward compatibility. When deserializing, they will fill
in the 'addresses' and 'routes' properties from the new-style data if
it is present (ignoring the old-style data), or from the old-style
data if the new-style isn't present.
The daemon-side NMIP4Config and NMIP6Config always emit changes for
both 'Addresses'/'Routes' and 'AddressData'/'RouteData'. The
libnm-side classes initially listen for changes on both properties,
but start ignoring the 'Addresses' and 'Routes' properties once they
know the daemon is also providing 'AddressData' and 'RouteData'.
2014-10-21 08:33:18 -04:00
|
|
|
**/
|
|
|
|
|
GPtrArray *
|
|
|
|
|
nm_utils_ip_routes_from_variant(GVariant *value, int family)
|
|
|
|
|
{
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
return _nm_utils_ip_routes_from_variant(value, family, FALSE, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* _nm_utils_ip_routes_from_variant:
|
|
|
|
|
* @value: a #GVariant of type 'aa{sv}'
|
|
|
|
|
* @family: an IP address family
|
|
|
|
|
* @strict: whether to parse in strict mode or best-effort mode
|
|
|
|
|
* @error: the error location
|
|
|
|
|
*
|
2025-02-28 17:56:00 +01:00
|
|
|
* Like #nm_utils_ip_routes_from_variant, but allows one to parse in strict mode. In
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
* strict mode, parsing is aborted on first error and %NULL is returned.
|
|
|
|
|
*
|
|
|
|
|
* Returns: (transfer full) (element-type NMIPRoute): a newly allocated
|
|
|
|
|
* #GPtrArray of #NMIPRoute objects. In strict mode %NULL is returned on error.
|
|
|
|
|
*/
|
|
|
|
|
GPtrArray *
|
|
|
|
|
_nm_utils_ip_routes_from_variant(GVariant *value, int family, bool strict, GError **error)
|
|
|
|
|
{
|
|
|
|
|
gs_unref_ptrarray GPtrArray *routes = NULL;
|
|
|
|
|
GVariantIter iter, attrs_iter;
|
|
|
|
|
GVariant *item;
|
|
|
|
|
const char *dest, *next_hop;
|
|
|
|
|
guint32 prefix, metric32;
|
|
|
|
|
gint64 metric;
|
|
|
|
|
const char *attr_name;
|
|
|
|
|
NMIPRoute *route;
|
|
|
|
|
guint i;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm-core, libnm, core: add AddressData and RouteData properties
Add AddressData and RouteData properties to NMSettingIPConfig and
NMIP[46]Config. These are like the existing "addresses" and "routes"
properties, but using strings and containing additional attributes,
like NMIPAddress and NMIPRoute.
This only affects the D-Bus representations; there are no API changes
to NMSettingIP{,4,6}Config or NMIP{4,6}Config as a result of this; the
additional information is just added to the existing 'addresses' and
'routes' properties.
NMSettingIP4Config and NMSettingIP6Config now always generate both
old-style data ('addresses', 'address-labels', 'routes') and new-style
data ('address-data', 'gateway', 'route-data') when serializing to
D-Bus, for backward compatibility. When deserializing, they will fill
in the 'addresses' and 'routes' properties from the new-style data if
it is present (ignoring the old-style data), or from the old-style
data if the new-style isn't present.
The daemon-side NMIP4Config and NMIP6Config always emit changes for
both 'Addresses'/'Routes' and 'AddressData'/'RouteData'. The
libnm-side classes initially listen for changes on both properties,
but start ignoring the 'Addresses' and 'Routes' properties once they
know the daemon is also providing 'AddressData' and 'RouteData'.
2014-10-21 08:33:18 -04:00
|
|
|
routes = g_ptr_array_new_with_free_func((GDestroyNotify) nm_ip_route_unref);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
if (!g_variant_is_of_type(value, G_VARIANT_TYPE("aa{sv}"))) {
|
|
|
|
|
if (strict) {
|
|
|
|
|
g_set_error_literal(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("Expected value of type \"aa{sv}\""));
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
return g_steal_pointer(&routes);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_variant_iter_init(&iter, value);
|
|
|
|
|
|
|
|
|
|
for (i = 0; g_variant_iter_next(&iter, "@a{sv}", &item); i++) {
|
|
|
|
|
gs_unref_variant GVariant *route_var = item;
|
|
|
|
|
gs_free_error GError *local_error = NULL;
|
|
|
|
|
|
libnm-core, libnm, core: add AddressData and RouteData properties
Add AddressData and RouteData properties to NMSettingIPConfig and
NMIP[46]Config. These are like the existing "addresses" and "routes"
properties, but using strings and containing additional attributes,
like NMIPAddress and NMIPRoute.
This only affects the D-Bus representations; there are no API changes
to NMSettingIP{,4,6}Config or NMIP{4,6}Config as a result of this; the
additional information is just added to the existing 'addresses' and
'routes' properties.
NMSettingIP4Config and NMSettingIP6Config now always generate both
old-style data ('addresses', 'address-labels', 'routes') and new-style
data ('address-data', 'gateway', 'route-data') when serializing to
D-Bus, for backward compatibility. When deserializing, they will fill
in the 'addresses' and 'routes' properties from the new-style data if
it is present (ignoring the old-style data), or from the old-style
data if the new-style isn't present.
The daemon-side NMIP4Config and NMIP6Config always emit changes for
both 'Addresses'/'Routes' and 'AddressData'/'RouteData'. The
libnm-side classes initially listen for changes on both properties,
but start ignoring the 'Addresses' and 'Routes' properties once they
know the daemon is also providing 'AddressData' and 'RouteData'.
2014-10-21 08:33:18 -04:00
|
|
|
if (!g_variant_lookup(route_var, "dest", "&s", &dest)
|
|
|
|
|
|| !g_variant_lookup(route_var, "prefix", "u", &prefix)) {
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
if (strict) {
|
|
|
|
|
g_set_error(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("Route requires fields \"dest\" and \"prefix\" (idx=%u)"),
|
|
|
|
|
i);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
continue;
|
libnm-core, libnm, core: add AddressData and RouteData properties
Add AddressData and RouteData properties to NMSettingIPConfig and
NMIP[46]Config. These are like the existing "addresses" and "routes"
properties, but using strings and containing additional attributes,
like NMIPAddress and NMIPRoute.
This only affects the D-Bus representations; there are no API changes
to NMSettingIP{,4,6}Config or NMIP{4,6}Config as a result of this; the
additional information is just added to the existing 'addresses' and
'routes' properties.
NMSettingIP4Config and NMSettingIP6Config now always generate both
old-style data ('addresses', 'address-labels', 'routes') and new-style
data ('address-data', 'gateway', 'route-data') when serializing to
D-Bus, for backward compatibility. When deserializing, they will fill
in the 'addresses' and 'routes' properties from the new-style data if
it is present (ignoring the old-style data), or from the old-style
data if the new-style isn't present.
The daemon-side NMIP4Config and NMIP6Config always emit changes for
both 'Addresses'/'Routes' and 'AddressData'/'RouteData'. The
libnm-side classes initially listen for changes on both properties,
but start ignoring the 'Addresses' and 'Routes' properties once they
know the daemon is also providing 'AddressData' and 'RouteData'.
2014-10-21 08:33:18 -04:00
|
|
|
}
|
|
|
|
|
if (!g_variant_lookup(route_var, "next-hop", "&s", &next_hop))
|
|
|
|
|
next_hop = NULL;
|
2014-11-04 15:48:48 -05:00
|
|
|
if (g_variant_lookup(route_var, "metric", "u", &metric32))
|
|
|
|
|
metric = metric32;
|
|
|
|
|
else
|
|
|
|
|
metric = -1;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
route = nm_ip_route_new(family, dest, prefix, next_hop, metric, &local_error);
|
libnm-core, libnm, core: add AddressData and RouteData properties
Add AddressData and RouteData properties to NMSettingIPConfig and
NMIP[46]Config. These are like the existing "addresses" and "routes"
properties, but using strings and containing additional attributes,
like NMIPAddress and NMIPRoute.
This only affects the D-Bus representations; there are no API changes
to NMSettingIP{,4,6}Config or NMIP{4,6}Config as a result of this; the
additional information is just added to the existing 'addresses' and
'routes' properties.
NMSettingIP4Config and NMSettingIP6Config now always generate both
old-style data ('addresses', 'address-labels', 'routes') and new-style
data ('address-data', 'gateway', 'route-data') when serializing to
D-Bus, for backward compatibility. When deserializing, they will fill
in the 'addresses' and 'routes' properties from the new-style data if
it is present (ignoring the old-style data), or from the old-style
data if the new-style isn't present.
The daemon-side NMIP4Config and NMIP6Config always emit changes for
both 'Addresses'/'Routes' and 'AddressData'/'RouteData'. The
libnm-side classes initially listen for changes on both properties,
but start ignoring the 'Addresses' and 'Routes' properties once they
know the daemon is also providing 'AddressData' and 'RouteData'.
2014-10-21 08:33:18 -04:00
|
|
|
if (!route) {
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
if (strict) {
|
|
|
|
|
g_set_error(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("%s (idx=%u)"),
|
|
|
|
|
local_error->message,
|
|
|
|
|
i);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
continue;
|
libnm-core, libnm, core: add AddressData and RouteData properties
Add AddressData and RouteData properties to NMSettingIPConfig and
NMIP[46]Config. These are like the existing "addresses" and "routes"
properties, but using strings and containing additional attributes,
like NMIPAddress and NMIPRoute.
This only affects the D-Bus representations; there are no API changes
to NMSettingIP{,4,6}Config or NMIP{4,6}Config as a result of this; the
additional information is just added to the existing 'addresses' and
'routes' properties.
NMSettingIP4Config and NMSettingIP6Config now always generate both
old-style data ('addresses', 'address-labels', 'routes') and new-style
data ('address-data', 'gateway', 'route-data') when serializing to
D-Bus, for backward compatibility. When deserializing, they will fill
in the 'addresses' and 'routes' properties from the new-style data if
it is present (ignoring the old-style data), or from the old-style
data if the new-style isn't present.
The daemon-side NMIP4Config and NMIP6Config always emit changes for
both 'Addresses'/'Routes' and 'AddressData'/'RouteData'. The
libnm-side classes initially listen for changes on both properties,
but start ignoring the 'Addresses' and 'Routes' properties once they
know the daemon is also providing 'AddressData' and 'RouteData'.
2014-10-21 08:33:18 -04:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm-core, libnm, core: add AddressData and RouteData properties
Add AddressData and RouteData properties to NMSettingIPConfig and
NMIP[46]Config. These are like the existing "addresses" and "routes"
properties, but using strings and containing additional attributes,
like NMIPAddress and NMIPRoute.
This only affects the D-Bus representations; there are no API changes
to NMSettingIP{,4,6}Config or NMIP{4,6}Config as a result of this; the
additional information is just added to the existing 'addresses' and
'routes' properties.
NMSettingIP4Config and NMSettingIP6Config now always generate both
old-style data ('addresses', 'address-labels', 'routes') and new-style
data ('address-data', 'gateway', 'route-data') when serializing to
D-Bus, for backward compatibility. When deserializing, they will fill
in the 'addresses' and 'routes' properties from the new-style data if
it is present (ignoring the old-style data), or from the old-style
data if the new-style isn't present.
The daemon-side NMIP4Config and NMIP6Config always emit changes for
both 'Addresses'/'Routes' and 'AddressData'/'RouteData'. The
libnm-side classes initially listen for changes on both properties,
but start ignoring the 'Addresses' and 'Routes' properties once they
know the daemon is also providing 'AddressData' and 'RouteData'.
2014-10-21 08:33:18 -04:00
|
|
|
g_variant_iter_init(&attrs_iter, route_var);
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
while (g_variant_iter_next(&attrs_iter, "{&sv}", &attr_name, &item)) {
|
|
|
|
|
gs_unref_variant GVariant *attr_val = item;
|
|
|
|
|
|
2020-06-21 21:48:59 +02:00
|
|
|
if (!NM_IN_STRSET(attr_name, "dest", "prefix", "next-hop", "metric"))
|
libnm-core, libnm, core: add AddressData and RouteData properties
Add AddressData and RouteData properties to NMSettingIPConfig and
NMIP[46]Config. These are like the existing "addresses" and "routes"
properties, but using strings and containing additional attributes,
like NMIPAddress and NMIPRoute.
This only affects the D-Bus representations; there are no API changes
to NMSettingIP{,4,6}Config or NMIP{4,6}Config as a result of this; the
additional information is just added to the existing 'addresses' and
'routes' properties.
NMSettingIP4Config and NMSettingIP6Config now always generate both
old-style data ('addresses', 'address-labels', 'routes') and new-style
data ('address-data', 'gateway', 'route-data') when serializing to
D-Bus, for backward compatibility. When deserializing, they will fill
in the 'addresses' and 'routes' properties from the new-style data if
it is present (ignoring the old-style data), or from the old-style
data if the new-style isn't present.
The daemon-side NMIP4Config and NMIP6Config always emit changes for
both 'Addresses'/'Routes' and 'AddressData'/'RouteData'. The
libnm-side classes initially listen for changes on both properties,
but start ignoring the 'Addresses' and 'Routes' properties once they
know the daemon is also providing 'AddressData' and 'RouteData'.
2014-10-21 08:33:18 -04:00
|
|
|
nm_ip_route_set_attribute(route, attr_name, attr_val);
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm-core, libnm, core: add AddressData and RouteData properties
Add AddressData and RouteData properties to NMSettingIPConfig and
NMIP[46]Config. These are like the existing "addresses" and "routes"
properties, but using strings and containing additional attributes,
like NMIPAddress and NMIPRoute.
This only affects the D-Bus representations; there are no API changes
to NMSettingIP{,4,6}Config or NMIP{4,6}Config as a result of this; the
additional information is just added to the existing 'addresses' and
'routes' properties.
NMSettingIP4Config and NMSettingIP6Config now always generate both
old-style data ('addresses', 'address-labels', 'routes') and new-style
data ('address-data', 'gateway', 'route-data') when serializing to
D-Bus, for backward compatibility. When deserializing, they will fill
in the 'addresses' and 'routes' properties from the new-style data if
it is present (ignoring the old-style data), or from the old-style
data if the new-style isn't present.
The daemon-side NMIP4Config and NMIP6Config always emit changes for
both 'Addresses'/'Routes' and 'AddressData'/'RouteData'. The
libnm-side classes initially listen for changes on both properties,
but start ignoring the 'Addresses' and 'Routes' properties once they
know the daemon is also providing 'AddressData' and 'RouteData'.
2014-10-21 08:33:18 -04:00
|
|
|
g_ptr_array_add(routes, route);
|
|
|
|
|
}
|
|
|
|
|
|
libnm/dbus: notify errors for invalid IPv4 properties
Invalid addresses received via DBUS were just ignored and filtered out,
only emitting a warning to the logs. If there were still some valid
addresses, those were configured and the client was unaware of the
errors. Only if there was not any valid address at all and method was
manual, an error was returned from `verify`, but not reflecting the
real cause:
ipv4.addresses: this property cannot be empty for 'method=manual'
Check for invalid addresses errors in the `_from_dbus` functions. With
NM_SETTING_PARSE_FLAG_STRICT, parsing is aborted on first error and
error is returned. With NM_SETTING_PARSE_BEST_EFFORT, we keep parsing
and set only the valid values.
Actually, the invalid addresses were dropped in a helper function that
converts from GVariant to NMIPAddress. As it is part of the public API,
we can't change now its signature to add the GError argument. Instead,
create a new internal function and call it from the public one. The
public function will ignore the error, as it was doing previously, but
it won't emit any warning to avoid spamming the logs (we don't even
know if ignoring the invalid values was intentional when calling the
function). The new internal function might be made public in
the future, deprecating the other, but probably it is not necessary
because clients are never going to receive invalid addresses from the
daemon.
Do the same as explained above for DNS entries and routes.
Also, fix the documentation of nm_utils_ip_routes_to/from_dbus, which
said that it accepts new style routes but described the old style ones.
2023-10-10 09:21:39 +02:00
|
|
|
return g_steal_pointer(&routes);
|
libnm-core, libnm, core: add AddressData and RouteData properties
Add AddressData and RouteData properties to NMSettingIPConfig and
NMIP[46]Config. These are like the existing "addresses" and "routes"
properties, but using strings and containing additional attributes,
like NMIPAddress and NMIPRoute.
This only affects the D-Bus representations; there are no API changes
to NMSettingIP{,4,6}Config or NMIP{4,6}Config as a result of this; the
additional information is just added to the existing 'addresses' and
'routes' properties.
NMSettingIP4Config and NMSettingIP6Config now always generate both
old-style data ('addresses', 'address-labels', 'routes') and new-style
data ('address-data', 'gateway', 'route-data') when serializing to
D-Bus, for backward compatibility. When deserializing, they will fill
in the 'addresses' and 'routes' properties from the new-style data if
it is present (ignoring the old-style data), or from the old-style
data if the new-style isn't present.
The daemon-side NMIP4Config and NMIP6Config always emit changes for
both 'Addresses'/'Routes' and 'AddressData'/'RouteData'. The
libnm-side classes initially listen for changes on both properties,
but start ignoring the 'Addresses' and 'Routes' properties once they
know the daemon is also providing 'AddressData' and 'RouteData'.
2014-10-21 08:33:18 -04:00
|
|
|
}
|
|
|
|
|
|
2016-10-02 18:22:50 +02:00
|
|
|
/*****************************************************************************/
|
2015-02-22 20:15:52 +01:00
|
|
|
|
2017-11-18 17:17:24 +01:00
|
|
|
static void
|
|
|
|
|
_string_append_tc_handle(GString *string, guint32 handle)
|
|
|
|
|
{
|
|
|
|
|
g_string_append_printf(string, "%x:", TC_H_MAJ(handle) >> 16);
|
|
|
|
|
if (TC_H_MIN(handle) != TC_H_UNSPEC)
|
|
|
|
|
g_string_append_printf(string, "%x", TC_H_MIN(handle));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* _nm_utils_string_append_tc_parent:
|
|
|
|
|
* @string: the string to write the parent handle to
|
|
|
|
|
* @prefix: optional prefix for the numeric handle
|
|
|
|
|
* @parent: the parent handle
|
|
|
|
|
*
|
|
|
|
|
* This is used to either write out the parent handle to the tc qdisc string
|
|
|
|
|
* or to pretty-format (use symbolic name for root) the key in keyfile.
|
2020-07-04 11:37:01 +03:00
|
|
|
* The presence of prefix determines which one is the case.
|
2017-11-18 17:17:24 +01:00
|
|
|
*
|
2018-09-15 07:20:54 -04:00
|
|
|
* Private API due to general ugliness and overall uselessness for anything
|
2017-11-18 17:17:24 +01:00
|
|
|
* sensible.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
_nm_utils_string_append_tc_parent(GString *string, const char *prefix, guint32 parent)
|
|
|
|
|
{
|
|
|
|
|
if (parent == TC_H_ROOT) {
|
|
|
|
|
g_string_append(string, "root");
|
|
|
|
|
} else {
|
|
|
|
|
if (prefix) {
|
|
|
|
|
if (parent == TC_H_INGRESS)
|
|
|
|
|
return;
|
|
|
|
|
g_string_append_printf(string, "%s ", prefix);
|
|
|
|
|
}
|
|
|
|
|
_string_append_tc_handle(string, parent);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (prefix)
|
|
|
|
|
g_string_append_c(string, ' ');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* _nm_utils_parse_tc_handle:
|
|
|
|
|
* @str: the string representation of a qdisc handle
|
|
|
|
|
* @error: location of the error
|
|
|
|
|
*
|
|
|
|
|
* Parses tc style handle number into a numeric representation.
|
|
|
|
|
* Don't use this, use nm_utils_tc_qdisc_from_str() instead.
|
|
|
|
|
*/
|
|
|
|
|
guint32
|
|
|
|
|
_nm_utils_parse_tc_handle(const char *str, GError **error)
|
|
|
|
|
{
|
libnm: cleanup _nm_utils_parse_tc_handle()
- g_ascii_strtoll() accepts leading spaces, but it leaves
the end pointer at the first space after the digit. That means,
we accepted "1: 0" but not "1 :0". We should either consistently
accept spaces around the digits/colon or reject it.
- g_ascii_strtoll() accepts "\v" as a space (just like `man 3 isspace`
comments that "\v" is a space in C and POSIX locale.
For some reasons (unknown to me) g_ascii_isspace() does not treat
"\v" as space. And neither does NM_ASCII_SPACES and
nm_str_skip_leading_spaces().
We should be consistent about what we consider spaces and what not.
It's already odd to accept '\n' as spaces here, but well, lets do
it for the sake of consistency (so that it matches with our
understanding of ASCII spaces, albeit not POSIX's).
- don't use bogus error domains in "g_set_error (error, 1, 0, ..."
That is a bug and we have NM_UTILS_ERROR exactly for error instances
with unspecified domain and code.
- as before, accept a trailing ":" with omitted minor number.
- reject all unexpected characters. strtoll() accepts '+' / '-'
and a "0x" prefix of the numbers (and leading POSIX spaces). Be
strict here and only accepts NM_ASCII_SPACES, ':', and hexdigits.
In particular, don't accept the "0x" prefix.
This parsing would be significantly simpler to implement, if we could
just strdup() the string, split the string at the colon delimiter and
use _nm_utils_ascii_str_to_int64() which gets leading/trailing spaces
right. But let's save the "overhead" of an additional alloc.
2019-05-01 10:27:32 +02:00
|
|
|
gint64 maj;
|
|
|
|
|
gint64 min = 0;
|
|
|
|
|
const char *sep;
|
|
|
|
|
|
|
|
|
|
nm_assert(str);
|
|
|
|
|
|
2020-04-01 12:30:20 +02:00
|
|
|
maj = nm_g_ascii_strtoll(str, (char **) &sep, 0x10);
|
libnm: cleanup _nm_utils_parse_tc_handle()
- g_ascii_strtoll() accepts leading spaces, but it leaves
the end pointer at the first space after the digit. That means,
we accepted "1: 0" but not "1 :0". We should either consistently
accept spaces around the digits/colon or reject it.
- g_ascii_strtoll() accepts "\v" as a space (just like `man 3 isspace`
comments that "\v" is a space in C and POSIX locale.
For some reasons (unknown to me) g_ascii_isspace() does not treat
"\v" as space. And neither does NM_ASCII_SPACES and
nm_str_skip_leading_spaces().
We should be consistent about what we consider spaces and what not.
It's already odd to accept '\n' as spaces here, but well, lets do
it for the sake of consistency (so that it matches with our
understanding of ASCII spaces, albeit not POSIX's).
- don't use bogus error domains in "g_set_error (error, 1, 0, ..."
That is a bug and we have NM_UTILS_ERROR exactly for error instances
with unspecified domain and code.
- as before, accept a trailing ":" with omitted minor number.
- reject all unexpected characters. strtoll() accepts '+' / '-'
and a "0x" prefix of the numbers (and leading POSIX spaces). Be
strict here and only accepts NM_ASCII_SPACES, ':', and hexdigits.
In particular, don't accept the "0x" prefix.
This parsing would be significantly simpler to implement, if we could
just strdup() the string, split the string at the colon delimiter and
use _nm_utils_ascii_str_to_int64() which gets leading/trailing spaces
right. But let's save the "overhead" of an additional alloc.
2019-05-01 10:27:32 +02:00
|
|
|
if (sep == str)
|
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
|
|
sep = nm_str_skip_leading_spaces(sep);
|
|
|
|
|
|
|
|
|
|
if (sep[0] == ':') {
|
|
|
|
|
const char *str2 = &sep[1];
|
|
|
|
|
|
2020-04-01 12:30:20 +02:00
|
|
|
min = nm_g_ascii_strtoll(str2, (char **) &sep, 0x10);
|
libnm: cleanup _nm_utils_parse_tc_handle()
- g_ascii_strtoll() accepts leading spaces, but it leaves
the end pointer at the first space after the digit. That means,
we accepted "1: 0" but not "1 :0". We should either consistently
accept spaces around the digits/colon or reject it.
- g_ascii_strtoll() accepts "\v" as a space (just like `man 3 isspace`
comments that "\v" is a space in C and POSIX locale.
For some reasons (unknown to me) g_ascii_isspace() does not treat
"\v" as space. And neither does NM_ASCII_SPACES and
nm_str_skip_leading_spaces().
We should be consistent about what we consider spaces and what not.
It's already odd to accept '\n' as spaces here, but well, lets do
it for the sake of consistency (so that it matches with our
understanding of ASCII spaces, albeit not POSIX's).
- don't use bogus error domains in "g_set_error (error, 1, 0, ..."
That is a bug and we have NM_UTILS_ERROR exactly for error instances
with unspecified domain and code.
- as before, accept a trailing ":" with omitted minor number.
- reject all unexpected characters. strtoll() accepts '+' / '-'
and a "0x" prefix of the numbers (and leading POSIX spaces). Be
strict here and only accepts NM_ASCII_SPACES, ':', and hexdigits.
In particular, don't accept the "0x" prefix.
This parsing would be significantly simpler to implement, if we could
just strdup() the string, split the string at the colon delimiter and
use _nm_utils_ascii_str_to_int64() which gets leading/trailing spaces
right. But let's save the "overhead" of an additional alloc.
2019-05-01 10:27:32 +02:00
|
|
|
sep = nm_str_skip_leading_spaces(sep);
|
|
|
|
|
if (sep[0] != '\0')
|
|
|
|
|
goto fail;
|
|
|
|
|
} else if (sep[0] != '\0')
|
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
|
|
if (maj <= 0 || maj > 0xffff || min < 0 || min > 0xffff
|
|
|
|
|
|| !NM_STRCHAR_ALL(str, ch, (g_ascii_isxdigit(ch) || ch == ':' || g_ascii_isspace(ch)))) {
|
|
|
|
|
goto fail;
|
2017-11-18 17:17:24 +01:00
|
|
|
}
|
|
|
|
|
|
libnm: cleanup _nm_utils_parse_tc_handle()
- g_ascii_strtoll() accepts leading spaces, but it leaves
the end pointer at the first space after the digit. That means,
we accepted "1: 0" but not "1 :0". We should either consistently
accept spaces around the digits/colon or reject it.
- g_ascii_strtoll() accepts "\v" as a space (just like `man 3 isspace`
comments that "\v" is a space in C and POSIX locale.
For some reasons (unknown to me) g_ascii_isspace() does not treat
"\v" as space. And neither does NM_ASCII_SPACES and
nm_str_skip_leading_spaces().
We should be consistent about what we consider spaces and what not.
It's already odd to accept '\n' as spaces here, but well, lets do
it for the sake of consistency (so that it matches with our
understanding of ASCII spaces, albeit not POSIX's).
- don't use bogus error domains in "g_set_error (error, 1, 0, ..."
That is a bug and we have NM_UTILS_ERROR exactly for error instances
with unspecified domain and code.
- as before, accept a trailing ":" with omitted minor number.
- reject all unexpected characters. strtoll() accepts '+' / '-'
and a "0x" prefix of the numbers (and leading POSIX spaces). Be
strict here and only accepts NM_ASCII_SPACES, ':', and hexdigits.
In particular, don't accept the "0x" prefix.
This parsing would be significantly simpler to implement, if we could
just strdup() the string, split the string at the colon delimiter and
use _nm_utils_ascii_str_to_int64() which gets leading/trailing spaces
right. But let's save the "overhead" of an additional alloc.
2019-05-01 10:27:32 +02:00
|
|
|
return TC_H_MAKE(((guint32) maj) << 16, (guint32) min);
|
|
|
|
|
fail:
|
|
|
|
|
nm_utils_error_set(error, NM_UTILS_ERROR_UNKNOWN, _("'%s' is not a valid handle."), str);
|
|
|
|
|
return TC_H_UNSPEC;
|
2017-11-18 17:17:24 +01:00
|
|
|
}
|
|
|
|
|
|
2019-05-01 11:56:29 +02:00
|
|
|
static const NMVariantAttributeSpec *const tc_object_attribute_spec[] = {
|
2020-05-13 13:25:17 +02:00
|
|
|
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE("root", G_VARIANT_TYPE_BOOLEAN, .no_value = TRUE, ),
|
|
|
|
|
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE("parent", G_VARIANT_TYPE_STRING, ),
|
|
|
|
|
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE("handle", G_VARIANT_TYPE_STRING, ),
|
|
|
|
|
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE("kind", G_VARIANT_TYPE_STRING, .no_value = TRUE, ),
|
|
|
|
|
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE("",
|
|
|
|
|
G_VARIANT_TYPE_STRING,
|
|
|
|
|
.no_value = TRUE,
|
|
|
|
|
.consumes_rest = TRUE, ),
|
2017-11-18 17:17:24 +01:00
|
|
|
NULL,
|
|
|
|
|
};
|
|
|
|
|
|
2020-04-30 09:19:55 +02:00
|
|
|
static const NMVariantAttributeSpec *const tc_qdisc_sfq_spec[] = {
|
|
|
|
|
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE("quantum", G_VARIANT_TYPE_UINT32, ),
|
|
|
|
|
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE("perturb", G_VARIANT_TYPE_INT32, ),
|
|
|
|
|
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE("limit", G_VARIANT_TYPE_UINT32, ),
|
|
|
|
|
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE("divisor", G_VARIANT_TYPE_UINT32, ),
|
|
|
|
|
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE("flows", G_VARIANT_TYPE_UINT32, ),
|
|
|
|
|
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE("depth", G_VARIANT_TYPE_UINT32, ),
|
|
|
|
|
NULL,
|
|
|
|
|
};
|
|
|
|
|
|
2020-05-08 19:11:44 +02:00
|
|
|
static const NMVariantAttributeSpec *const tc_qdisc_tbf_spec[] = {
|
|
|
|
|
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE("rate", G_VARIANT_TYPE_UINT64, ),
|
|
|
|
|
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE("burst", G_VARIANT_TYPE_UINT32, ),
|
|
|
|
|
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE("limit", G_VARIANT_TYPE_UINT32, ),
|
|
|
|
|
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE("latency", G_VARIANT_TYPE_UINT32, ),
|
|
|
|
|
NULL,
|
|
|
|
|
};
|
|
|
|
|
|
2019-05-01 11:56:29 +02:00
|
|
|
static const NMVariantAttributeSpec *const tc_qdisc_fq_codel_spec[] = {
|
|
|
|
|
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE("limit", G_VARIANT_TYPE_UINT32, ),
|
|
|
|
|
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE("flows", G_VARIANT_TYPE_UINT32, ),
|
|
|
|
|
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE("target", G_VARIANT_TYPE_UINT32, ),
|
|
|
|
|
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE("interval", G_VARIANT_TYPE_UINT32, ),
|
|
|
|
|
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE("quantum", G_VARIANT_TYPE_UINT32, ),
|
platform: fix handling of default value for TCA_FQ_CODEL_CE_THRESHOLD
iproute2 uses the special value ~0u to indicate not to set
TCA_FQ_CODEL_CE_THRESHOLD in RTM_NEWQDISC. When not explicitly
setting the value, kernel treats the threshold as disabled.
However note that 0xFFFFFFFFu is not an invalid threshold (as far as
kernel is concerned). Thus, we should not use that as value to indicate
that the value is unset. Note that iproute2 uses the special value ~0u
only internally thereby making it impossible to set the threshold to
0xFFFFFFFFu). But kernel does not have this limitation.
Maybe the cleanest way would be to add another field to NMPlatformQDisc:
guint32 ce_threshold;
bool ce_threshold_set:1;
that indicates whether the threshold is enable or not.
But note that kernel does:
static void codel_params_init(struct codel_params *params)
{
...
params->ce_threshold = CODEL_DISABLED_THRESHOLD;
static int fq_codel_change(struct Qdisc *sch, struct nlattr *opt,
struct netlink_ext_ack *extack)
{
...
if (tb[TCA_FQ_CODEL_CE_THRESHOLD]) {
u64 val = nla_get_u32(tb[TCA_FQ_CODEL_CE_THRESHOLD]);
q->cparams.ce_threshold = (val * NSEC_PER_USEC) >> CODEL_SHIFT;
}
static int fq_codel_dump(struct Qdisc *sch, struct sk_buff *skb)
{
...
if (q->cparams.ce_threshold != CODEL_DISABLED_THRESHOLD &&
nla_put_u32(skb, TCA_FQ_CODEL_CE_THRESHOLD,
codel_time_to_us(q->cparams.ce_threshold)))
goto nla_put_failure;
This means, kernel internally uses the special value 0x83126E97u to indicate
that the threshold is disabled (WTF). That is because
(((guint64) 0x83126E97u) * NSEC_PER_USEC) >> CODEL_SHIFT == CODEL_DISABLED_THRESHOLD
So in kernel API this value is reserved (and has a special meaning
to indicate that the threshold is disabled). So, instead of adding a
ce_threshold_set flag, use the same value that kernel anyway uses.
2019-05-01 09:19:59 +02:00
|
|
|
|
|
|
|
|
/* 0x83126E97u is not a valid value (it means "disabled"). We should reject that
|
|
|
|
|
* value. Or alternatively, reject all values >= MAX_INT(32). */
|
2019-05-01 11:56:29 +02:00
|
|
|
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE("ce_threshold", G_VARIANT_TYPE_UINT32, ),
|
2019-05-01 08:43:31 +02:00
|
|
|
|
|
|
|
|
/* kernel clamps the value at 2^31. Possibly such values should be rejected from configuration
|
|
|
|
|
* as they cannot be configured. Leaving the attribute unspecified causes kernel to choose
|
|
|
|
|
* a default (currently 32MB). */
|
2019-05-01 12:56:46 +02:00
|
|
|
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE("memory_limit", G_VARIANT_TYPE_UINT32, ),
|
2019-05-01 08:43:31 +02:00
|
|
|
|
2019-05-01 11:56:29 +02:00
|
|
|
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE("ecn", G_VARIANT_TYPE_BOOLEAN, .no_value = TRUE, ),
|
2019-04-09 13:42:52 +02:00
|
|
|
NULL,
|
|
|
|
|
};
|
|
|
|
|
|
2019-04-09 09:10:43 +02:00
|
|
|
typedef struct {
|
2021-11-09 13:28:54 +01:00
|
|
|
const char *kind;
|
2019-05-01 11:56:29 +02:00
|
|
|
const NMVariantAttributeSpec *const *attrs;
|
2019-04-09 09:10:43 +02:00
|
|
|
} NMQdiscAttributeSpec;
|
|
|
|
|
|
|
|
|
|
static const NMQdiscAttributeSpec *const tc_qdisc_attribute_spec[] = {
|
2024-10-04 10:45:56 +02:00
|
|
|
&(const NMQdiscAttributeSpec) {"fq_codel", tc_qdisc_fq_codel_spec},
|
|
|
|
|
&(const NMQdiscAttributeSpec) {"sfq", tc_qdisc_sfq_spec},
|
|
|
|
|
&(const NMQdiscAttributeSpec) {"tbf", tc_qdisc_tbf_spec},
|
2019-04-09 09:10:43 +02:00
|
|
|
NULL,
|
|
|
|
|
};
|
|
|
|
|
|
2017-11-18 17:17:24 +01:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* _nm_utils_string_append_tc_qdisc_rest:
|
|
|
|
|
* @string: the string to write the formatted qdisc to
|
|
|
|
|
* @qdisc: the %NMTCQdisc
|
|
|
|
|
*
|
|
|
|
|
* This formats the rest of the qdisc string but the parent. Useful to format
|
|
|
|
|
* the keyfile value and nowhere else.
|
|
|
|
|
* Use nm_utils_tc_qdisc_to_str() that also includes the parent instead.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
_nm_utils_string_append_tc_qdisc_rest(GString *string, NMTCQdisc *qdisc)
|
|
|
|
|
{
|
|
|
|
|
guint32 handle = nm_tc_qdisc_get_handle(qdisc);
|
2021-11-09 13:28:54 +01:00
|
|
|
const char *kind = nm_tc_qdisc_get_kind(qdisc);
|
2019-04-09 09:10:43 +02:00
|
|
|
gs_free char *str = NULL;
|
2017-11-18 17:17:24 +01:00
|
|
|
|
2020-07-09 05:32:07 +02:00
|
|
|
if (handle != TC_H_UNSPEC && !NM_IN_STRSET(kind, "ingress", "clsact")) {
|
2017-11-18 17:17:24 +01:00
|
|
|
g_string_append(string, "handle ");
|
|
|
|
|
_string_append_tc_handle(string, handle);
|
|
|
|
|
g_string_append_c(string, ' ');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_string_append(string, kind);
|
2019-04-09 09:10:43 +02:00
|
|
|
|
2019-04-19 11:51:42 +02:00
|
|
|
str = nm_utils_format_variant_attributes(_nm_tc_qdisc_get_attributes(qdisc), ' ', ' ');
|
|
|
|
|
if (str) {
|
2019-04-09 09:10:43 +02:00
|
|
|
g_string_append_c(string, ' ');
|
|
|
|
|
g_string_append(string, str);
|
|
|
|
|
}
|
2017-11-18 17:17:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_utils_tc_qdisc_to_str:
|
|
|
|
|
* @qdisc: the %NMTCQdisc
|
|
|
|
|
* @error: location of the error
|
|
|
|
|
*
|
|
|
|
|
* Turns the %NMTCQdisc into a tc style string representation of the queueing
|
|
|
|
|
* discipline.
|
|
|
|
|
*
|
|
|
|
|
* Returns: formatted string or %NULL
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
*/
|
|
|
|
|
char *
|
|
|
|
|
nm_utils_tc_qdisc_to_str(NMTCQdisc *qdisc, GError **error)
|
|
|
|
|
{
|
|
|
|
|
GString *string;
|
|
|
|
|
|
|
|
|
|
string = g_string_sized_new(60);
|
|
|
|
|
|
|
|
|
|
_nm_utils_string_append_tc_parent(string, "parent", nm_tc_qdisc_get_parent(qdisc));
|
|
|
|
|
_nm_utils_string_append_tc_qdisc_rest(string, qdisc);
|
|
|
|
|
|
|
|
|
|
return g_string_free(string, FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
_tc_read_common_opts(const char *str,
|
2021-11-09 13:28:54 +01:00
|
|
|
guint32 *handle,
|
|
|
|
|
guint32 *parent,
|
|
|
|
|
char **kind,
|
|
|
|
|
char **rest,
|
|
|
|
|
GError **error)
|
2017-11-18 17:17:24 +01:00
|
|
|
{
|
|
|
|
|
gs_unref_hashtable GHashTable *ht = NULL;
|
2021-11-09 13:28:54 +01:00
|
|
|
GVariant *variant;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-09-14 17:24:46 +02:00
|
|
|
ht = nm_utils_parse_variant_attributes(str, ' ', ' ', FALSE, tc_object_attribute_spec, error);
|
2017-11-18 17:17:24 +01:00
|
|
|
if (!ht)
|
|
|
|
|
return FALSE;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-18 17:17:24 +01:00
|
|
|
if (g_hash_table_contains(ht, "root"))
|
|
|
|
|
*parent = TC_H_ROOT;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-18 17:17:24 +01:00
|
|
|
variant = g_hash_table_lookup(ht, "parent");
|
|
|
|
|
if (variant) {
|
|
|
|
|
if (*parent != TC_H_UNSPEC) {
|
|
|
|
|
g_set_error(error,
|
|
|
|
|
1,
|
|
|
|
|
0,
|
|
|
|
|
_("'%s' unexpected: parent already specified."),
|
|
|
|
|
g_variant_get_string(variant, NULL));
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
*parent = _nm_utils_parse_tc_handle(g_variant_get_string(variant, NULL), error);
|
|
|
|
|
if (*parent == TC_H_UNSPEC)
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-18 17:17:24 +01:00
|
|
|
variant = g_hash_table_lookup(ht, "handle");
|
|
|
|
|
if (variant) {
|
|
|
|
|
*handle = _nm_utils_parse_tc_handle(g_variant_get_string(variant, NULL), error);
|
|
|
|
|
if (*handle == TC_H_UNSPEC)
|
|
|
|
|
return FALSE;
|
|
|
|
|
if (TC_H_MIN(*handle)) {
|
|
|
|
|
g_set_error(error,
|
|
|
|
|
1,
|
|
|
|
|
0,
|
|
|
|
|
_("invalid handle: '%s'"),
|
|
|
|
|
g_variant_get_string(variant, NULL));
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-18 17:17:24 +01:00
|
|
|
variant = g_hash_table_lookup(ht, "kind");
|
|
|
|
|
if (variant) {
|
|
|
|
|
*kind = g_variant_dup_string(variant, NULL);
|
2020-07-09 05:32:07 +02:00
|
|
|
if (NM_IN_STRSET(*kind, "ingress", "clsact")) {
|
2017-11-18 17:17:24 +01:00
|
|
|
if (*parent == TC_H_UNSPEC)
|
|
|
|
|
*parent = TC_H_INGRESS;
|
|
|
|
|
if (*handle == TC_H_UNSPEC)
|
|
|
|
|
*handle = TC_H_MAKE(TC_H_INGRESS, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-18 17:17:24 +01:00
|
|
|
if (*parent == TC_H_UNSPEC) {
|
|
|
|
|
if (*kind) {
|
|
|
|
|
g_free(*kind);
|
|
|
|
|
*kind = NULL;
|
|
|
|
|
}
|
|
|
|
|
g_set_error_literal(error, 1, 0, _("parent not specified."));
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-18 17:17:24 +01:00
|
|
|
variant = g_hash_table_lookup(ht, "");
|
|
|
|
|
if (variant)
|
|
|
|
|
*rest = g_variant_dup_string(variant, NULL);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-18 17:17:24 +01:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_utils_tc_qdisc_from_str:
|
|
|
|
|
* @str: the string representation of a qdisc
|
|
|
|
|
* @error: location of the error
|
|
|
|
|
*
|
2019-03-19 15:04:54 +01:00
|
|
|
* Parses the tc style string qdisc representation of the queueing
|
2017-11-18 17:17:24 +01:00
|
|
|
* discipline to a %NMTCQdisc instance. Supports a subset of the tc language.
|
|
|
|
|
*
|
|
|
|
|
* Returns: the %NMTCQdisc or %NULL
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
*/
|
|
|
|
|
NMTCQdisc *
|
|
|
|
|
nm_utils_tc_qdisc_from_str(const char *str, GError **error)
|
|
|
|
|
{
|
2021-11-09 13:28:54 +01:00
|
|
|
guint32 handle = TC_H_UNSPEC;
|
|
|
|
|
guint32 parent = TC_H_UNSPEC;
|
|
|
|
|
gs_free char *kind = NULL;
|
|
|
|
|
gs_free char *rest = NULL;
|
|
|
|
|
NMTCQdisc *qdisc = NULL;
|
2019-04-09 09:10:43 +02:00
|
|
|
gs_unref_hashtable GHashTable *options = NULL;
|
|
|
|
|
GHashTableIter iter;
|
|
|
|
|
gpointer key, value;
|
|
|
|
|
guint i;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-18 17:17:24 +01:00
|
|
|
nm_assert(str);
|
|
|
|
|
nm_assert(!error || !*error);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-18 17:17:24 +01:00
|
|
|
if (!_tc_read_common_opts(str, &handle, &parent, &kind, &rest, error))
|
|
|
|
|
return NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-04-09 09:10:43 +02:00
|
|
|
for (i = 0; rest && tc_qdisc_attribute_spec[i]; i++) {
|
2020-06-21 21:48:59 +02:00
|
|
|
if (nm_streq(tc_qdisc_attribute_spec[i]->kind, kind)) {
|
2019-04-09 09:10:43 +02:00
|
|
|
options = nm_utils_parse_variant_attributes(rest,
|
|
|
|
|
' ',
|
|
|
|
|
' ',
|
|
|
|
|
FALSE,
|
|
|
|
|
tc_qdisc_attribute_spec[i]->attrs,
|
|
|
|
|
error);
|
|
|
|
|
if (!options)
|
|
|
|
|
return NULL;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
}
|
2020-04-27 12:54:14 +02:00
|
|
|
nm_clear_g_free(&rest);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-04-09 09:10:43 +02:00
|
|
|
if (options) {
|
|
|
|
|
value = g_hash_table_lookup(options, "");
|
|
|
|
|
if (value)
|
|
|
|
|
rest = g_variant_dup_string(value, NULL);
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-18 17:17:24 +01:00
|
|
|
if (rest) {
|
|
|
|
|
g_set_error(error, 1, 0, _("unsupported qdisc option: '%s'."), rest);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-18 17:17:24 +01:00
|
|
|
qdisc = nm_tc_qdisc_new(kind, parent, error);
|
|
|
|
|
if (!qdisc)
|
|
|
|
|
return NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-18 17:17:24 +01:00
|
|
|
nm_tc_qdisc_set_handle(qdisc, handle);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-04-09 09:10:43 +02:00
|
|
|
if (options) {
|
|
|
|
|
g_hash_table_iter_init(&iter, options);
|
|
|
|
|
while (g_hash_table_iter_next(&iter, &key, &value))
|
|
|
|
|
nm_tc_qdisc_set_attribute(qdisc, key, g_variant_ref_sink(value));
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-18 17:17:24 +01:00
|
|
|
return qdisc;
|
|
|
|
|
}
|
2019-04-09 09:10:43 +02:00
|
|
|
|
2017-11-28 09:22:49 +01:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-05-01 11:56:29 +02:00
|
|
|
static const NMVariantAttributeSpec *const tc_action_simple_attribute_spec[] = {
|
|
|
|
|
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE("sdata", G_VARIANT_TYPE_BYTESTRING, ),
|
2017-11-28 09:22:49 +01:00
|
|
|
NULL,
|
|
|
|
|
};
|
|
|
|
|
|
2019-05-01 11:56:29 +02:00
|
|
|
static const NMVariantAttributeSpec *const tc_action_mirred_attribute_spec[] = {
|
2020-05-13 13:25:17 +02:00
|
|
|
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE("egress", G_VARIANT_TYPE_BOOLEAN, .no_value = TRUE, ),
|
|
|
|
|
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE("ingress", G_VARIANT_TYPE_BOOLEAN, .no_value = TRUE, ),
|
|
|
|
|
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE("mirror", G_VARIANT_TYPE_BOOLEAN, .no_value = TRUE, ),
|
|
|
|
|
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE("redirect", G_VARIANT_TYPE_BOOLEAN, .no_value = TRUE, ),
|
2020-05-11 15:44:10 +02:00
|
|
|
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE("dev", G_VARIANT_TYPE_STRING, ),
|
2019-04-09 16:23:39 +02:00
|
|
|
NULL,
|
|
|
|
|
};
|
|
|
|
|
|
2019-05-01 11:56:29 +02:00
|
|
|
static const NMVariantAttributeSpec *const tc_action_attribute_spec[] = {
|
2020-05-13 13:25:17 +02:00
|
|
|
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE("kind", G_VARIANT_TYPE_STRING, .no_value = TRUE, ),
|
|
|
|
|
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE("",
|
|
|
|
|
G_VARIANT_TYPE_STRING,
|
|
|
|
|
.no_value = TRUE,
|
|
|
|
|
.consumes_rest = TRUE, ),
|
2017-11-28 09:22:49 +01:00
|
|
|
NULL,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
_string_append_tc_action(GString *string, NMTCAction *action, GError **error)
|
|
|
|
|
{
|
2021-11-09 13:28:54 +01:00
|
|
|
const char *kind = nm_tc_action_get_kind(action);
|
|
|
|
|
gs_free char *str = NULL;
|
2020-06-18 11:39:02 +02:00
|
|
|
const NMVariantAttributeSpec *const *attrs;
|
|
|
|
|
|
|
|
|
|
if (nm_streq(kind, "simple"))
|
|
|
|
|
attrs = tc_action_simple_attribute_spec;
|
|
|
|
|
else if (nm_streq(kind, "mirred"))
|
|
|
|
|
attrs = tc_action_mirred_attribute_spec;
|
|
|
|
|
else
|
|
|
|
|
attrs = NULL;
|
|
|
|
|
|
2017-11-28 09:22:49 +01:00
|
|
|
g_string_append(string, kind);
|
|
|
|
|
|
2020-09-28 16:03:33 +02:00
|
|
|
str =
|
2020-06-18 11:39:02 +02:00
|
|
|
_nm_utils_format_variant_attributes(_nm_tc_action_get_attributes(action), attrs, ' ', ' ');
|
2017-11-28 09:22:49 +01:00
|
|
|
if (str) {
|
|
|
|
|
g_string_append_c(string, ' ');
|
|
|
|
|
g_string_append(string, str);
|
2020-09-28 16:03:33 +02:00
|
|
|
}
|
2017-11-28 09:22:49 +01:00
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_utils_tc_action_to_str:
|
|
|
|
|
* @action: the %NMTCAction
|
|
|
|
|
* @error: location of the error
|
|
|
|
|
*
|
|
|
|
|
* Turns the %NMTCAction into a tc style string representation of the queueing
|
|
|
|
|
* discipline.
|
|
|
|
|
*
|
|
|
|
|
* Returns: formatted string or %NULL
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
*/
|
|
|
|
|
char *
|
|
|
|
|
nm_utils_tc_action_to_str(NMTCAction *action, GError **error)
|
|
|
|
|
{
|
|
|
|
|
GString *string;
|
|
|
|
|
|
|
|
|
|
string = g_string_sized_new(60);
|
|
|
|
|
if (!_string_append_tc_action(string, action, error)) {
|
|
|
|
|
g_string_free(string, TRUE);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return g_string_free(string, FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_utils_tc_action_from_str:
|
|
|
|
|
* @str: the string representation of a action
|
|
|
|
|
* @error: location of the error
|
|
|
|
|
*
|
2019-03-19 15:04:54 +01:00
|
|
|
* Parses the tc style string action representation of the queueing
|
2017-11-28 09:22:49 +01:00
|
|
|
* discipline to a %NMTCAction instance. Supports a subset of the tc language.
|
|
|
|
|
*
|
|
|
|
|
* Returns: the %NMTCAction or %NULL
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
*/
|
|
|
|
|
NMTCAction *
|
|
|
|
|
nm_utils_tc_action_from_str(const char *str, GError **error)
|
|
|
|
|
{
|
2021-11-09 13:28:54 +01:00
|
|
|
const char *kind = NULL;
|
|
|
|
|
const char *rest = NULL;
|
|
|
|
|
nm_auto_unref_tc_action NMTCAction *action = NULL;
|
|
|
|
|
gs_unref_hashtable GHashTable *ht = NULL;
|
|
|
|
|
gs_unref_hashtable GHashTable *options = NULL;
|
|
|
|
|
GVariant *variant;
|
2019-05-01 11:56:29 +02:00
|
|
|
const NMVariantAttributeSpec *const *attrs;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-28 09:22:49 +01:00
|
|
|
nm_assert(str);
|
|
|
|
|
nm_assert(!error || !*error);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-10 12:20:38 +01:00
|
|
|
ht = nm_utils_parse_variant_attributes(str, ' ', ' ', FALSE, tc_action_attribute_spec, error);
|
2017-11-28 09:22:49 +01:00
|
|
|
if (!ht)
|
|
|
|
|
return FALSE;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-28 09:22:49 +01:00
|
|
|
variant = g_hash_table_lookup(ht, "kind");
|
|
|
|
|
if (variant) {
|
|
|
|
|
kind = g_variant_get_string(variant, NULL);
|
|
|
|
|
} else {
|
|
|
|
|
g_set_error_literal(error, 1, 0, _("action name missing."));
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-28 09:22:49 +01:00
|
|
|
kind = g_variant_get_string(variant, NULL);
|
2020-06-21 21:48:59 +02:00
|
|
|
if (nm_streq(kind, "simple"))
|
2017-11-28 09:22:49 +01:00
|
|
|
attrs = tc_action_simple_attribute_spec;
|
2020-06-21 21:48:59 +02:00
|
|
|
else if (nm_streq(kind, "mirred"))
|
2019-04-09 16:23:39 +02:00
|
|
|
attrs = tc_action_mirred_attribute_spec;
|
2017-11-28 09:22:49 +01:00
|
|
|
else
|
|
|
|
|
attrs = NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-28 09:22:49 +01:00
|
|
|
variant = g_hash_table_lookup(ht, "");
|
|
|
|
|
if (variant)
|
|
|
|
|
rest = g_variant_get_string(variant, NULL);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-28 09:22:49 +01:00
|
|
|
action = nm_tc_action_new(kind, error);
|
|
|
|
|
if (!action)
|
|
|
|
|
return NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-28 09:22:49 +01:00
|
|
|
if (rest) {
|
|
|
|
|
GHashTableIter iter;
|
|
|
|
|
gpointer key, value;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-28 09:22:49 +01:00
|
|
|
if (!attrs) {
|
|
|
|
|
g_set_error(error, 1, 0, _("unsupported action option: '%s'."), rest);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-10 12:20:38 +01:00
|
|
|
options = nm_utils_parse_variant_attributes(rest, ' ', ' ', FALSE, attrs, error);
|
2021-05-06 18:26:30 +02:00
|
|
|
if (!options)
|
2017-11-28 09:22:49 +01:00
|
|
|
return NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-28 09:22:49 +01:00
|
|
|
g_hash_table_iter_init(&iter, options);
|
|
|
|
|
while (g_hash_table_iter_next(&iter, &key, &value))
|
|
|
|
|
nm_tc_action_set_attribute(action, key, g_variant_ref_sink(value));
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2021-05-06 18:26:30 +02:00
|
|
|
return g_steal_pointer(&action);
|
2017-11-28 09:22:49 +01:00
|
|
|
}
|
2017-11-18 17:17:24 +01:00
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2017-11-28 09:26:14 +01:00
|
|
|
/**
|
|
|
|
|
* _nm_utils_string_append_tc_tfilter_rest:
|
|
|
|
|
* @string: the string to write the formatted tfilter to
|
|
|
|
|
* @tfilter: the %NMTCTfilter
|
|
|
|
|
*
|
|
|
|
|
* This formats the rest of the tfilter string but the parent. Useful to format
|
|
|
|
|
* the keyfile value and nowhere else.
|
|
|
|
|
* Use nm_utils_tc_tfilter_to_str() that also includes the parent instead.
|
|
|
|
|
*/
|
|
|
|
|
gboolean
|
|
|
|
|
_nm_utils_string_append_tc_tfilter_rest(GString *string, NMTCTfilter *tfilter, GError **error)
|
|
|
|
|
{
|
|
|
|
|
guint32 handle = nm_tc_tfilter_get_handle(tfilter);
|
|
|
|
|
const char *kind = nm_tc_tfilter_get_kind(tfilter);
|
|
|
|
|
NMTCAction *action;
|
|
|
|
|
|
|
|
|
|
if (handle != TC_H_UNSPEC) {
|
|
|
|
|
g_string_append(string, "handle ");
|
|
|
|
|
_string_append_tc_handle(string, handle);
|
|
|
|
|
g_string_append_c(string, ' ');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_string_append(string, kind);
|
|
|
|
|
|
|
|
|
|
action = nm_tc_tfilter_get_action(tfilter);
|
|
|
|
|
if (action) {
|
|
|
|
|
g_string_append(string, " action ");
|
|
|
|
|
if (!_string_append_tc_action(string, action, error))
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_utils_tc_tfilter_to_str:
|
|
|
|
|
* @tfilter: the %NMTCTfilter
|
|
|
|
|
* @error: location of the error
|
|
|
|
|
*
|
|
|
|
|
* Turns the %NMTCTfilter into a tc style string representation of the queueing
|
|
|
|
|
* discipline.
|
|
|
|
|
*
|
|
|
|
|
* Returns: formatted string or %NULL
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
*/
|
|
|
|
|
char *
|
|
|
|
|
nm_utils_tc_tfilter_to_str(NMTCTfilter *tfilter, GError **error)
|
|
|
|
|
{
|
|
|
|
|
GString *string;
|
|
|
|
|
|
|
|
|
|
string = g_string_sized_new(60);
|
|
|
|
|
|
|
|
|
|
_nm_utils_string_append_tc_parent(string, "parent", nm_tc_tfilter_get_parent(tfilter));
|
|
|
|
|
if (!_nm_utils_string_append_tc_tfilter_rest(string, tfilter, error)) {
|
|
|
|
|
g_string_free(string, TRUE);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return g_string_free(string, FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-01 11:56:29 +02:00
|
|
|
static const NMVariantAttributeSpec *const tc_tfilter_attribute_spec[] = {
|
2020-05-13 13:25:17 +02:00
|
|
|
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE("action", G_VARIANT_TYPE_BOOLEAN, .no_value = TRUE, ),
|
|
|
|
|
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE("",
|
|
|
|
|
G_VARIANT_TYPE_STRING,
|
|
|
|
|
.no_value = TRUE,
|
|
|
|
|
.consumes_rest = TRUE, ),
|
2017-11-28 09:26:14 +01:00
|
|
|
NULL,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_utils_tc_tfilter_from_str:
|
|
|
|
|
* @str: the string representation of a tfilter
|
|
|
|
|
* @error: location of the error
|
|
|
|
|
*
|
2019-03-19 15:04:54 +01:00
|
|
|
* Parses the tc style string tfilter representation of the queueing
|
2017-11-28 09:26:14 +01:00
|
|
|
* discipline to a %NMTCTfilter instance. Supports a subset of the tc language.
|
|
|
|
|
*
|
|
|
|
|
* Returns: the %NMTCTfilter or %NULL
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
*/
|
|
|
|
|
NMTCTfilter *
|
|
|
|
|
nm_utils_tc_tfilter_from_str(const char *str, GError **error)
|
|
|
|
|
{
|
2021-11-09 13:28:54 +01:00
|
|
|
guint32 handle = TC_H_UNSPEC;
|
|
|
|
|
guint32 parent = TC_H_UNSPEC;
|
|
|
|
|
gs_free char *kind = NULL;
|
|
|
|
|
gs_free char *rest = NULL;
|
2021-05-06 18:25:48 +02:00
|
|
|
nm_auto_unref_tc_action NMTCAction *action = NULL;
|
2021-11-09 13:28:54 +01:00
|
|
|
const char *extra_opts = NULL;
|
|
|
|
|
NMTCTfilter *tfilter = NULL;
|
|
|
|
|
gs_unref_hashtable GHashTable *ht = NULL;
|
|
|
|
|
GVariant *variant;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-28 09:26:14 +01:00
|
|
|
nm_assert(str);
|
|
|
|
|
nm_assert(!error || !*error);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-28 09:26:14 +01:00
|
|
|
if (!_tc_read_common_opts(str, &handle, &parent, &kind, &rest, error))
|
|
|
|
|
return NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-28 09:26:14 +01:00
|
|
|
if (rest) {
|
2018-09-14 17:24:46 +02:00
|
|
|
ht = nm_utils_parse_variant_attributes(rest,
|
|
|
|
|
' ',
|
|
|
|
|
' ',
|
|
|
|
|
FALSE,
|
|
|
|
|
tc_tfilter_attribute_spec,
|
|
|
|
|
error);
|
2017-11-28 09:26:14 +01:00
|
|
|
if (!ht)
|
|
|
|
|
return NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-28 09:26:14 +01:00
|
|
|
variant = g_hash_table_lookup(ht, "");
|
|
|
|
|
if (variant)
|
|
|
|
|
extra_opts = g_variant_get_string(variant, NULL);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-28 09:26:14 +01:00
|
|
|
if (g_hash_table_contains(ht, "action")) {
|
|
|
|
|
action = nm_utils_tc_action_from_str(extra_opts, error);
|
|
|
|
|
if (!action) {
|
|
|
|
|
g_prefix_error(error, _("invalid action: "));
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
g_set_error(error, 1, 0, _("unsupported tfilter option: '%s'."), rest);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-28 09:26:14 +01:00
|
|
|
tfilter = nm_tc_tfilter_new(kind, parent, error);
|
|
|
|
|
if (!tfilter)
|
|
|
|
|
return NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-28 09:26:14 +01:00
|
|
|
nm_tc_tfilter_set_handle(tfilter, handle);
|
2021-05-06 18:25:48 +02:00
|
|
|
if (action)
|
2017-11-28 09:26:14 +01:00
|
|
|
nm_tc_tfilter_set_action(tfilter, action);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-28 09:26:14 +01:00
|
|
|
return tfilter;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2018-05-25 12:05:24 +02:00
|
|
|
extern const NMVariantAttributeSpec *const _nm_sriov_vf_attribute_spec[];
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_utils_sriov_vf_to_str:
|
|
|
|
|
* @vf: the %NMSriovVF
|
|
|
|
|
* @omit_index: if %TRUE, the VF index will be omitted from output string
|
2023-03-01 01:21:38 +01:00
|
|
|
* @error: location to store the error on failure
|
2018-05-25 12:05:24 +02:00
|
|
|
*
|
|
|
|
|
* Converts a SR-IOV virtual function object to its string representation.
|
|
|
|
|
*
|
|
|
|
|
* Returns: a newly allocated string or %NULL on error
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.14
|
|
|
|
|
*/
|
|
|
|
|
char *
|
|
|
|
|
nm_utils_sriov_vf_to_str(const NMSriovVF *vf, gboolean omit_index, GError **error)
|
|
|
|
|
{
|
|
|
|
|
gs_free NMUtilsNamedValue *values = NULL;
|
2021-11-09 13:28:54 +01:00
|
|
|
gs_free const char **names = NULL;
|
|
|
|
|
const guint *vlan_ids;
|
2018-05-25 12:05:24 +02:00
|
|
|
guint num_vlans, num_attrs;
|
|
|
|
|
guint i;
|
2021-11-09 13:28:54 +01:00
|
|
|
GString *str;
|
2018-05-25 12:05:24 +02:00
|
|
|
|
|
|
|
|
str = g_string_new("");
|
|
|
|
|
if (!omit_index)
|
|
|
|
|
g_string_append_printf(str, "%u", nm_sriov_vf_get_index(vf));
|
|
|
|
|
|
|
|
|
|
names = nm_sriov_vf_get_attribute_names(vf);
|
|
|
|
|
num_attrs = names ? g_strv_length((char **) names) : 0;
|
|
|
|
|
values = g_new0(NMUtilsNamedValue, num_attrs);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < num_attrs; i++) {
|
|
|
|
|
values[i].name = names[i];
|
|
|
|
|
values[i].value_ptr = nm_sriov_vf_get_attribute(vf, names[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (num_attrs > 0) {
|
|
|
|
|
if (!omit_index)
|
|
|
|
|
g_string_append_c(str, ' ');
|
2020-07-07 18:03:48 +02:00
|
|
|
_nm_utils_format_variant_attributes_full(str, values, num_attrs, NULL, ' ', '=');
|
2018-05-25 12:05:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vlan_ids = nm_sriov_vf_get_vlan_ids(vf, &num_vlans);
|
|
|
|
|
if (num_vlans != 0) {
|
|
|
|
|
g_string_append(str, " vlans");
|
|
|
|
|
for (i = 0; i < num_vlans; i++) {
|
|
|
|
|
guint32 qos;
|
|
|
|
|
NMSriovVFVlanProtocol protocol;
|
|
|
|
|
|
|
|
|
|
qos = nm_sriov_vf_get_vlan_qos(vf, vlan_ids[i]);
|
|
|
|
|
protocol = nm_sriov_vf_get_vlan_protocol(vf, vlan_ids[i]);
|
|
|
|
|
|
|
|
|
|
g_string_append_c(str, i == 0 ? '=' : ';');
|
|
|
|
|
|
|
|
|
|
g_string_append_printf(str, "%u", vlan_ids[i]);
|
|
|
|
|
|
|
|
|
|
if (qos != 0 || protocol != NM_SRIOV_VF_VLAN_PROTOCOL_802_1Q) {
|
|
|
|
|
g_string_append_printf(str,
|
|
|
|
|
".%u%s",
|
|
|
|
|
(unsigned) qos,
|
|
|
|
|
protocol == NM_SRIOV_VF_VLAN_PROTOCOL_802_1Q ? "" : ".ad");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return g_string_free(str, FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
|
_nm_sriov_vf_parse_vlans(NMSriovVF *vf, const char *str, GError **error)
|
|
|
|
|
{
|
|
|
|
|
gs_free const char **vlans = NULL;
|
|
|
|
|
guint i;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2021-07-30 09:15:38 +02:00
|
|
|
vlans = nm_strsplit_set(str, ";");
|
2018-05-25 12:05:24 +02:00
|
|
|
if (!vlans) {
|
|
|
|
|
g_set_error_literal(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_FAILED,
|
|
|
|
|
"empty VF VLAN");
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-05-25 12:05:24 +02:00
|
|
|
for (i = 0; vlans[i]; i++) {
|
|
|
|
|
gs_strfreev char **params = NULL;
|
|
|
|
|
guint id = G_MAXUINT;
|
|
|
|
|
gint64 qos = -1;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-05-25 12:05:24 +02:00
|
|
|
/* we accept leading/trailing whitespace around vlans[1]. Hence
|
|
|
|
|
* the nm_str_skip_leading_spaces() and g_strchomp() below.
|
|
|
|
|
*
|
|
|
|
|
* However, we don't accept any whitespace inside the specifier.
|
|
|
|
|
* Hence the NM_STRCHAR_ALL() checks. */
|
|
|
|
|
|
|
|
|
|
params = g_strsplit(nm_str_skip_leading_spaces(vlans[i]), ".", 3);
|
|
|
|
|
if (!params || !params[0] || *params[0] == '\0') {
|
|
|
|
|
g_set_error_literal(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_FAILED,
|
|
|
|
|
"empty VF VLAN");
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-05-25 12:05:24 +02:00
|
|
|
if (!params[1])
|
|
|
|
|
g_strchomp(params[0]);
|
|
|
|
|
if (NM_STRCHAR_ALL(params[0], ch, ch == 'x' || g_ascii_isdigit(ch)))
|
|
|
|
|
id = _nm_utils_ascii_str_to_int64(params[0], 0, 0, 4095, G_MAXUINT);
|
|
|
|
|
if (id == G_MAXUINT) {
|
|
|
|
|
g_set_error(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_FAILED,
|
|
|
|
|
"invalid VF VLAN id '%s'",
|
|
|
|
|
params[0]);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
if (!nm_sriov_vf_add_vlan(vf, id)) {
|
|
|
|
|
g_set_error(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_FAILED,
|
|
|
|
|
"duplicate VLAN id %u",
|
|
|
|
|
id);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-05-25 12:05:24 +02:00
|
|
|
if (!params[1])
|
|
|
|
|
continue;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-05-25 12:05:24 +02:00
|
|
|
if (!params[2])
|
|
|
|
|
g_strchomp(params[1]);
|
|
|
|
|
if (NM_STRCHAR_ALL(params[1], ch, ch == 'x' || g_ascii_isdigit(ch)))
|
|
|
|
|
qos = _nm_utils_ascii_str_to_int64(params[1], 0, 0, G_MAXUINT32, -1);
|
|
|
|
|
if (qos == -1) {
|
|
|
|
|
g_set_error(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_FAILED,
|
|
|
|
|
"invalid VF VLAN QoS '%s'",
|
|
|
|
|
params[1]);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
nm_sriov_vf_set_vlan_qos(vf, id, qos);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-05-25 12:05:24 +02:00
|
|
|
if (!params[2])
|
|
|
|
|
continue;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-05-25 12:05:24 +02:00
|
|
|
g_strchomp(params[2]);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-05-25 12:05:24 +02:00
|
|
|
if (nm_streq(params[2], "ad"))
|
|
|
|
|
nm_sriov_vf_set_vlan_protocol(vf, id, NM_SRIOV_VF_VLAN_PROTOCOL_802_1AD);
|
|
|
|
|
else if (nm_streq(params[2], "q"))
|
|
|
|
|
nm_sriov_vf_set_vlan_protocol(vf, id, NM_SRIOV_VF_VLAN_PROTOCOL_802_1Q);
|
|
|
|
|
else {
|
|
|
|
|
g_set_error(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_FAILED,
|
|
|
|
|
"invalid VF VLAN protocol '%s'",
|
|
|
|
|
params[2]);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-05-25 12:05:24 +02:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_utils_sriov_vf_from_str:
|
|
|
|
|
* @str: the input string
|
2023-03-01 01:21:38 +01:00
|
|
|
* @error: location to store the error on failure
|
2018-05-25 12:05:24 +02:00
|
|
|
*
|
|
|
|
|
* Converts a string to a SR-IOV virtual function object.
|
|
|
|
|
*
|
|
|
|
|
* Returns: (transfer full): the virtual function object
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.14
|
|
|
|
|
*/
|
|
|
|
|
NMSriovVF *
|
|
|
|
|
nm_utils_sriov_vf_from_str(const char *str, GError **error)
|
|
|
|
|
{
|
|
|
|
|
gs_free char *index_free = NULL;
|
2021-11-09 13:28:54 +01:00
|
|
|
const char *detail;
|
2018-05-25 12:05:24 +02:00
|
|
|
|
|
|
|
|
g_return_val_if_fail(str, NULL);
|
|
|
|
|
g_return_val_if_fail(!error || !*error, NULL);
|
|
|
|
|
|
|
|
|
|
while (*str == ' ')
|
|
|
|
|
str++;
|
|
|
|
|
|
|
|
|
|
detail = strchr(str, ' ');
|
|
|
|
|
if (detail) {
|
2019-03-20 12:26:15 +01:00
|
|
|
str = nm_strndup_a(200, str, detail - str, &index_free);
|
2018-05-25 12:05:24 +02:00
|
|
|
detail++;
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-01 17:44:37 +01:00
|
|
|
return _nm_utils_sriov_vf_from_strparts(str, detail, FALSE, error);
|
2018-05-25 12:05:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NMSriovVF *
|
2018-12-01 17:44:37 +01:00
|
|
|
_nm_utils_sriov_vf_from_strparts(const char *index,
|
|
|
|
|
const char *detail,
|
|
|
|
|
gboolean ignore_unknown,
|
2021-11-09 13:28:54 +01:00
|
|
|
GError **error)
|
2018-05-25 12:05:24 +02:00
|
|
|
{
|
2021-11-09 13:28:54 +01:00
|
|
|
NMSriovVF *vf;
|
|
|
|
|
guint32 n_index;
|
|
|
|
|
GHashTableIter iter;
|
|
|
|
|
char *key;
|
|
|
|
|
GVariant *variant;
|
2018-05-25 12:05:24 +02:00
|
|
|
gs_unref_hashtable GHashTable *ht = NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-05-25 12:05:24 +02:00
|
|
|
n_index = _nm_utils_ascii_str_to_int64(index, 10, 0, G_MAXUINT32, 0);
|
|
|
|
|
if (errno) {
|
|
|
|
|
g_set_error_literal(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_FAILED,
|
|
|
|
|
"invalid index");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-05-25 12:05:24 +02:00
|
|
|
vf = nm_sriov_vf_new(n_index);
|
|
|
|
|
if (detail) {
|
2018-12-01 17:44:37 +01:00
|
|
|
ht = nm_utils_parse_variant_attributes(detail,
|
|
|
|
|
' ',
|
|
|
|
|
'=',
|
|
|
|
|
ignore_unknown,
|
|
|
|
|
_nm_sriov_vf_attribute_spec,
|
|
|
|
|
error);
|
2018-05-25 12:05:24 +02:00
|
|
|
if (!ht) {
|
|
|
|
|
nm_sriov_vf_unref(vf);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-05-25 12:05:24 +02:00
|
|
|
if ((variant = g_hash_table_lookup(ht, "vlans"))) {
|
|
|
|
|
if (!_nm_sriov_vf_parse_vlans(vf, g_variant_get_string(variant, NULL), error)) {
|
|
|
|
|
nm_sriov_vf_unref(vf);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
g_hash_table_remove(ht, "vlans");
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-05-25 12:05:24 +02:00
|
|
|
g_hash_table_iter_init(&iter, ht);
|
|
|
|
|
while (g_hash_table_iter_next(&iter, (gpointer *) &key, (gpointer *) &variant))
|
|
|
|
|
nm_sriov_vf_set_attribute(vf, key, g_variant_ref_sink(variant));
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-05-25 12:05:24 +02:00
|
|
|
return vf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2016-11-08 17:39:26 +01:00
|
|
|
/**
|
|
|
|
|
* nm_utils_uuid_generate:
|
|
|
|
|
*
|
|
|
|
|
* Returns: a newly allocated UUID suitable for use as the #NMSettingConnection
|
|
|
|
|
* object's #NMSettingConnection:id: property. Should be freed with g_free()
|
|
|
|
|
**/
|
|
|
|
|
char *
|
|
|
|
|
nm_utils_uuid_generate(void)
|
|
|
|
|
{
|
2021-05-02 14:55:46 +02:00
|
|
|
return nm_uuid_generate_random_str_malloc();
|
2016-11-08 17:39:26 +01:00
|
|
|
}
|
|
|
|
|
|
2016-10-02 18:22:50 +02:00
|
|
|
/*****************************************************************************/
|
2015-02-22 20:15:52 +01:00
|
|
|
|
2015-05-28 21:52:24 +02:00
|
|
|
gboolean
|
2021-11-09 13:28:54 +01:00
|
|
|
_nm_utils_check_file(const char *filename,
|
2015-05-28 21:52:24 +02:00
|
|
|
gint64 check_owner,
|
|
|
|
|
NMUtilsCheckFilePredicate check_file,
|
|
|
|
|
gpointer user_data,
|
2021-11-09 13:28:54 +01:00
|
|
|
struct stat *out_st,
|
|
|
|
|
GError **error)
|
2015-05-28 21:52:24 +02:00
|
|
|
{
|
|
|
|
|
struct stat st_backup;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-05-28 21:52:24 +02:00
|
|
|
if (!out_st)
|
|
|
|
|
out_st = &st_backup;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-05-28 21:52:24 +02:00
|
|
|
if (stat(filename, out_st) != 0) {
|
|
|
|
|
int errsv = errno;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-05-28 21:52:24 +02:00
|
|
|
g_set_error(error,
|
|
|
|
|
NM_VPN_PLUGIN_ERROR,
|
|
|
|
|
NM_VPN_PLUGIN_ERROR_FAILED,
|
2019-01-31 17:22:18 +01:00
|
|
|
_("failed stat file %s: %s"),
|
|
|
|
|
filename,
|
|
|
|
|
nm_strerror_native(errsv));
|
2015-05-28 21:52:24 +02:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-05-28 21:52:24 +02:00
|
|
|
/* ignore non-files. */
|
|
|
|
|
if (!S_ISREG(out_st->st_mode)) {
|
|
|
|
|
g_set_error(error,
|
|
|
|
|
NM_VPN_PLUGIN_ERROR,
|
|
|
|
|
NM_VPN_PLUGIN_ERROR_FAILED,
|
|
|
|
|
_("not a file (%s)"),
|
|
|
|
|
filename);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-05-28 21:52:24 +02:00
|
|
|
/* with check_owner enabled, check that the file belongs to the
|
|
|
|
|
* owner or root. */
|
|
|
|
|
if (check_owner >= 0 && (out_st->st_uid != 0 && (gint64) out_st->st_uid != check_owner)) {
|
|
|
|
|
g_set_error(error,
|
|
|
|
|
NM_VPN_PLUGIN_ERROR,
|
|
|
|
|
NM_VPN_PLUGIN_ERROR_FAILED,
|
|
|
|
|
_("invalid file owner %d for %s"),
|
|
|
|
|
out_st->st_uid,
|
|
|
|
|
filename);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-05-28 21:52:24 +02:00
|
|
|
/* with check_owner enabled, check that the file cannot be modified
|
|
|
|
|
* by other users (except root). */
|
|
|
|
|
if (check_owner >= 0 && NM_FLAGS_ANY(out_st->st_mode, S_IWGRP | S_IWOTH | S_ISUID)) {
|
|
|
|
|
g_set_error(error,
|
|
|
|
|
NM_VPN_PLUGIN_ERROR,
|
|
|
|
|
NM_VPN_PLUGIN_ERROR_FAILED,
|
|
|
|
|
_("file permissions for %s"),
|
|
|
|
|
filename);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-05-28 21:52:24 +02:00
|
|
|
if (check_file && !check_file(filename, out_st, user_data, error)) {
|
|
|
|
|
if (error && !*error) {
|
|
|
|
|
g_set_error(error,
|
|
|
|
|
NM_VPN_PLUGIN_ERROR,
|
|
|
|
|
NM_VPN_PLUGIN_ERROR_FAILED,
|
|
|
|
|
_("reject %s"),
|
|
|
|
|
filename);
|
|
|
|
|
}
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-05-28 21:52:24 +02:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
libnm: require exact vpn plugin filename
Originally, nm-applet loaded the vpn plugins by passing the filename
to g_module_open(). Thereby, g_module_open() allowed for missing file
extension and tries to complete the name with a system-dependent suffix.
When porting to libnm, we kept that behavior but did more elaborate
checks on the file, like checking owner and permissions.
Change to no longer trying to append the system suffix, but require
an exact path. That is no usability problem, because the plugin path
is specified in the .name files, and we just require them now to be the
full path (including the .so extension).
Note also, that this only affects new, libnm-based vpn plugins, thus there
is no change in behavior for legacy libnm-glib based plugins.
Fixes: eed0d0c58f7f13638eb587e240737048d729cb68
2015-08-18 11:56:17 +02:00
|
|
|
gboolean
|
2021-11-09 13:28:54 +01:00
|
|
|
_nm_utils_check_module_file(const char *name,
|
2015-05-28 22:07:55 +02:00
|
|
|
int check_owner,
|
|
|
|
|
NMUtilsCheckFilePredicate check_file,
|
|
|
|
|
gpointer user_data,
|
2021-11-09 13:28:54 +01:00
|
|
|
GError **error)
|
2015-05-28 22:07:55 +02:00
|
|
|
{
|
|
|
|
|
if (!g_path_is_absolute(name)) {
|
|
|
|
|
g_set_error(error,
|
|
|
|
|
NM_VPN_PLUGIN_ERROR,
|
|
|
|
|
NM_VPN_PLUGIN_ERROR_FAILED,
|
|
|
|
|
_("path is not absolute (%s)"),
|
|
|
|
|
name);
|
libnm: require exact vpn plugin filename
Originally, nm-applet loaded the vpn plugins by passing the filename
to g_module_open(). Thereby, g_module_open() allowed for missing file
extension and tries to complete the name with a system-dependent suffix.
When porting to libnm, we kept that behavior but did more elaborate
checks on the file, like checking owner and permissions.
Change to no longer trying to append the system suffix, but require
an exact path. That is no usability problem, because the plugin path
is specified in the .name files, and we just require them now to be the
full path (including the .so extension).
Note also, that this only affects new, libnm-based vpn plugins, thus there
is no change in behavior for legacy libnm-glib based plugins.
Fixes: eed0d0c58f7f13638eb587e240737048d729cb68
2015-08-18 11:56:17 +02:00
|
|
|
return FALSE;
|
2015-05-28 22:07:55 +02:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-08-20 12:25:24 +02:00
|
|
|
/* Set special error code if the file doesn't exist.
|
|
|
|
|
* The VPN package might be split into separate packages,
|
|
|
|
|
* so it could be correct that the plugin file is missing.
|
|
|
|
|
*
|
|
|
|
|
* Note that nm-applet checks for this error code to fail
|
|
|
|
|
* gracefully. */
|
|
|
|
|
if (!g_file_test(name, G_FILE_TEST_EXISTS)) {
|
|
|
|
|
g_set_error(error,
|
|
|
|
|
G_FILE_ERROR,
|
|
|
|
|
G_FILE_ERROR_NOENT,
|
|
|
|
|
_("Plugin file does not exist (%s)"),
|
|
|
|
|
name);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm: require exact vpn plugin filename
Originally, nm-applet loaded the vpn plugins by passing the filename
to g_module_open(). Thereby, g_module_open() allowed for missing file
extension and tries to complete the name with a system-dependent suffix.
When porting to libnm, we kept that behavior but did more elaborate
checks on the file, like checking owner and permissions.
Change to no longer trying to append the system suffix, but require
an exact path. That is no usability problem, because the plugin path
is specified in the .name files, and we just require them now to be the
full path (including the .so extension).
Note also, that this only affects new, libnm-based vpn plugins, thus there
is no change in behavior for legacy libnm-glib based plugins.
Fixes: eed0d0c58f7f13638eb587e240737048d729cb68
2015-08-18 11:56:17 +02:00
|
|
|
if (!g_file_test(name, G_FILE_TEST_IS_REGULAR)) {
|
2015-05-28 22:07:55 +02:00
|
|
|
g_set_error(error,
|
|
|
|
|
NM_VPN_PLUGIN_ERROR,
|
|
|
|
|
NM_VPN_PLUGIN_ERROR_FAILED,
|
2015-08-20 12:25:24 +02:00
|
|
|
_("Plugin is not a valid file (%s)"),
|
|
|
|
|
name);
|
libnm: require exact vpn plugin filename
Originally, nm-applet loaded the vpn plugins by passing the filename
to g_module_open(). Thereby, g_module_open() allowed for missing file
extension and tries to complete the name with a system-dependent suffix.
When porting to libnm, we kept that behavior but did more elaborate
checks on the file, like checking owner and permissions.
Change to no longer trying to append the system suffix, but require
an exact path. That is no usability problem, because the plugin path
is specified in the .name files, and we just require them now to be the
full path (including the .so extension).
Note also, that this only affects new, libnm-based vpn plugins, thus there
is no change in behavior for legacy libnm-glib based plugins.
Fixes: eed0d0c58f7f13638eb587e240737048d729cb68
2015-08-18 11:56:17 +02:00
|
|
|
return FALSE;
|
2015-05-28 22:07:55 +02:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm: require exact vpn plugin filename
Originally, nm-applet loaded the vpn plugins by passing the filename
to g_module_open(). Thereby, g_module_open() allowed for missing file
extension and tries to complete the name with a system-dependent suffix.
When porting to libnm, we kept that behavior but did more elaborate
checks on the file, like checking owner and permissions.
Change to no longer trying to append the system suffix, but require
an exact path. That is no usability problem, because the plugin path
is specified in the .name files, and we just require them now to be the
full path (including the .so extension).
Note also, that this only affects new, libnm-based vpn plugins, thus there
is no change in behavior for legacy libnm-glib based plugins.
Fixes: eed0d0c58f7f13638eb587e240737048d729cb68
2015-08-18 11:56:17 +02:00
|
|
|
if (g_str_has_suffix(name, ".la")) {
|
2015-05-28 22:07:55 +02:00
|
|
|
/* g_module_open() treats files that end with .la special.
|
|
|
|
|
* We don't want to parse the libtool archive. Just error out. */
|
|
|
|
|
g_set_error(error,
|
|
|
|
|
NM_VPN_PLUGIN_ERROR,
|
|
|
|
|
NM_VPN_PLUGIN_ERROR_FAILED,
|
libnm: require exact vpn plugin filename
Originally, nm-applet loaded the vpn plugins by passing the filename
to g_module_open(). Thereby, g_module_open() allowed for missing file
extension and tries to complete the name with a system-dependent suffix.
When porting to libnm, we kept that behavior but did more elaborate
checks on the file, like checking owner and permissions.
Change to no longer trying to append the system suffix, but require
an exact path. That is no usability problem, because the plugin path
is specified in the .name files, and we just require them now to be the
full path (including the .so extension).
Note also, that this only affects new, libnm-based vpn plugins, thus there
is no change in behavior for legacy libnm-glib based plugins.
Fixes: eed0d0c58f7f13638eb587e240737048d729cb68
2015-08-18 11:56:17 +02:00
|
|
|
_("libtool archives are not supported (%s)"),
|
|
|
|
|
name);
|
|
|
|
|
return FALSE;
|
2015-05-28 22:07:55 +02:00
|
|
|
}
|
|
|
|
|
|
libnm: require exact vpn plugin filename
Originally, nm-applet loaded the vpn plugins by passing the filename
to g_module_open(). Thereby, g_module_open() allowed for missing file
extension and tries to complete the name with a system-dependent suffix.
When porting to libnm, we kept that behavior but did more elaborate
checks on the file, like checking owner and permissions.
Change to no longer trying to append the system suffix, but require
an exact path. That is no usability problem, because the plugin path
is specified in the .name files, and we just require them now to be the
full path (including the .so extension).
Note also, that this only affects new, libnm-based vpn plugins, thus there
is no change in behavior for legacy libnm-glib based plugins.
Fixes: eed0d0c58f7f13638eb587e240737048d729cb68
2015-08-18 11:56:17 +02:00
|
|
|
return _nm_utils_check_file(name, check_owner, check_file, user_data, NULL, error);
|
2015-05-28 22:07:55 +02:00
|
|
|
}
|
|
|
|
|
|
2016-10-02 18:22:50 +02:00
|
|
|
/*****************************************************************************/
|
2015-05-28 21:52:24 +02:00
|
|
|
|
2014-11-25 23:01:55 +01:00
|
|
|
/**
|
|
|
|
|
* nm_utils_file_search_in_paths:
|
|
|
|
|
* @progname: the helper program name, like "iptables"
|
|
|
|
|
* Must be a non-empty string, without path separator (/).
|
2023-03-01 01:21:38 +01:00
|
|
|
* @try_first: (nullable): a custom path to try first before searching.
|
2014-11-25 23:01:55 +01:00
|
|
|
* It is silently ignored if it is empty or not an absolute path.
|
2023-03-01 01:21:38 +01:00
|
|
|
* @paths: (nullable): a %NULL terminated list of search paths.
|
2014-11-25 23:01:55 +01:00
|
|
|
* Can be empty or %NULL, in which case only @try_first is checked.
|
|
|
|
|
* @file_test_flags: the flags passed to g_file_test() when searching
|
|
|
|
|
* for @progname. Set it to 0 to skip the g_file_test().
|
2024-11-27 12:51:24 +01:00
|
|
|
* @predicate: (scope call) (closure user_data): if given, pass the file name to this function
|
2014-11-25 23:01:55 +01:00
|
|
|
* for additional checks. This check is performed after the check for
|
|
|
|
|
* @file_test_flags. You cannot omit both @file_test_flags and @predicate.
|
2024-11-27 12:51:24 +01:00
|
|
|
* @user_data: (nullable): user data for @predicate function.
|
2023-03-01 01:21:38 +01:00
|
|
|
* @error: on failure, set a "not found" error %G_IO_ERROR %G_IO_ERROR_NOT_FOUND.
|
2014-11-25 23:01:55 +01:00
|
|
|
*
|
|
|
|
|
* Searches for a @progname file in a list of search @paths.
|
|
|
|
|
*
|
|
|
|
|
* Returns: (transfer none): the full path to the helper, if found, or %NULL if not found.
|
|
|
|
|
* The returned string is not owned by the caller, but later
|
|
|
|
|
* invocations of the function might overwrite it.
|
|
|
|
|
*/
|
|
|
|
|
const char *
|
2021-11-09 13:28:54 +01:00
|
|
|
nm_utils_file_search_in_paths(const char *progname,
|
|
|
|
|
const char *try_first,
|
|
|
|
|
const char *const *paths,
|
2014-11-25 23:01:55 +01:00
|
|
|
GFileTest file_test_flags,
|
|
|
|
|
NMUtilsFileSearchInPathsPredicate predicate,
|
|
|
|
|
gpointer user_data,
|
2021-11-09 13:28:54 +01:00
|
|
|
GError **error)
|
2014-11-25 23:01:55 +01:00
|
|
|
{
|
|
|
|
|
g_return_val_if_fail(!error || !*error, NULL);
|
|
|
|
|
g_return_val_if_fail(progname && progname[0] && !strchr(progname, '/'), NULL);
|
2014-12-05 14:59:34 +01:00
|
|
|
g_return_val_if_fail(file_test_flags || predicate, NULL);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-11-25 23:01:55 +01:00
|
|
|
/* Only consider @try_first if it is a valid, absolute path. This makes
|
|
|
|
|
* it simpler to pass in a path from configure checks. */
|
|
|
|
|
if (try_first && try_first[0] == '/'
|
2020-06-21 13:10:45 +02:00
|
|
|
&& (file_test_flags == 0 || g_file_test(try_first, file_test_flags))
|
|
|
|
|
&& (!predicate || predicate(try_first, user_data)))
|
2014-11-25 23:01:55 +01:00
|
|
|
return g_intern_string(try_first);
|
|
|
|
|
|
2020-06-21 13:10:45 +02:00
|
|
|
if (paths && paths[0]) {
|
|
|
|
|
nm_auto_str_buf NMStrBuf strbuf =
|
|
|
|
|
NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_104, FALSE);
|
2014-11-25 23:01:55 +01:00
|
|
|
|
2020-06-21 13:10:45 +02:00
|
|
|
for (; *paths; paths++) {
|
|
|
|
|
const char *path = *paths;
|
|
|
|
|
const char *s;
|
|
|
|
|
|
|
|
|
|
if (!path[0])
|
|
|
|
|
continue;
|
|
|
|
|
|
2021-02-10 08:46:58 +01:00
|
|
|
nm_str_buf_reset(&strbuf);
|
|
|
|
|
nm_str_buf_append(&strbuf, path);
|
2020-06-21 13:10:45 +02:00
|
|
|
nm_str_buf_ensure_trailing_c(&strbuf, '/');
|
|
|
|
|
s = nm_str_buf_append0(&strbuf, progname);
|
|
|
|
|
|
|
|
|
|
if ((file_test_flags == 0 || g_file_test(s, file_test_flags))
|
|
|
|
|
&& (!predicate || predicate(s, user_data)))
|
|
|
|
|
return g_intern_string(s);
|
2014-11-25 23:01:55 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_set_error(error,
|
|
|
|
|
G_IO_ERROR,
|
|
|
|
|
G_IO_ERROR_NOT_FOUND,
|
|
|
|
|
_("Could not find \"%s\" binary"),
|
|
|
|
|
progname);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-02 18:22:50 +02:00
|
|
|
/*****************************************************************************/
|
2014-11-25 23:01:55 +01:00
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
/* Band, channel/frequency stuff for wireless */
|
|
|
|
|
struct cf_pair {
|
|
|
|
|
guint32 chan;
|
|
|
|
|
guint32 freq;
|
|
|
|
|
};
|
|
|
|
|
|
2025-11-28 15:19:59 +01:00
|
|
|
static const struct cf_pair table_5ghz[] = {
|
2014-07-24 08:53:33 -04:00
|
|
|
{7, 5035}, {8, 5040}, {9, 5045}, {11, 5055}, {12, 5060}, {16, 5080}, {34, 5170},
|
|
|
|
|
{36, 5180}, {38, 5190}, {40, 5200}, {42, 5210}, {44, 5220}, {46, 5230}, {48, 5240},
|
|
|
|
|
{50, 5250}, {52, 5260}, {56, 5280}, {58, 5290}, {60, 5300}, {64, 5320}, {100, 5500},
|
|
|
|
|
{104, 5520}, {108, 5540}, {112, 5560}, {116, 5580}, {120, 5600}, {124, 5620}, {128, 5640},
|
|
|
|
|
{132, 5660}, {136, 5680}, {140, 5700}, {149, 5745}, {152, 5760}, {153, 5765}, {157, 5785},
|
|
|
|
|
{160, 5800}, {161, 5805}, {165, 5825}, {183, 4915}, {184, 4920}, {185, 4925}, {187, 4935},
|
|
|
|
|
{188, 4945}, {192, 4960}, {196, 4980}, {0, 0}};
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2025-11-28 15:19:59 +01:00
|
|
|
static const guint table_5ghz_freqs[G_N_ELEMENTS(table_5ghz)] = {
|
2020-06-21 21:59:32 +02:00
|
|
|
5035, 5040, 5045, 5055, 5060, 5080, 5170, 5180, 5190, 5200, 5210, 5220, 5230, 5240, 5250, 5260,
|
|
|
|
|
5280, 5290, 5300, 5320, 5500, 5520, 5540, 5560, 5580, 5600, 5620, 5640, 5660, 5680, 5700, 5745,
|
|
|
|
|
5760, 5765, 5785, 5800, 5805, 5825, 4915, 4920, 4925, 4935, 4945, 4960, 4980, 0,
|
|
|
|
|
};
|
|
|
|
|
|
2025-11-28 15:19:59 +01:00
|
|
|
static const struct cf_pair table_2ghz[] = {{1, 2412},
|
|
|
|
|
{2, 2417},
|
|
|
|
|
{3, 2422},
|
|
|
|
|
{4, 2427},
|
|
|
|
|
{5, 2432},
|
|
|
|
|
{6, 2437},
|
|
|
|
|
{7, 2442},
|
|
|
|
|
{8, 2447},
|
|
|
|
|
{9, 2452},
|
|
|
|
|
{10, 2457},
|
|
|
|
|
{11, 2462},
|
|
|
|
|
{12, 2467},
|
|
|
|
|
{13, 2472},
|
|
|
|
|
{14, 2484},
|
|
|
|
|
{0, 0}};
|
|
|
|
|
|
|
|
|
|
static const guint table_2ghz_freqs[G_N_ELEMENTS(table_2ghz)] = {
|
2020-06-21 21:59:32 +02:00
|
|
|
2412,
|
|
|
|
|
2417,
|
|
|
|
|
2422,
|
|
|
|
|
2427,
|
|
|
|
|
2432,
|
|
|
|
|
2437,
|
|
|
|
|
2442,
|
|
|
|
|
2447,
|
|
|
|
|
2452,
|
|
|
|
|
2457,
|
|
|
|
|
2462,
|
|
|
|
|
2467,
|
|
|
|
|
2472,
|
|
|
|
|
2484,
|
|
|
|
|
0,
|
2014-07-24 08:53:33 -04:00
|
|
|
};
|
|
|
|
|
|
2025-11-28 15:19:59 +01:00
|
|
|
static const struct cf_pair table_6ghz[] = {
|
|
|
|
|
{1, 5955}, {5, 5975}, {9, 5995}, {13, 6015}, {17, 6035}, {21, 6055}, {25, 6075},
|
|
|
|
|
{29, 6095}, {33, 6115}, {37, 6135}, {41, 6155}, {45, 6175}, {49, 6195}, {53, 6215},
|
|
|
|
|
{57, 6235}, {61, 6255}, {65, 6275}, {69, 6295}, {73, 6315}, {77, 6335}, {81, 6355},
|
|
|
|
|
{85, 6375}, {89, 6395}, {93, 6415}, {97, 6435}, {101, 6455}, {105, 6475}, {109, 6495},
|
|
|
|
|
{113, 6515}, {117, 6535}, {121, 6555}, {125, 6575}, {129, 6595}, {133, 6615}, {137, 6635},
|
|
|
|
|
{141, 6655}, {145, 6675}, {149, 6695}, {153, 6715}, {157, 6735}, {161, 6755}, {169, 6775},
|
|
|
|
|
{173, 6815}, {177, 6835}, {181, 6855}, {185, 6875}, {189, 6895}, {193, 6915}, {197, 6935},
|
|
|
|
|
{201, 6955}, {205, 6975}, {209, 6995}, {213, 7015}, {217, 7035}, {221, 7055}, {225, 7075},
|
|
|
|
|
{229, 7095}, {233, 7115}, {0, 0}};
|
|
|
|
|
|
|
|
|
|
static const guint table_6ghz_freqs[G_N_ELEMENTS(table_6ghz)] = {
|
|
|
|
|
5955, 5975, 5995, 6015, 6035, 6055, 6075, 6095, 6115, 6135, 6155, 6175, 6195, 6215, 6235,
|
|
|
|
|
6255, 6275, 6295, 6315, 6335, 6355, 6375, 6395, 6415, 6435, 6455, 6475, 6495, 6515, 6535,
|
|
|
|
|
6555, 6575, 6595, 6615, 6635, 6655, 6675, 6695, 6715, 6735, 6755, 6775, 6815, 6835, 6855,
|
|
|
|
|
6875, 6895, 6915, 6935, 6955, 6975, 6995, 7015, 7035, 7055, 7075, 7095, 7115, 0,
|
|
|
|
|
};
|
|
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
/**
|
|
|
|
|
* nm_utils_wifi_freq_to_channel:
|
|
|
|
|
* @freq: frequency
|
|
|
|
|
*
|
|
|
|
|
* Utility function to translate a Wi-Fi frequency to its corresponding channel.
|
|
|
|
|
*
|
|
|
|
|
* Returns: the channel represented by the frequency or 0
|
|
|
|
|
**/
|
|
|
|
|
guint32
|
|
|
|
|
nm_utils_wifi_freq_to_channel(guint32 freq)
|
|
|
|
|
{
|
2025-11-28 15:19:59 +01:00
|
|
|
const struct cf_pair *table;
|
|
|
|
|
int i = 0;
|
2014-07-24 08:53:33 -04:00
|
|
|
|
2025-11-28 15:19:59 +01:00
|
|
|
if (freq >= _NM_WIFI_FREQ_MIN_6GHZ) {
|
|
|
|
|
table = table_6ghz;
|
|
|
|
|
} else if (freq >= _NM_WIFI_FREQ_MIN_5GHZ) {
|
|
|
|
|
table = table_5ghz;
|
|
|
|
|
} else {
|
|
|
|
|
table = table_2ghz;
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
|
|
|
|
|
2025-11-28 15:19:59 +01:00
|
|
|
while (table[i].freq && (table[i].freq != freq))
|
2020-06-21 21:59:32 +02:00
|
|
|
i++;
|
2025-11-28 15:19:59 +01:00
|
|
|
|
|
|
|
|
return table[i].chan;
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
|
|
|
|
|
2019-02-20 13:23:26 +01:00
|
|
|
/**
|
|
|
|
|
* nm_utils_wifi_freq_to_band:
|
|
|
|
|
* @freq: frequency
|
|
|
|
|
*
|
|
|
|
|
* Utility function to translate a Wi-Fi frequency to its corresponding band.
|
|
|
|
|
*
|
|
|
|
|
* Returns: the band containing the frequency or NULL if freq is invalid
|
|
|
|
|
**/
|
|
|
|
|
const char *
|
|
|
|
|
nm_utils_wifi_freq_to_band(guint32 freq)
|
|
|
|
|
{
|
2025-11-28 15:19:59 +01:00
|
|
|
if (freq >= _NM_WIFI_FREQ_MIN_2GHZ && freq <= _NM_WIFI_FREQ_MAX_2GHZ)
|
2019-02-20 13:23:26 +01:00
|
|
|
return "bg";
|
2025-11-28 15:19:59 +01:00
|
|
|
else if (freq >= _NM_WIFI_FREQ_MIN_5GHZ && freq <= _NM_WIFI_FREQ_MAX_5GHZ)
|
|
|
|
|
return "a";
|
|
|
|
|
else if (freq >= _NM_WIFI_FREQ_MIN_6GHZ && freq <= _NM_WIFI_FREQ_MAX_6GHZ)
|
|
|
|
|
return "6GHz";
|
2019-02-20 13:23:26 +01:00
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
/**
|
|
|
|
|
* nm_utils_wifi_channel_to_freq:
|
|
|
|
|
* @channel: channel
|
2025-11-28 15:19:59 +01:00
|
|
|
* @band: frequency band for wireless ("a", "bg", "6GHz")
|
2014-07-24 08:53:33 -04:00
|
|
|
*
|
|
|
|
|
* Utility function to translate a Wi-Fi channel to its corresponding frequency.
|
|
|
|
|
*
|
|
|
|
|
* Returns: the frequency represented by the channel of the band,
|
|
|
|
|
* or -1 when the freq is invalid, or 0 when the band
|
|
|
|
|
* is invalid
|
|
|
|
|
**/
|
|
|
|
|
guint32
|
|
|
|
|
nm_utils_wifi_channel_to_freq(guint32 channel, const char *band)
|
|
|
|
|
{
|
2025-11-28 15:19:59 +01:00
|
|
|
const struct cf_pair *table;
|
|
|
|
|
int i;
|
2020-06-21 21:59:32 +02:00
|
|
|
|
|
|
|
|
g_return_val_if_fail(band, 0);
|
2014-07-24 08:53:33 -04:00
|
|
|
|
2025-11-28 15:19:59 +01:00
|
|
|
if (nm_streq0(band, "a")) {
|
|
|
|
|
table = table_5ghz;
|
|
|
|
|
} else if (nm_streq0(band, "bg")) {
|
|
|
|
|
table = table_2ghz;
|
|
|
|
|
} else if (nm_streq0(band, "6GHz")) {
|
|
|
|
|
table = table_6ghz;
|
|
|
|
|
} else {
|
|
|
|
|
return 0;
|
2020-06-21 21:59:32 +02:00
|
|
|
}
|
|
|
|
|
|
2025-11-28 15:19:59 +01:00
|
|
|
for (i = 0; table[i].chan; i++) {
|
|
|
|
|
if (table[i].chan == channel)
|
|
|
|
|
return table[i].freq;
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
2025-11-28 15:19:59 +01:00
|
|
|
return ((guint32) -1);
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_utils_wifi_find_next_channel:
|
|
|
|
|
* @channel: current channel
|
|
|
|
|
* @direction: whether going downward (0 or less) or upward (1 or more)
|
2025-11-28 15:19:59 +01:00
|
|
|
* @band: frequency band for wireless ("a", "bg", "6GHz")
|
2014-07-24 08:53:33 -04:00
|
|
|
*
|
|
|
|
|
* Utility function to find out next/previous Wi-Fi channel for a channel.
|
|
|
|
|
*
|
|
|
|
|
* Returns: the next channel in the specified direction or 0
|
|
|
|
|
**/
|
|
|
|
|
guint32
|
|
|
|
|
nm_utils_wifi_find_next_channel(guint32 channel, int direction, char *band)
|
|
|
|
|
{
|
2025-11-28 15:19:59 +01:00
|
|
|
const struct cf_pair *table;
|
|
|
|
|
guint table_size;
|
|
|
|
|
|
|
|
|
|
if (nm_streq0(band, "a")) {
|
|
|
|
|
table = table_5ghz;
|
|
|
|
|
table_size = G_N_ELEMENTS(table_5ghz);
|
|
|
|
|
} else if (nm_streq0(band, "bg")) {
|
|
|
|
|
table = table_2ghz;
|
|
|
|
|
table_size = G_N_ELEMENTS(table_2ghz);
|
|
|
|
|
} else if (nm_streq0(band, "6GHz")) {
|
|
|
|
|
table = table_6ghz;
|
|
|
|
|
table_size = G_N_ELEMENTS(table_6ghz);
|
2020-06-22 09:21:06 +02:00
|
|
|
} else
|
|
|
|
|
g_return_val_if_reached(0);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2025-11-28 15:19:59 +01:00
|
|
|
if (channel < table[0].chan)
|
|
|
|
|
return table[0].chan;
|
|
|
|
|
if (channel > table[table_size - 2].chan)
|
|
|
|
|
return table[table_size - 2].chan;
|
|
|
|
|
|
|
|
|
|
while (table->chan) {
|
|
|
|
|
if (channel == table->chan)
|
2014-07-24 08:53:33 -04:00
|
|
|
return channel;
|
2025-11-28 15:19:59 +01:00
|
|
|
if ((channel < (table + 1)->chan) && (channel > table->chan)) {
|
2014-07-24 08:53:33 -04:00
|
|
|
if (direction > 0)
|
2025-11-28 15:19:59 +01:00
|
|
|
return (table + 1)->chan;
|
2014-07-24 08:53:33 -04:00
|
|
|
else
|
2025-11-28 15:19:59 +01:00
|
|
|
return table->chan;
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
2025-11-28 15:19:59 +01:00
|
|
|
table++;
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_utils_wifi_is_channel_valid:
|
|
|
|
|
* @channel: channel
|
2025-11-28 15:19:59 +01:00
|
|
|
* @band: frequency band for wireless ("a", "bg", "6GHz")
|
2014-07-24 08:53:33 -04:00
|
|
|
*
|
|
|
|
|
* Utility function to verify Wi-Fi channel validity.
|
|
|
|
|
*
|
|
|
|
|
* Returns: %TRUE or %FALSE
|
|
|
|
|
**/
|
|
|
|
|
gboolean
|
|
|
|
|
nm_utils_wifi_is_channel_valid(guint32 channel, const char *band)
|
|
|
|
|
{
|
2020-06-21 21:59:32 +02:00
|
|
|
guint32 freq;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-06-21 21:59:32 +02:00
|
|
|
freq = nm_utils_wifi_channel_to_freq(channel, band);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-06-21 21:59:32 +02:00
|
|
|
return !NM_IN_SET(freq, 0u, (guint32) -1);
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-06-21 21:59:32 +02:00
|
|
|
#define _nm_assert_wifi_freqs(table, table_freqs) \
|
|
|
|
|
G_STMT_START \
|
|
|
|
|
{ \
|
|
|
|
|
if (NM_MORE_ASSERT_ONCE(5)) { \
|
|
|
|
|
int i, j; \
|
|
|
|
|
\
|
|
|
|
|
G_STATIC_ASSERT(G_N_ELEMENTS(table) > 0); \
|
|
|
|
|
G_STATIC_ASSERT(G_N_ELEMENTS(table) == G_N_ELEMENTS(table_freqs)); \
|
|
|
|
|
\
|
2020-10-29 12:36:22 +01:00
|
|
|
for (i = 0; i < (int) G_N_ELEMENTS(table); i++) { \
|
2020-06-21 21:59:32 +02:00
|
|
|
nm_assert((i == G_N_ELEMENTS(table) - 1) == (table[i].chan == 0)); \
|
|
|
|
|
nm_assert((i == G_N_ELEMENTS(table) - 1) == (table[i].freq == 0)); \
|
|
|
|
|
nm_assert(table[i].freq == table_freqs[i]); \
|
|
|
|
|
for (j = 0; j < i; j++) { \
|
|
|
|
|
nm_assert(table[j].chan != table[i].chan); \
|
|
|
|
|
nm_assert(table[j].freq != table[i].freq); \
|
2020-09-28 16:03:33 +02:00
|
|
|
} \
|
2020-06-21 21:59:32 +02:00
|
|
|
} \
|
|
|
|
|
} \
|
|
|
|
|
} \
|
|
|
|
|
G_STMT_END
|
2015-08-18 09:37:48 +02:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_utils_wifi_2ghz_freqs:
|
|
|
|
|
*
|
|
|
|
|
* Utility function to return 2.4 GHz Wi-Fi frequencies (802.11bg band).
|
|
|
|
|
*
|
|
|
|
|
* Returns: zero-terminated array of frequencies numbers (in MHz)
|
|
|
|
|
*
|
Revert "all: change "Since: 1.2" to "Since: 1.0.4"/"Since: 1.0.6" for backported API"
API should be added with "Since:" of the next release on the same branch.
That means, new API on 1.1 branch (development), should be "Since: 1.2"
and new API on 1.0 branch (stable) will be "Since: 1.0.x". Similarly, new
API on master is NM_AVAILABLE_IN_1_2 and will be added with the linker
version libnl_1_2 -- never the versions of minor releases.
It is also strongly advised that for the 1.0 branch, we only add API
that was previously formerly added on master. IOW, that we only do true
backports of API that already exists on master.
API that gets backported, must also be added to master via NM_BACKPORT_SYMBOL().
That gives ABI compatibility and an application that was build against 1.0.x
will work with 1.y.z version (y > 0) without need for recompiling -- provided
that 1.y.z also contains that API.
There is one important caveat: if a major branch (e.g. current master) has a
linker section of backported APIs (e.g. libnm_1_0_6), we must do the minor release
(1.0.6) before the next major release (1.2). The reason is that after the major
release, the linker section (libnm_1_0_6) must not be extended and thus
the minor release (1.0.6) must be already released at that point.
In general, users should avoid using backported API because it limits
the ability to upgrade to arbitrary later versions. But together with the
previous point (that we only backport API to minor releases), a user that
uses backported API can be sure that a 1.y.z version is ABI compatible with
1.0.x, if the 1.y.z release date was after the release date of 1.0.x.
This reverts commit 02a136682c749a0fd27853c0152d36c44635151f.
2015-08-22 00:57:30 +02:00
|
|
|
* Since: 1.2
|
2015-08-18 09:37:48 +02:00
|
|
|
**/
|
|
|
|
|
const guint *
|
|
|
|
|
nm_utils_wifi_2ghz_freqs(void)
|
|
|
|
|
{
|
2025-11-28 15:19:59 +01:00
|
|
|
_nm_assert_wifi_freqs(table_2ghz, table_2ghz_freqs);
|
|
|
|
|
return table_2ghz_freqs;
|
2015-08-18 09:37:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_utils_wifi_5ghz_freqs:
|
|
|
|
|
*
|
|
|
|
|
* Utility function to return 5 GHz Wi-Fi frequencies (802.11a band).
|
|
|
|
|
*
|
|
|
|
|
* Returns: zero-terminated array of frequencies numbers (in MHz)
|
|
|
|
|
*
|
Revert "all: change "Since: 1.2" to "Since: 1.0.4"/"Since: 1.0.6" for backported API"
API should be added with "Since:" of the next release on the same branch.
That means, new API on 1.1 branch (development), should be "Since: 1.2"
and new API on 1.0 branch (stable) will be "Since: 1.0.x". Similarly, new
API on master is NM_AVAILABLE_IN_1_2 and will be added with the linker
version libnl_1_2 -- never the versions of minor releases.
It is also strongly advised that for the 1.0 branch, we only add API
that was previously formerly added on master. IOW, that we only do true
backports of API that already exists on master.
API that gets backported, must also be added to master via NM_BACKPORT_SYMBOL().
That gives ABI compatibility and an application that was build against 1.0.x
will work with 1.y.z version (y > 0) without need for recompiling -- provided
that 1.y.z also contains that API.
There is one important caveat: if a major branch (e.g. current master) has a
linker section of backported APIs (e.g. libnm_1_0_6), we must do the minor release
(1.0.6) before the next major release (1.2). The reason is that after the major
release, the linker section (libnm_1_0_6) must not be extended and thus
the minor release (1.0.6) must be already released at that point.
In general, users should avoid using backported API because it limits
the ability to upgrade to arbitrary later versions. But together with the
previous point (that we only backport API to minor releases), a user that
uses backported API can be sure that a 1.y.z version is ABI compatible with
1.0.x, if the 1.y.z release date was after the release date of 1.0.x.
This reverts commit 02a136682c749a0fd27853c0152d36c44635151f.
2015-08-22 00:57:30 +02:00
|
|
|
* Since: 1.2
|
2015-08-18 09:37:48 +02:00
|
|
|
**/
|
|
|
|
|
const guint *
|
|
|
|
|
nm_utils_wifi_5ghz_freqs(void)
|
|
|
|
|
{
|
2025-11-28 15:19:59 +01:00
|
|
|
_nm_assert_wifi_freqs(table_5ghz, table_5ghz_freqs);
|
|
|
|
|
return table_5ghz_freqs;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_utils_wifi_6ghz_freqs:
|
|
|
|
|
*
|
|
|
|
|
* Utility function to return 6 GHz Wi-Fi frequencies (802.11ax/be, Wi-Fi 6E).
|
|
|
|
|
*
|
|
|
|
|
* Returns: zero-terminated array of frequencies numbers (in MHz)
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.58
|
|
|
|
|
**/
|
|
|
|
|
const guint *
|
|
|
|
|
nm_utils_wifi_6ghz_freqs(void)
|
|
|
|
|
{
|
|
|
|
|
_nm_assert_wifi_freqs(table_6ghz, table_6ghz_freqs);
|
|
|
|
|
return table_6ghz_freqs;
|
2015-08-18 09:37:48 +02:00
|
|
|
}
|
|
|
|
|
|
2014-09-19 16:51:07 -04:00
|
|
|
/**
|
|
|
|
|
* nm_utils_wifi_strength_bars:
|
|
|
|
|
* @strength: the access point strength, from 0 to 100
|
|
|
|
|
*
|
|
|
|
|
* Converts @strength into a 4-character-wide graphical representation of
|
2017-12-15 16:46:07 +01:00
|
|
|
* strength suitable for printing to stdout.
|
|
|
|
|
*
|
|
|
|
|
* Previous versions used to take a guess at the terminal type and possibly
|
|
|
|
|
* return a wide UTF-8 encoded string. Now it always returns a 7-bit
|
|
|
|
|
* clean strings of one to 0 to 4 asterisks. Users that actually need
|
|
|
|
|
* the functionality are encouraged to make their implementations instead.
|
2014-09-19 16:51:07 -04:00
|
|
|
*
|
|
|
|
|
* Returns: the graphical representation of the access point strength
|
|
|
|
|
*/
|
|
|
|
|
const char *
|
|
|
|
|
nm_utils_wifi_strength_bars(guint8 strength)
|
|
|
|
|
{
|
|
|
|
|
if (strength > 80)
|
2017-12-15 16:46:07 +01:00
|
|
|
return "****";
|
2014-09-19 16:51:07 -04:00
|
|
|
else if (strength > 55)
|
2017-12-15 16:46:07 +01:00
|
|
|
return "*** ";
|
2014-09-19 16:51:07 -04:00
|
|
|
else if (strength > 30)
|
2017-12-15 16:46:07 +01:00
|
|
|
return "** ";
|
2014-09-19 16:51:07 -04:00
|
|
|
else if (strength > 5)
|
2017-12-15 16:46:07 +01:00
|
|
|
return "* ";
|
2014-09-19 16:51:07 -04:00
|
|
|
else
|
2017-12-15 16:46:07 +01:00
|
|
|
return " ";
|
2014-09-19 16:51:07 -04:00
|
|
|
}
|
|
|
|
|
|
2021-07-14 13:22:40 +02:00
|
|
|
gboolean
|
|
|
|
|
_nm_property_variant_to_gvalue(GVariant *src_value, GValue *dst_value)
|
|
|
|
|
{
|
|
|
|
|
GValue tmp = G_VALUE_INIT;
|
|
|
|
|
gboolean success;
|
|
|
|
|
|
|
|
|
|
g_dbus_gvariant_to_gvalue(src_value, &tmp);
|
|
|
|
|
if (G_VALUE_TYPE(&tmp) == G_VALUE_TYPE(dst_value)) {
|
|
|
|
|
*dst_value = tmp;
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
success = g_value_transform(&tmp, dst_value);
|
|
|
|
|
g_value_unset(&tmp);
|
|
|
|
|
return success;
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
/**
|
|
|
|
|
* nm_utils_hwaddr_len:
|
2014-12-18 12:44:57 -05:00
|
|
|
* @type: the type of address; either <literal>ARPHRD_ETHER</literal> or
|
|
|
|
|
* <literal>ARPHRD_INFINIBAND</literal>
|
2014-07-24 08:53:33 -04:00
|
|
|
*
|
|
|
|
|
* Returns the length in octets of a hardware address of type @type.
|
|
|
|
|
*
|
2020-09-23 12:24:56 +02:00
|
|
|
* Before 1.28, it was an error to call this function with any value other than
|
2014-12-18 12:44:57 -05:00
|
|
|
* <literal>ARPHRD_ETHER</literal> or <literal>ARPHRD_INFINIBAND</literal>.
|
2014-07-04 15:59:19 -04:00
|
|
|
*
|
2023-03-02 11:59:17 +01:00
|
|
|
* Returns: the length or zero if the type is unrecognized.
|
2014-07-24 08:53:33 -04:00
|
|
|
*/
|
2014-07-04 15:59:19 -04:00
|
|
|
gsize
|
2014-07-24 08:53:33 -04:00
|
|
|
nm_utils_hwaddr_len(int type)
|
|
|
|
|
{
|
2020-09-23 12:24:56 +02:00
|
|
|
switch (type) {
|
|
|
|
|
case ARPHRD_ETHER:
|
2014-07-24 08:53:33 -04:00
|
|
|
return ETH_ALEN;
|
2020-09-23 12:24:56 +02:00
|
|
|
case ARPHRD_INFINIBAND:
|
2014-07-24 08:53:33 -04:00
|
|
|
return INFINIBAND_ALEN;
|
2020-09-23 12:24:56 +02:00
|
|
|
default:
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
|
|
|
|
|
2016-11-13 15:54:28 +01:00
|
|
|
/**
|
|
|
|
|
* nm_utils_hexstr2bin:
|
|
|
|
|
* @hex: a string of hexadecimal characters with optional ':' separators
|
|
|
|
|
*
|
|
|
|
|
* Converts a hexadecimal string @hex into an array of bytes. The optional
|
|
|
|
|
* separator ':' may be used between single or pairs of hexadecimal characters,
|
|
|
|
|
* eg "00:11" or "0:1". Any "0x" at the beginning of @hex is ignored. @hex
|
|
|
|
|
* may not start or end with ':'.
|
|
|
|
|
*
|
2023-03-02 11:59:17 +01:00
|
|
|
* Returns: (transfer full): the converted bytes, or %NULL on error
|
2016-11-13 15:54:28 +01:00
|
|
|
*/
|
|
|
|
|
GBytes *
|
|
|
|
|
nm_utils_hexstr2bin(const char *hex)
|
|
|
|
|
{
|
2016-11-27 14:47:07 +01:00
|
|
|
guint8 *buffer;
|
2018-09-27 16:29:55 +02:00
|
|
|
gsize len;
|
2016-11-13 15:54:28 +01:00
|
|
|
|
2019-02-21 10:02:28 +01:00
|
|
|
buffer = nm_utils_hexstr2bin_alloc(hex, TRUE, FALSE, ":", 0, &len);
|
2018-09-27 16:29:55 +02:00
|
|
|
if (!buffer)
|
2016-11-27 14:47:07 +01:00
|
|
|
return NULL;
|
|
|
|
|
buffer = g_realloc(buffer, len);
|
|
|
|
|
return g_bytes_new_take(buffer, len);
|
2016-11-13 15:54:28 +01:00
|
|
|
}
|
|
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
/**
|
|
|
|
|
* nm_utils_hwaddr_atoba:
|
|
|
|
|
* @asc: the ASCII representation of a hardware address
|
2014-07-04 15:59:19 -04:00
|
|
|
* @length: the expected length in bytes of the result
|
2014-07-24 08:53:33 -04:00
|
|
|
*
|
|
|
|
|
* Parses @asc and converts it to binary form in a #GByteArray. See
|
|
|
|
|
* nm_utils_hwaddr_aton() if you don't want a #GByteArray.
|
|
|
|
|
*
|
2023-03-02 11:59:17 +01:00
|
|
|
* Returns: (transfer full): a new #GByteArray, or %NULL if @asc couldn't
|
2014-07-24 08:53:33 -04:00
|
|
|
* be parsed
|
|
|
|
|
*/
|
|
|
|
|
GByteArray *
|
2014-07-04 15:59:19 -04:00
|
|
|
nm_utils_hwaddr_atoba(const char *asc, gsize length)
|
2014-07-24 08:53:33 -04:00
|
|
|
{
|
|
|
|
|
GByteArray *ba;
|
|
|
|
|
|
2016-10-13 17:51:07 +02:00
|
|
|
g_return_val_if_fail(asc, NULL);
|
2014-07-04 15:59:19 -04:00
|
|
|
g_return_val_if_fail(length > 0 && length <= NM_UTILS_HWADDR_LEN_MAX, NULL);
|
2014-07-24 08:53:33 -04:00
|
|
|
|
2014-07-04 15:59:19 -04:00
|
|
|
ba = g_byte_array_sized_new(length);
|
|
|
|
|
g_byte_array_set_size(ba, length);
|
2021-01-08 19:01:28 +01:00
|
|
|
if (!_nm_utils_hwaddr_aton_exact(asc, ba->data, length))
|
2016-10-13 17:51:07 +02:00
|
|
|
goto fail;
|
2014-07-24 08:53:33 -04:00
|
|
|
|
|
|
|
|
return ba;
|
2016-10-13 17:51:07 +02:00
|
|
|
fail:
|
|
|
|
|
g_byte_array_unref(ba);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
/**
|
2014-07-04 15:59:19 -04:00
|
|
|
* nm_utils_hwaddr_aton:
|
2014-07-24 08:53:33 -04:00
|
|
|
* @asc: the ASCII representation of a hardware address
|
2018-03-24 15:18:21 +00:00
|
|
|
* @buffer: (type guint8) (array length=length): buffer to store the result into
|
2014-07-24 08:53:33 -04:00
|
|
|
* @length: the expected length in bytes of the result and
|
|
|
|
|
* the size of the buffer in bytes.
|
|
|
|
|
*
|
|
|
|
|
* Parses @asc and converts it to binary form in @buffer.
|
2020-07-04 11:37:01 +03:00
|
|
|
* Bytes in @asc can be separated by colons (:), or hyphens (-), but not mixed.
|
2014-07-24 08:53:33 -04:00
|
|
|
*
|
2023-03-02 11:59:17 +01:00
|
|
|
* Returns: @buffer, or %NULL if @asc couldn't be parsed
|
2014-07-24 08:53:33 -04:00
|
|
|
* or would be shorter or longer than @length.
|
|
|
|
|
*/
|
|
|
|
|
guint8 *
|
2014-07-04 15:59:19 -04:00
|
|
|
nm_utils_hwaddr_aton(const char *asc, gpointer buffer, gsize length)
|
2014-07-24 08:53:33 -04:00
|
|
|
{
|
2016-10-13 17:51:07 +02:00
|
|
|
g_return_val_if_fail(asc, NULL);
|
|
|
|
|
g_return_val_if_fail(buffer, NULL);
|
2014-07-04 15:59:19 -04:00
|
|
|
g_return_val_if_fail(length > 0 && length <= NM_UTILS_HWADDR_LEN_MAX, NULL);
|
2014-07-24 08:53:33 -04:00
|
|
|
|
2021-01-08 19:01:28 +01:00
|
|
|
return _nm_utils_hwaddr_aton_exact(asc, buffer, length);
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
|
|
|
|
|
2016-11-13 15:54:28 +01:00
|
|
|
/**
|
|
|
|
|
* nm_utils_bin2hexstr:
|
|
|
|
|
* @src: (type guint8) (array length=len): an array of bytes
|
|
|
|
|
* @len: the length of the @src array
|
|
|
|
|
* @final_len: an index where to cut off the returned string, or -1
|
|
|
|
|
*
|
|
|
|
|
* Converts the byte array @src into a hexadecimal string. If @final_len is
|
|
|
|
|
* greater than -1, the returned string is terminated at that index
|
|
|
|
|
* (returned_string[final_len] == '\0'),
|
|
|
|
|
*
|
2023-03-02 11:59:17 +01:00
|
|
|
* Returns: (transfer full): the textual form of @bytes
|
2016-11-13 15:54:28 +01:00
|
|
|
*/
|
|
|
|
|
char *
|
|
|
|
|
nm_utils_bin2hexstr(gconstpointer src, gsize len, int final_len)
|
|
|
|
|
{
|
|
|
|
|
gsize buflen = (len * 2) + 1;
|
|
|
|
|
|
2016-11-27 13:46:42 +01:00
|
|
|
g_return_val_if_fail(src != NULL, NULL);
|
|
|
|
|
g_return_val_if_fail(len > 0 && (buflen - 1) / 2 == len, NULL);
|
|
|
|
|
g_return_val_if_fail(final_len < 0 || (gsize) final_len < buflen, NULL);
|
|
|
|
|
|
2022-03-18 20:27:21 +01:00
|
|
|
return _nm_utils_bin2hexstr(src, len, final_len);
|
2016-11-13 15:54:28 +01:00
|
|
|
}
|
|
|
|
|
|
2016-07-10 13:42:13 +02:00
|
|
|
/**
|
|
|
|
|
* nm_utils_hwaddr_ntoa:
|
|
|
|
|
* @addr: (type guint8) (array length=length): a binary hardware address
|
|
|
|
|
* @length: the length of @addr
|
|
|
|
|
*
|
|
|
|
|
* Converts @addr to textual form.
|
|
|
|
|
*
|
2023-03-02 11:59:17 +01:00
|
|
|
* Returns: (transfer full): the textual form of @addr
|
2016-07-10 13:42:13 +02:00
|
|
|
*/
|
|
|
|
|
char *
|
|
|
|
|
nm_utils_hwaddr_ntoa(gconstpointer addr, gsize length)
|
|
|
|
|
{
|
2016-10-13 17:51:07 +02:00
|
|
|
g_return_val_if_fail(addr, g_strdup(""));
|
|
|
|
|
g_return_val_if_fail(length > 0, g_strdup(""));
|
|
|
|
|
|
2019-01-28 16:56:46 +01:00
|
|
|
return nm_utils_bin2hexstr_full(addr, length, ':', TRUE, NULL);
|
2016-07-10 13:42:13 +02:00
|
|
|
}
|
|
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
/**
|
|
|
|
|
* nm_utils_hwaddr_valid:
|
|
|
|
|
* @asc: the ASCII representation of a hardware address
|
2014-07-04 15:59:19 -04:00
|
|
|
* @length: the length of address that @asc is expected to convert to
|
|
|
|
|
* (or -1 to accept any length up to %NM_UTILS_HWADDR_LEN_MAX)
|
2014-07-24 08:53:33 -04:00
|
|
|
*
|
2014-07-04 15:59:19 -04:00
|
|
|
* Parses @asc to see if it is a valid hardware address of the given
|
|
|
|
|
* length.
|
2014-07-24 08:53:33 -04:00
|
|
|
*
|
2023-03-02 11:59:17 +01:00
|
|
|
* Returns: %TRUE if @asc appears to be a valid hardware address
|
2014-07-04 15:59:19 -04:00
|
|
|
* of the indicated length, %FALSE if not.
|
2014-07-24 08:53:33 -04:00
|
|
|
*/
|
|
|
|
|
gboolean
|
2014-07-04 15:59:19 -04:00
|
|
|
nm_utils_hwaddr_valid(const char *asc, gssize length)
|
2014-07-24 08:53:33 -04:00
|
|
|
{
|
|
|
|
|
guint8 buf[NM_UTILS_HWADDR_LEN_MAX];
|
2016-10-13 17:51:07 +02:00
|
|
|
gsize l;
|
2014-07-24 08:53:33 -04:00
|
|
|
|
2014-07-04 15:59:19 -04:00
|
|
|
g_return_val_if_fail(asc != NULL, FALSE);
|
2020-09-23 11:49:17 +02:00
|
|
|
g_return_val_if_fail(length >= -1 && length <= NM_UTILS_HWADDR_LEN_MAX, FALSE);
|
2014-07-04 15:59:19 -04:00
|
|
|
|
2020-09-23 11:49:17 +02:00
|
|
|
if (length == 0)
|
2018-05-22 20:03:44 +02:00
|
|
|
return FALSE;
|
2020-09-23 11:49:17 +02:00
|
|
|
|
2020-09-23 12:02:49 +02:00
|
|
|
if (!_nm_utils_hwaddr_aton(asc, buf, sizeof(buf), &l))
|
2020-09-23 11:49:17 +02:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
return length == -1 || length == (gssize) l;
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
|
|
|
|
|
2014-10-28 08:32:25 -04:00
|
|
|
/**
|
|
|
|
|
* nm_utils_hwaddr_canonical:
|
|
|
|
|
* @asc: the ASCII representation of a hardware address
|
|
|
|
|
* @length: the length of address that @asc is expected to convert to
|
|
|
|
|
* (or -1 to accept any length up to %NM_UTILS_HWADDR_LEN_MAX)
|
|
|
|
|
*
|
|
|
|
|
* Parses @asc to see if it is a valid hardware address of the given
|
|
|
|
|
* length, and if so, returns it in canonical form (uppercase, with
|
|
|
|
|
* leading 0s as needed, and with colons rather than hyphens).
|
|
|
|
|
*
|
2023-03-02 11:59:17 +01:00
|
|
|
* Returns: (transfer full): the canonicalized address if @asc appears to
|
2014-10-28 08:32:25 -04:00
|
|
|
* be a valid hardware address of the indicated length, %NULL if not.
|
|
|
|
|
*/
|
|
|
|
|
char *
|
|
|
|
|
nm_utils_hwaddr_canonical(const char *asc, gssize length)
|
|
|
|
|
{
|
|
|
|
|
guint8 buf[NM_UTILS_HWADDR_LEN_MAX];
|
2016-10-13 17:51:07 +02:00
|
|
|
gsize l;
|
2014-10-28 08:32:25 -04:00
|
|
|
|
2016-10-13 17:51:07 +02:00
|
|
|
g_return_val_if_fail(asc, NULL);
|
2020-09-23 11:49:17 +02:00
|
|
|
g_return_val_if_fail(length == -1 || (length > 0 && length <= NM_UTILS_HWADDR_LEN_MAX), NULL);
|
2014-10-28 08:32:25 -04:00
|
|
|
|
2020-09-23 12:02:49 +02:00
|
|
|
if (!_nm_utils_hwaddr_aton(asc, buf, sizeof(buf), &l))
|
2020-09-23 11:49:17 +02:00
|
|
|
return NULL;
|
|
|
|
|
if (length != -1 && length != (gssize) l)
|
|
|
|
|
return NULL;
|
2016-10-13 17:51:07 +02:00
|
|
|
return nm_utils_hwaddr_ntoa(buf, l);
|
2014-10-28 08:32:25 -04:00
|
|
|
}
|
|
|
|
|
|
2014-10-28 08:56:07 -04:00
|
|
|
/* This is used to possibly canonicalize values passed to MAC address property
|
|
|
|
|
* setters. Unlike nm_utils_hwaddr_canonical(), it accepts %NULL, and if you
|
|
|
|
|
* pass it an invalid MAC address, it just returns that string rather than
|
|
|
|
|
* returning %NULL (so that we can return a proper error from verify() later).
|
|
|
|
|
*/
|
|
|
|
|
char *
|
|
|
|
|
_nm_utils_hwaddr_canonical_or_invalid(const char *mac, gssize length)
|
|
|
|
|
{
|
|
|
|
|
char *canonical;
|
|
|
|
|
|
|
|
|
|
if (!mac)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
canonical = nm_utils_hwaddr_canonical(mac, length);
|
|
|
|
|
if (canonical)
|
|
|
|
|
return canonical;
|
|
|
|
|
else
|
|
|
|
|
return g_strdup(mac);
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-14 07:40:35 +02:00
|
|
|
char *
|
2022-01-05 13:37:12 +01:00
|
|
|
_nm_utils_ipaddr_canonical_or_invalid(int addr_family, const char *ip, gboolean map_zero_to_null)
|
2021-07-14 07:40:35 +02:00
|
|
|
{
|
|
|
|
|
NMIPAddr addr_bin;
|
|
|
|
|
|
2022-01-05 13:18:44 +01:00
|
|
|
nm_assert_addr_family_or_unspec(addr_family);
|
2021-07-14 07:40:35 +02:00
|
|
|
|
|
|
|
|
if (!ip)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
glib-aux: rename IP address related helpers from "nm-inet-utils.h"
- name things related to `in_addr_t`, `struct in6_addr`, `NMIPAddr` as
`nm_ip4_addr_*()`, `nm_ip6_addr_*()`, `nm_ip_addr_*()`, respectively.
- we have a wrapper `nm_inet_ntop()` for `inet_ntop()`. This name
of our wrapper is chosen to be familiar with the libc underlying
function. With this, also name functions that are about string
representations of addresses `nm_inet_*()`, `nm_inet4_*()`,
`nm_inet6_*()`. For example, `nm_inet_parse_str()`,
`nm_inet_is_normalized()`.
<<<<
R() {
git grep -l "$1" | xargs sed -i "s/\<$1\>/$2/g"
}
R NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX NM_CMP_DIRECT_IP4_ADDR_SAME_PREFIX
R NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX NM_CMP_DIRECT_IP6_ADDR_SAME_PREFIX
R NM_UTILS_INET_ADDRSTRLEN NM_INET_ADDRSTRLEN
R _nm_utils_inet4_ntop nm_inet4_ntop
R _nm_utils_inet6_ntop nm_inet6_ntop
R _nm_utils_ip4_get_default_prefix nm_ip4_addr_get_default_prefix
R _nm_utils_ip4_get_default_prefix0 nm_ip4_addr_get_default_prefix0
R _nm_utils_ip4_netmask_to_prefix nm_ip4_addr_netmask_to_prefix
R _nm_utils_ip4_prefix_to_netmask nm_ip4_addr_netmask_from_prefix
R nm_utils_inet4_ntop_dup nm_inet4_ntop_dup
R nm_utils_inet6_ntop_dup nm_inet6_ntop_dup
R nm_utils_inet_ntop nm_inet_ntop
R nm_utils_inet_ntop_dup nm_inet_ntop_dup
R nm_utils_ip4_address_clear_host_address nm_ip4_addr_clear_host_address
R nm_utils_ip4_address_is_link_local nm_ip4_addr_is_link_local
R nm_utils_ip4_address_is_loopback nm_ip4_addr_is_loopback
R nm_utils_ip4_address_is_zeronet nm_ip4_addr_is_zeronet
R nm_utils_ip4_address_same_prefix nm_ip4_addr_same_prefix
R nm_utils_ip4_address_same_prefix_cmp nm_ip4_addr_same_prefix_cmp
R nm_utils_ip6_address_clear_host_address nm_ip6_addr_clear_host_address
R nm_utils_ip6_address_same_prefix nm_ip6_addr_same_prefix
R nm_utils_ip6_address_same_prefix_cmp nm_ip6_addr_same_prefix_cmp
R nm_utils_ip6_is_ula nm_ip6_addr_is_ula
R nm_utils_ip_address_same_prefix nm_ip_addr_same_prefix
R nm_utils_ip_address_same_prefix_cmp nm_ip_addr_same_prefix_cmp
R nm_utils_ip_is_site_local nm_ip_addr_is_site_local
R nm_utils_ipaddr_is_normalized nm_inet_is_normalized
R nm_utils_ipaddr_is_valid nm_inet_is_valid
R nm_utils_ipx_address_clear_host_address nm_ip_addr_clear_host_address
R nm_utils_parse_inaddr nm_inet_parse_str
R nm_utils_parse_inaddr_bin nm_inet_parse_bin
R nm_utils_parse_inaddr_bin_full nm_inet_parse_bin_full
R nm_utils_parse_inaddr_prefix nm_inet_parse_with_prefix_str
R nm_utils_parse_inaddr_prefix_bin nm_inet_parse_with_prefix_bin
R test_nm_utils_ip6_address_same_prefix test_nm_ip_addr_same_prefix
./contrib/scripts/nm-code-format.sh -F
2022-08-19 13:15:20 +02:00
|
|
|
if (!nm_inet_parse_bin(addr_family, ip, &addr_family, &addr_bin))
|
2021-07-14 07:40:35 +02:00
|
|
|
return g_strdup(ip);
|
|
|
|
|
|
2022-01-05 13:37:12 +01:00
|
|
|
if (map_zero_to_null && nm_ip_addr_is_null(addr_family, &addr_bin))
|
2021-07-14 07:40:35 +02:00
|
|
|
return NULL;
|
|
|
|
|
|
glib-aux: rename IP address related helpers from "nm-inet-utils.h"
- name things related to `in_addr_t`, `struct in6_addr`, `NMIPAddr` as
`nm_ip4_addr_*()`, `nm_ip6_addr_*()`, `nm_ip_addr_*()`, respectively.
- we have a wrapper `nm_inet_ntop()` for `inet_ntop()`. This name
of our wrapper is chosen to be familiar with the libc underlying
function. With this, also name functions that are about string
representations of addresses `nm_inet_*()`, `nm_inet4_*()`,
`nm_inet6_*()`. For example, `nm_inet_parse_str()`,
`nm_inet_is_normalized()`.
<<<<
R() {
git grep -l "$1" | xargs sed -i "s/\<$1\>/$2/g"
}
R NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX NM_CMP_DIRECT_IP4_ADDR_SAME_PREFIX
R NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX NM_CMP_DIRECT_IP6_ADDR_SAME_PREFIX
R NM_UTILS_INET_ADDRSTRLEN NM_INET_ADDRSTRLEN
R _nm_utils_inet4_ntop nm_inet4_ntop
R _nm_utils_inet6_ntop nm_inet6_ntop
R _nm_utils_ip4_get_default_prefix nm_ip4_addr_get_default_prefix
R _nm_utils_ip4_get_default_prefix0 nm_ip4_addr_get_default_prefix0
R _nm_utils_ip4_netmask_to_prefix nm_ip4_addr_netmask_to_prefix
R _nm_utils_ip4_prefix_to_netmask nm_ip4_addr_netmask_from_prefix
R nm_utils_inet4_ntop_dup nm_inet4_ntop_dup
R nm_utils_inet6_ntop_dup nm_inet6_ntop_dup
R nm_utils_inet_ntop nm_inet_ntop
R nm_utils_inet_ntop_dup nm_inet_ntop_dup
R nm_utils_ip4_address_clear_host_address nm_ip4_addr_clear_host_address
R nm_utils_ip4_address_is_link_local nm_ip4_addr_is_link_local
R nm_utils_ip4_address_is_loopback nm_ip4_addr_is_loopback
R nm_utils_ip4_address_is_zeronet nm_ip4_addr_is_zeronet
R nm_utils_ip4_address_same_prefix nm_ip4_addr_same_prefix
R nm_utils_ip4_address_same_prefix_cmp nm_ip4_addr_same_prefix_cmp
R nm_utils_ip6_address_clear_host_address nm_ip6_addr_clear_host_address
R nm_utils_ip6_address_same_prefix nm_ip6_addr_same_prefix
R nm_utils_ip6_address_same_prefix_cmp nm_ip6_addr_same_prefix_cmp
R nm_utils_ip6_is_ula nm_ip6_addr_is_ula
R nm_utils_ip_address_same_prefix nm_ip_addr_same_prefix
R nm_utils_ip_address_same_prefix_cmp nm_ip_addr_same_prefix_cmp
R nm_utils_ip_is_site_local nm_ip_addr_is_site_local
R nm_utils_ipaddr_is_normalized nm_inet_is_normalized
R nm_utils_ipaddr_is_valid nm_inet_is_valid
R nm_utils_ipx_address_clear_host_address nm_ip_addr_clear_host_address
R nm_utils_parse_inaddr nm_inet_parse_str
R nm_utils_parse_inaddr_bin nm_inet_parse_bin
R nm_utils_parse_inaddr_bin_full nm_inet_parse_bin_full
R nm_utils_parse_inaddr_prefix nm_inet_parse_with_prefix_str
R nm_utils_parse_inaddr_prefix_bin nm_inet_parse_with_prefix_bin
R test_nm_utils_ip6_address_same_prefix test_nm_ip_addr_same_prefix
./contrib/scripts/nm-code-format.sh -F
2022-08-19 13:15:20 +02:00
|
|
|
return nm_inet_ntop_dup(addr_family, &addr_bin);
|
2021-07-14 07:40:35 +02:00
|
|
|
}
|
|
|
|
|
|
2020-03-23 19:29:24 +01:00
|
|
|
/*
|
|
|
|
|
* Determine if given Ethernet address is link-local
|
|
|
|
|
*
|
2023-03-02 11:59:17 +01:00
|
|
|
* Returns: %TRUE if @mac is link local
|
2020-03-23 19:29:24 +01:00
|
|
|
* reserved addr (01:80:c2:00:00:0X) per IEEE 802.1Q 8.6.3 Frame filtering, %FALSE if not.
|
|
|
|
|
*/
|
|
|
|
|
gboolean
|
|
|
|
|
_nm_utils_hwaddr_link_local_valid(const char *mac)
|
|
|
|
|
{
|
|
|
|
|
guint8 mac_net[ETH_ALEN];
|
|
|
|
|
static const guint8 eth_reserved_addr_base[] = {0x01, 0x80, 0xc2, 0x00, 0x00};
|
|
|
|
|
|
|
|
|
|
if (!mac)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (!nm_utils_hwaddr_aton(mac, mac_net, ETH_ALEN))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (memcmp(mac_net, eth_reserved_addr_base, ETH_ALEN - 1) || (mac_net[5] & 0xF0))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (mac_net[5] == 1 /* 802.3x Pause address */
|
|
|
|
|
|| mac_net[5] == 2 /* 802.3ad Slow protocols */
|
|
|
|
|
|| mac_net[5] == 3) /* 802.1X PAE address */
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-16 11:30:47 -04:00
|
|
|
/**
|
|
|
|
|
* nm_utils_hwaddr_matches:
|
2018-03-24 15:18:21 +00:00
|
|
|
* @hwaddr1: (nullable): pointer to a binary or ASCII hardware address, or %NULL
|
2014-06-16 11:30:47 -04:00
|
|
|
* @hwaddr1_len: size of @hwaddr1, or -1 if @hwaddr1 is ASCII
|
2018-03-24 15:18:21 +00:00
|
|
|
* @hwaddr2: (nullable): pointer to a binary or ASCII hardware address, or %NULL
|
2014-06-16 11:30:47 -04:00
|
|
|
* @hwaddr2_len: size of @hwaddr2, or -1 if @hwaddr2 is ASCII
|
|
|
|
|
*
|
|
|
|
|
* Generalized hardware address comparison function. Tests if @hwaddr1 and
|
|
|
|
|
* @hwaddr2 "equal" (or more precisely, "equivalent"), with several advantages
|
|
|
|
|
* over a simple memcmp():
|
|
|
|
|
*
|
|
|
|
|
* 1. If @hwaddr1_len or @hwaddr2_len is -1, then the corresponding address is
|
|
|
|
|
* assumed to be ASCII rather than binary, and will be converted to binary
|
|
|
|
|
* before being compared.
|
|
|
|
|
*
|
|
|
|
|
* 2. If @hwaddr1 or @hwaddr2 is %NULL, it is treated instead as though it was
|
|
|
|
|
* a zero-filled buffer @hwaddr1_len or @hwaddr2_len bytes long.
|
|
|
|
|
*
|
|
|
|
|
* 3. If @hwaddr1 and @hwaddr2 are InfiniBand hardware addresses (that is, if
|
2014-12-18 12:44:57 -05:00
|
|
|
* they are <literal>INFINIBAND_ALEN</literal> bytes long in binary form)
|
|
|
|
|
* then only the last 8 bytes are compared, since those are the only bytes
|
|
|
|
|
* that actually identify the hardware. (The other 12 bytes will change
|
|
|
|
|
* depending on the configuration of the InfiniBand fabric that the device
|
|
|
|
|
* is connected to.)
|
2014-06-16 11:30:47 -04:00
|
|
|
*
|
|
|
|
|
* If a passed-in ASCII hardware address cannot be parsed, or would parse to an
|
|
|
|
|
* address larger than %NM_UTILS_HWADDR_LEN_MAX, then it will silently fail to
|
|
|
|
|
* match. (This means that externally-provided address strings do not need to be
|
|
|
|
|
* sanity-checked before comparing them against known good addresses; they are
|
|
|
|
|
* guaranteed to not match if they are invalid.)
|
|
|
|
|
*
|
2023-03-02 11:59:17 +01:00
|
|
|
* Returns: %TRUE if @hwaddr1 and @hwaddr2 are equivalent, %FALSE if they are
|
2014-06-16 11:30:47 -04:00
|
|
|
* different (or either of them is invalid).
|
|
|
|
|
*/
|
|
|
|
|
gboolean
|
|
|
|
|
nm_utils_hwaddr_matches(gconstpointer hwaddr1,
|
|
|
|
|
gssize hwaddr1_len,
|
|
|
|
|
gconstpointer hwaddr2,
|
|
|
|
|
gssize hwaddr2_len)
|
|
|
|
|
{
|
|
|
|
|
guint8 buf1[NM_UTILS_HWADDR_LEN_MAX], buf2[NM_UTILS_HWADDR_LEN_MAX];
|
2016-10-13 17:51:07 +02:00
|
|
|
gsize l;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-06-16 11:30:47 -04:00
|
|
|
if (hwaddr1_len == -1) {
|
2019-11-14 15:08:31 +01:00
|
|
|
if (hwaddr1 == NULL) {
|
|
|
|
|
hwaddr1_len = 0;
|
2020-09-23 12:02:49 +02:00
|
|
|
} else if (_nm_utils_hwaddr_aton(hwaddr1, buf1, sizeof(buf1), &l)) {
|
2019-11-14 15:08:31 +01:00
|
|
|
hwaddr1 = buf1;
|
|
|
|
|
hwaddr1_len = l;
|
|
|
|
|
} else {
|
libnm: don't compare invalid mac addresses as equal in nm_utils_hwaddr_matches()
By passing as length of the MAC addresses -1 for both arguments, one
could get through to compare empty strings, NULL, and addresses longer
than the maximum. Such addresses are not valid, and they should never
compare equal (not even to themselves).
This is a change in behavior of public API, but it never made sense to
claim two addresses are equal, when they are not even valid addresses.
Also, avoid undefined behavior with "NULL, -1, NULL, -1" arguments,
where we would call memcmp() with zero length and NULL arguments.
UBSan flags that too.
2020-05-13 22:48:34 +02:00
|
|
|
g_return_val_if_fail(hwaddr2_len == -1
|
|
|
|
|
|| (hwaddr2_len > 0 && hwaddr2_len <= NM_UTILS_HWADDR_LEN_MAX),
|
|
|
|
|
FALSE);
|
2014-06-16 11:30:47 -04:00
|
|
|
return FALSE;
|
2016-10-13 17:51:07 +02:00
|
|
|
}
|
2014-06-16 11:30:47 -04:00
|
|
|
} else {
|
|
|
|
|
g_return_val_if_fail(hwaddr1_len > 0 && hwaddr1_len <= NM_UTILS_HWADDR_LEN_MAX, FALSE);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-06-16 11:30:47 -04:00
|
|
|
if (!hwaddr1) {
|
|
|
|
|
memset(buf1, 0, hwaddr1_len);
|
|
|
|
|
hwaddr1 = buf1;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
}
|
|
|
|
|
|
2014-06-16 11:30:47 -04:00
|
|
|
if (hwaddr2_len == -1) {
|
2019-11-14 15:08:31 +01:00
|
|
|
if (hwaddr2 == NULL)
|
|
|
|
|
l = 0;
|
2020-09-23 12:02:49 +02:00
|
|
|
else if (!_nm_utils_hwaddr_aton(hwaddr2, buf2, sizeof(buf2), &l))
|
2016-10-13 17:51:07 +02:00
|
|
|
return FALSE;
|
|
|
|
|
if (l != hwaddr1_len)
|
2014-06-16 11:30:47 -04:00
|
|
|
return FALSE;
|
|
|
|
|
hwaddr2 = buf2;
|
|
|
|
|
} else {
|
|
|
|
|
g_return_val_if_fail(hwaddr2_len > 0 && hwaddr2_len <= NM_UTILS_HWADDR_LEN_MAX, FALSE);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2016-10-13 17:51:07 +02:00
|
|
|
if (hwaddr2_len != hwaddr1_len)
|
|
|
|
|
return FALSE;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-06-16 11:30:47 -04:00
|
|
|
if (!hwaddr2) {
|
|
|
|
|
memset(buf2, 0, hwaddr2_len);
|
|
|
|
|
hwaddr2 = buf2;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
}
|
|
|
|
|
|
libnm: don't compare invalid mac addresses as equal in nm_utils_hwaddr_matches()
By passing as length of the MAC addresses -1 for both arguments, one
could get through to compare empty strings, NULL, and addresses longer
than the maximum. Such addresses are not valid, and they should never
compare equal (not even to themselves).
This is a change in behavior of public API, but it never made sense to
claim two addresses are equal, when they are not even valid addresses.
Also, avoid undefined behavior with "NULL, -1, NULL, -1" arguments,
where we would call memcmp() with zero length and NULL arguments.
UBSan flags that too.
2020-05-13 22:48:34 +02:00
|
|
|
if (G_UNLIKELY(hwaddr1_len <= 0 || hwaddr1_len > NM_UTILS_HWADDR_LEN_MAX)) {
|
|
|
|
|
/* Only valid addresses can compare equal. In particular,
|
|
|
|
|
* addresses that are too long or of zero bytes, never
|
|
|
|
|
* compare equal. */
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-16 11:30:47 -04:00
|
|
|
if (hwaddr1_len == INFINIBAND_ALEN) {
|
libnm: don't compare invalid mac addresses as equal in nm_utils_hwaddr_matches()
By passing as length of the MAC addresses -1 for both arguments, one
could get through to compare empty strings, NULL, and addresses longer
than the maximum. Such addresses are not valid, and they should never
compare equal (not even to themselves).
This is a change in behavior of public API, but it never made sense to
claim two addresses are equal, when they are not even valid addresses.
Also, avoid undefined behavior with "NULL, -1, NULL, -1" arguments,
where we would call memcmp() with zero length and NULL arguments.
UBSan flags that too.
2020-05-13 22:48:34 +02:00
|
|
|
hwaddr1 = &((guint8 *) hwaddr1)[INFINIBAND_ALEN - 8];
|
|
|
|
|
hwaddr2 = &((guint8 *) hwaddr2)[INFINIBAND_ALEN - 8];
|
2016-12-13 18:23:24 +01:00
|
|
|
hwaddr1_len = 8;
|
2014-06-16 11:30:47 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return !memcmp(hwaddr1, hwaddr2, hwaddr1_len);
|
|
|
|
|
}
|
|
|
|
|
|
device: extend MAC address handling including randomization for ethernet and wifi
Extend the "ethernet.cloned-mac-address" and "wifi.cloned-mac-address"
settings. Instead of specifying an explicit MAC address, the additional
special values "permanent", "preserve", "random", "random-bia", "stable" and
"stable-bia" are supported.
"permanent" means to use the permanent hardware address. Previously that
was the default if no explict cloned-mac-address was set. The default is
thus still "permanent", but it can be overwritten by global
configuration.
"preserve" means not to configure the MAC address when activating the
device. That was actually the default behavior before introducing MAC
address handling with commit 1b49f941a69af910b0e68530be7339e8053068e5.
"random" and "random-bia" use a randomized MAC address for each
connection. "stable" and "stable-bia" use a generated, stable
address based on some token. The "bia" suffix says to generate a
burned-in address. The stable method by default uses as token the
connection UUID, but the token can be explicitly choosen via
"stable:<TOKEN>" and "stable-bia:<TOKEN>".
On a D-Bus level, the "cloned-mac-address" is a bytestring and thus
cannot express the new forms. It is replaced by the new
"assigned-mac-address" field. For the GObject property, libnm's API,
nmcli, keyfile, etc. the old name "cloned-mac-address" is still used.
Deprecating the old field seems more complicated then just extending
the use of the existing "cloned-mac-address" field, although the name
doesn't match well with the extended meaning.
There is some overlap with the "wifi.mac-address-randomization" setting.
https://bugzilla.gnome.org/show_bug.cgi?id=705545
https://bugzilla.gnome.org/show_bug.cgi?id=708820
https://bugzilla.gnome.org/show_bug.cgi?id=758301
2016-05-24 15:57:16 +02:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2021-06-18 13:18:12 +02:00
|
|
|
GVariant *
|
|
|
|
|
nm_utils_hwaddr_to_dbus(const char *str)
|
2014-07-30 10:57:45 -04:00
|
|
|
{
|
2014-08-16 10:09:48 -04:00
|
|
|
guint8 buf[NM_UTILS_HWADDR_LEN_MAX];
|
2016-10-13 17:51:07 +02:00
|
|
|
gsize len;
|
2014-08-16 10:09:48 -04:00
|
|
|
|
2016-06-08 00:56:13 +02:00
|
|
|
if (!str)
|
|
|
|
|
return NULL;
|
2020-09-23 12:02:49 +02:00
|
|
|
if (!_nm_utils_hwaddr_aton(str, buf, sizeof(buf), &len))
|
2016-06-08 00:56:13 +02:00
|
|
|
return NULL;
|
2014-07-30 10:57:45 -04:00
|
|
|
|
2021-04-15 09:17:47 +02:00
|
|
|
return nm_g_variant_new_ay(buf, len);
|
2014-07-30 10:57:45 -04:00
|
|
|
}
|
|
|
|
|
|
2021-06-29 14:37:16 +02:00
|
|
|
GVariant *
|
2022-10-21 14:50:27 +02:00
|
|
|
_nm_sett_info_prop_to_dbus_fcn_cloned_mac_address(_NM_SETT_INFO_PROP_TO_DBUS_FCN_ARGS _nm_nil)
|
device: extend MAC address handling including randomization for ethernet and wifi
Extend the "ethernet.cloned-mac-address" and "wifi.cloned-mac-address"
settings. Instead of specifying an explicit MAC address, the additional
special values "permanent", "preserve", "random", "random-bia", "stable" and
"stable-bia" are supported.
"permanent" means to use the permanent hardware address. Previously that
was the default if no explict cloned-mac-address was set. The default is
thus still "permanent", but it can be overwritten by global
configuration.
"preserve" means not to configure the MAC address when activating the
device. That was actually the default behavior before introducing MAC
address handling with commit 1b49f941a69af910b0e68530be7339e8053068e5.
"random" and "random-bia" use a randomized MAC address for each
connection. "stable" and "stable-bia" use a generated, stable
address based on some token. The "bia" suffix says to generate a
burned-in address. The stable method by default uses as token the
connection UUID, but the token can be explicitly choosen via
"stable:<TOKEN>" and "stable-bia:<TOKEN>".
On a D-Bus level, the "cloned-mac-address" is a bytestring and thus
cannot express the new forms. It is replaced by the new
"assigned-mac-address" field. For the GObject property, libnm's API,
nmcli, keyfile, etc. the old name "cloned-mac-address" is still used.
Deprecating the old field seems more complicated then just extending
the use of the existing "cloned-mac-address" field, although the name
doesn't match well with the extended meaning.
There is some overlap with the "wifi.mac-address-randomization" setting.
https://bugzilla.gnome.org/show_bug.cgi?id=705545
https://bugzilla.gnome.org/show_bug.cgi?id=708820
https://bugzilla.gnome.org/show_bug.cgi?id=758301
2016-05-24 15:57:16 +02:00
|
|
|
{
|
|
|
|
|
gs_free char *addr = NULL;
|
|
|
|
|
|
2021-06-29 12:04:00 +02:00
|
|
|
nm_assert(nm_streq(property_info->name, "cloned-mac-address"));
|
device: extend MAC address handling including randomization for ethernet and wifi
Extend the "ethernet.cloned-mac-address" and "wifi.cloned-mac-address"
settings. Instead of specifying an explicit MAC address, the additional
special values "permanent", "preserve", "random", "random-bia", "stable" and
"stable-bia" are supported.
"permanent" means to use the permanent hardware address. Previously that
was the default if no explict cloned-mac-address was set. The default is
thus still "permanent", but it can be overwritten by global
configuration.
"preserve" means not to configure the MAC address when activating the
device. That was actually the default behavior before introducing MAC
address handling with commit 1b49f941a69af910b0e68530be7339e8053068e5.
"random" and "random-bia" use a randomized MAC address for each
connection. "stable" and "stable-bia" use a generated, stable
address based on some token. The "bia" suffix says to generate a
burned-in address. The stable method by default uses as token the
connection UUID, but the token can be explicitly choosen via
"stable:<TOKEN>" and "stable-bia:<TOKEN>".
On a D-Bus level, the "cloned-mac-address" is a bytestring and thus
cannot express the new forms. It is replaced by the new
"assigned-mac-address" field. For the GObject property, libnm's API,
nmcli, keyfile, etc. the old name "cloned-mac-address" is still used.
Deprecating the old field seems more complicated then just extending
the use of the existing "cloned-mac-address" field, although the name
doesn't match well with the extended meaning.
There is some overlap with the "wifi.mac-address-randomization" setting.
https://bugzilla.gnome.org/show_bug.cgi?id=705545
https://bugzilla.gnome.org/show_bug.cgi?id=708820
https://bugzilla.gnome.org/show_bug.cgi?id=758301
2016-05-24 15:57:16 +02:00
|
|
|
|
|
|
|
|
g_object_get(setting, "cloned-mac-address", &addr, NULL);
|
2021-06-18 13:18:12 +02:00
|
|
|
return nm_utils_hwaddr_to_dbus(addr);
|
device: extend MAC address handling including randomization for ethernet and wifi
Extend the "ethernet.cloned-mac-address" and "wifi.cloned-mac-address"
settings. Instead of specifying an explicit MAC address, the additional
special values "permanent", "preserve", "random", "random-bia", "stable" and
"stable-bia" are supported.
"permanent" means to use the permanent hardware address. Previously that
was the default if no explict cloned-mac-address was set. The default is
thus still "permanent", but it can be overwritten by global
configuration.
"preserve" means not to configure the MAC address when activating the
device. That was actually the default behavior before introducing MAC
address handling with commit 1b49f941a69af910b0e68530be7339e8053068e5.
"random" and "random-bia" use a randomized MAC address for each
connection. "stable" and "stable-bia" use a generated, stable
address based on some token. The "bia" suffix says to generate a
burned-in address. The stable method by default uses as token the
connection UUID, but the token can be explicitly choosen via
"stable:<TOKEN>" and "stable-bia:<TOKEN>".
On a D-Bus level, the "cloned-mac-address" is a bytestring and thus
cannot express the new forms. It is replaced by the new
"assigned-mac-address" field. For the GObject property, libnm's API,
nmcli, keyfile, etc. the old name "cloned-mac-address" is still used.
Deprecating the old field seems more complicated then just extending
the use of the existing "cloned-mac-address" field, although the name
doesn't match well with the extended meaning.
There is some overlap with the "wifi.mac-address-randomization" setting.
https://bugzilla.gnome.org/show_bug.cgi?id=705545
https://bugzilla.gnome.org/show_bug.cgi?id=708820
https://bugzilla.gnome.org/show_bug.cgi?id=758301
2016-05-24 15:57:16 +02:00
|
|
|
}
|
|
|
|
|
|
2021-06-29 14:37:16 +02:00
|
|
|
gboolean
|
2022-10-21 14:50:27 +02:00
|
|
|
_nm_sett_info_prop_from_dbus_fcn_cloned_mac_address(_NM_SETT_INFO_PROP_FROM_DBUS_FCN_ARGS _nm_nil)
|
device: extend MAC address handling including randomization for ethernet and wifi
Extend the "ethernet.cloned-mac-address" and "wifi.cloned-mac-address"
settings. Instead of specifying an explicit MAC address, the additional
special values "permanent", "preserve", "random", "random-bia", "stable" and
"stable-bia" are supported.
"permanent" means to use the permanent hardware address. Previously that
was the default if no explict cloned-mac-address was set. The default is
thus still "permanent", but it can be overwritten by global
configuration.
"preserve" means not to configure the MAC address when activating the
device. That was actually the default behavior before introducing MAC
address handling with commit 1b49f941a69af910b0e68530be7339e8053068e5.
"random" and "random-bia" use a randomized MAC address for each
connection. "stable" and "stable-bia" use a generated, stable
address based on some token. The "bia" suffix says to generate a
burned-in address. The stable method by default uses as token the
connection UUID, but the token can be explicitly choosen via
"stable:<TOKEN>" and "stable-bia:<TOKEN>".
On a D-Bus level, the "cloned-mac-address" is a bytestring and thus
cannot express the new forms. It is replaced by the new
"assigned-mac-address" field. For the GObject property, libnm's API,
nmcli, keyfile, etc. the old name "cloned-mac-address" is still used.
Deprecating the old field seems more complicated then just extending
the use of the existing "cloned-mac-address" field, although the name
doesn't match well with the extended meaning.
There is some overlap with the "wifi.mac-address-randomization" setting.
https://bugzilla.gnome.org/show_bug.cgi?id=705545
https://bugzilla.gnome.org/show_bug.cgi?id=708820
https://bugzilla.gnome.org/show_bug.cgi?id=758301
2016-05-24 15:57:16 +02:00
|
|
|
{
|
|
|
|
|
gsize length;
|
|
|
|
|
const guint8 *array;
|
2021-11-09 13:28:54 +01:00
|
|
|
char *str;
|
device: extend MAC address handling including randomization for ethernet and wifi
Extend the "ethernet.cloned-mac-address" and "wifi.cloned-mac-address"
settings. Instead of specifying an explicit MAC address, the additional
special values "permanent", "preserve", "random", "random-bia", "stable" and
"stable-bia" are supported.
"permanent" means to use the permanent hardware address. Previously that
was the default if no explict cloned-mac-address was set. The default is
thus still "permanent", but it can be overwritten by global
configuration.
"preserve" means not to configure the MAC address when activating the
device. That was actually the default behavior before introducing MAC
address handling with commit 1b49f941a69af910b0e68530be7339e8053068e5.
"random" and "random-bia" use a randomized MAC address for each
connection. "stable" and "stable-bia" use a generated, stable
address based on some token. The "bia" suffix says to generate a
burned-in address. The stable method by default uses as token the
connection UUID, but the token can be explicitly choosen via
"stable:<TOKEN>" and "stable-bia:<TOKEN>".
On a D-Bus level, the "cloned-mac-address" is a bytestring and thus
cannot express the new forms. It is replaced by the new
"assigned-mac-address" field. For the GObject property, libnm's API,
nmcli, keyfile, etc. the old name "cloned-mac-address" is still used.
Deprecating the old field seems more complicated then just extending
the use of the existing "cloned-mac-address" field, although the name
doesn't match well with the extended meaning.
There is some overlap with the "wifi.mac-address-randomization" setting.
https://bugzilla.gnome.org/show_bug.cgi?id=705545
https://bugzilla.gnome.org/show_bug.cgi?id=708820
https://bugzilla.gnome.org/show_bug.cgi?id=758301
2016-05-24 15:57:16 +02:00
|
|
|
|
2021-06-29 23:51:46 +02:00
|
|
|
nm_assert(nm_streq0(property_info->name, "cloned-mac-address"));
|
device: extend MAC address handling including randomization for ethernet and wifi
Extend the "ethernet.cloned-mac-address" and "wifi.cloned-mac-address"
settings. Instead of specifying an explicit MAC address, the additional
special values "permanent", "preserve", "random", "random-bia", "stable" and
"stable-bia" are supported.
"permanent" means to use the permanent hardware address. Previously that
was the default if no explict cloned-mac-address was set. The default is
thus still "permanent", but it can be overwritten by global
configuration.
"preserve" means not to configure the MAC address when activating the
device. That was actually the default behavior before introducing MAC
address handling with commit 1b49f941a69af910b0e68530be7339e8053068e5.
"random" and "random-bia" use a randomized MAC address for each
connection. "stable" and "stable-bia" use a generated, stable
address based on some token. The "bia" suffix says to generate a
burned-in address. The stable method by default uses as token the
connection UUID, but the token can be explicitly choosen via
"stable:<TOKEN>" and "stable-bia:<TOKEN>".
On a D-Bus level, the "cloned-mac-address" is a bytestring and thus
cannot express the new forms. It is replaced by the new
"assigned-mac-address" field. For the GObject property, libnm's API,
nmcli, keyfile, etc. the old name "cloned-mac-address" is still used.
Deprecating the old field seems more complicated then just extending
the use of the existing "cloned-mac-address" field, although the name
doesn't match well with the extended meaning.
There is some overlap with the "wifi.mac-address-randomization" setting.
https://bugzilla.gnome.org/show_bug.cgi?id=705545
https://bugzilla.gnome.org/show_bug.cgi?id=708820
https://bugzilla.gnome.org/show_bug.cgi?id=758301
2016-05-24 15:57:16 +02:00
|
|
|
|
|
|
|
|
if (!_nm_setting_use_legacy_property(setting,
|
|
|
|
|
connection_dict,
|
|
|
|
|
"cloned-mac-address",
|
2021-07-27 10:27:44 +02:00
|
|
|
"assigned-mac-address")) {
|
|
|
|
|
*out_is_modified = FALSE;
|
device: extend MAC address handling including randomization for ethernet and wifi
Extend the "ethernet.cloned-mac-address" and "wifi.cloned-mac-address"
settings. Instead of specifying an explicit MAC address, the additional
special values "permanent", "preserve", "random", "random-bia", "stable" and
"stable-bia" are supported.
"permanent" means to use the permanent hardware address. Previously that
was the default if no explict cloned-mac-address was set. The default is
thus still "permanent", but it can be overwritten by global
configuration.
"preserve" means not to configure the MAC address when activating the
device. That was actually the default behavior before introducing MAC
address handling with commit 1b49f941a69af910b0e68530be7339e8053068e5.
"random" and "random-bia" use a randomized MAC address for each
connection. "stable" and "stable-bia" use a generated, stable
address based on some token. The "bia" suffix says to generate a
burned-in address. The stable method by default uses as token the
connection UUID, but the token can be explicitly choosen via
"stable:<TOKEN>" and "stable-bia:<TOKEN>".
On a D-Bus level, the "cloned-mac-address" is a bytestring and thus
cannot express the new forms. It is replaced by the new
"assigned-mac-address" field. For the GObject property, libnm's API,
nmcli, keyfile, etc. the old name "cloned-mac-address" is still used.
Deprecating the old field seems more complicated then just extending
the use of the existing "cloned-mac-address" field, although the name
doesn't match well with the extended meaning.
There is some overlap with the "wifi.mac-address-randomization" setting.
https://bugzilla.gnome.org/show_bug.cgi?id=705545
https://bugzilla.gnome.org/show_bug.cgi?id=708820
https://bugzilla.gnome.org/show_bug.cgi?id=758301
2016-05-24 15:57:16 +02:00
|
|
|
return TRUE;
|
2021-07-27 10:27:44 +02:00
|
|
|
}
|
device: extend MAC address handling including randomization for ethernet and wifi
Extend the "ethernet.cloned-mac-address" and "wifi.cloned-mac-address"
settings. Instead of specifying an explicit MAC address, the additional
special values "permanent", "preserve", "random", "random-bia", "stable" and
"stable-bia" are supported.
"permanent" means to use the permanent hardware address. Previously that
was the default if no explict cloned-mac-address was set. The default is
thus still "permanent", but it can be overwritten by global
configuration.
"preserve" means not to configure the MAC address when activating the
device. That was actually the default behavior before introducing MAC
address handling with commit 1b49f941a69af910b0e68530be7339e8053068e5.
"random" and "random-bia" use a randomized MAC address for each
connection. "stable" and "stable-bia" use a generated, stable
address based on some token. The "bia" suffix says to generate a
burned-in address. The stable method by default uses as token the
connection UUID, but the token can be explicitly choosen via
"stable:<TOKEN>" and "stable-bia:<TOKEN>".
On a D-Bus level, the "cloned-mac-address" is a bytestring and thus
cannot express the new forms. It is replaced by the new
"assigned-mac-address" field. For the GObject property, libnm's API,
nmcli, keyfile, etc. the old name "cloned-mac-address" is still used.
Deprecating the old field seems more complicated then just extending
the use of the existing "cloned-mac-address" field, although the name
doesn't match well with the extended meaning.
There is some overlap with the "wifi.mac-address-randomization" setting.
https://bugzilla.gnome.org/show_bug.cgi?id=705545
https://bugzilla.gnome.org/show_bug.cgi?id=708820
https://bugzilla.gnome.org/show_bug.cgi?id=758301
2016-05-24 15:57:16 +02:00
|
|
|
|
|
|
|
|
length = 0;
|
|
|
|
|
array = g_variant_get_fixed_array(value, &length, 1);
|
|
|
|
|
|
2021-07-27 10:27:44 +02:00
|
|
|
if (!length) {
|
|
|
|
|
*out_is_modified = FALSE;
|
device: extend MAC address handling including randomization for ethernet and wifi
Extend the "ethernet.cloned-mac-address" and "wifi.cloned-mac-address"
settings. Instead of specifying an explicit MAC address, the additional
special values "permanent", "preserve", "random", "random-bia", "stable" and
"stable-bia" are supported.
"permanent" means to use the permanent hardware address. Previously that
was the default if no explict cloned-mac-address was set. The default is
thus still "permanent", but it can be overwritten by global
configuration.
"preserve" means not to configure the MAC address when activating the
device. That was actually the default behavior before introducing MAC
address handling with commit 1b49f941a69af910b0e68530be7339e8053068e5.
"random" and "random-bia" use a randomized MAC address for each
connection. "stable" and "stable-bia" use a generated, stable
address based on some token. The "bia" suffix says to generate a
burned-in address. The stable method by default uses as token the
connection UUID, but the token can be explicitly choosen via
"stable:<TOKEN>" and "stable-bia:<TOKEN>".
On a D-Bus level, the "cloned-mac-address" is a bytestring and thus
cannot express the new forms. It is replaced by the new
"assigned-mac-address" field. For the GObject property, libnm's API,
nmcli, keyfile, etc. the old name "cloned-mac-address" is still used.
Deprecating the old field seems more complicated then just extending
the use of the existing "cloned-mac-address" field, although the name
doesn't match well with the extended meaning.
There is some overlap with the "wifi.mac-address-randomization" setting.
https://bugzilla.gnome.org/show_bug.cgi?id=705545
https://bugzilla.gnome.org/show_bug.cgi?id=708820
https://bugzilla.gnome.org/show_bug.cgi?id=758301
2016-05-24 15:57:16 +02:00
|
|
|
return TRUE;
|
2021-07-27 10:27:44 +02:00
|
|
|
}
|
device: extend MAC address handling including randomization for ethernet and wifi
Extend the "ethernet.cloned-mac-address" and "wifi.cloned-mac-address"
settings. Instead of specifying an explicit MAC address, the additional
special values "permanent", "preserve", "random", "random-bia", "stable" and
"stable-bia" are supported.
"permanent" means to use the permanent hardware address. Previously that
was the default if no explict cloned-mac-address was set. The default is
thus still "permanent", but it can be overwritten by global
configuration.
"preserve" means not to configure the MAC address when activating the
device. That was actually the default behavior before introducing MAC
address handling with commit 1b49f941a69af910b0e68530be7339e8053068e5.
"random" and "random-bia" use a randomized MAC address for each
connection. "stable" and "stable-bia" use a generated, stable
address based on some token. The "bia" suffix says to generate a
burned-in address. The stable method by default uses as token the
connection UUID, but the token can be explicitly choosen via
"stable:<TOKEN>" and "stable-bia:<TOKEN>".
On a D-Bus level, the "cloned-mac-address" is a bytestring and thus
cannot express the new forms. It is replaced by the new
"assigned-mac-address" field. For the GObject property, libnm's API,
nmcli, keyfile, etc. the old name "cloned-mac-address" is still used.
Deprecating the old field seems more complicated then just extending
the use of the existing "cloned-mac-address" field, although the name
doesn't match well with the extended meaning.
There is some overlap with the "wifi.mac-address-randomization" setting.
https://bugzilla.gnome.org/show_bug.cgi?id=705545
https://bugzilla.gnome.org/show_bug.cgi?id=708820
https://bugzilla.gnome.org/show_bug.cgi?id=758301
2016-05-24 15:57:16 +02:00
|
|
|
|
|
|
|
|
str = nm_utils_hwaddr_ntoa(array, length);
|
|
|
|
|
g_object_set(setting, "cloned-mac-address", str, NULL);
|
|
|
|
|
g_free(str);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-29 14:37:16 +02:00
|
|
|
gboolean
|
2022-10-21 14:50:27 +02:00
|
|
|
_nm_sett_info_prop_missing_from_dbus_fcn_cloned_mac_address(
|
|
|
|
|
_NM_SETT_INFO_PROP_MISSING_FROM_DBUS_FCN_ARGS _nm_nil)
|
device: extend MAC address handling including randomization for ethernet and wifi
Extend the "ethernet.cloned-mac-address" and "wifi.cloned-mac-address"
settings. Instead of specifying an explicit MAC address, the additional
special values "permanent", "preserve", "random", "random-bia", "stable" and
"stable-bia" are supported.
"permanent" means to use the permanent hardware address. Previously that
was the default if no explict cloned-mac-address was set. The default is
thus still "permanent", but it can be overwritten by global
configuration.
"preserve" means not to configure the MAC address when activating the
device. That was actually the default behavior before introducing MAC
address handling with commit 1b49f941a69af910b0e68530be7339e8053068e5.
"random" and "random-bia" use a randomized MAC address for each
connection. "stable" and "stable-bia" use a generated, stable
address based on some token. The "bia" suffix says to generate a
burned-in address. The stable method by default uses as token the
connection UUID, but the token can be explicitly choosen via
"stable:<TOKEN>" and "stable-bia:<TOKEN>".
On a D-Bus level, the "cloned-mac-address" is a bytestring and thus
cannot express the new forms. It is replaced by the new
"assigned-mac-address" field. For the GObject property, libnm's API,
nmcli, keyfile, etc. the old name "cloned-mac-address" is still used.
Deprecating the old field seems more complicated then just extending
the use of the existing "cloned-mac-address" field, although the name
doesn't match well with the extended meaning.
There is some overlap with the "wifi.mac-address-randomization" setting.
https://bugzilla.gnome.org/show_bug.cgi?id=705545
https://bugzilla.gnome.org/show_bug.cgi?id=708820
https://bugzilla.gnome.org/show_bug.cgi?id=758301
2016-05-24 15:57:16 +02:00
|
|
|
{
|
|
|
|
|
nm_assert(nm_streq0(property, "cloned-mac-address"));
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-22 10:57:57 +02:00
|
|
|
static GVariant *
|
2022-10-21 14:50:27 +02:00
|
|
|
assigned_mac_address_to_dbus(_NM_SETT_INFO_PROP_TO_DBUS_FCN_ARGS _nm_nil)
|
device: extend MAC address handling including randomization for ethernet and wifi
Extend the "ethernet.cloned-mac-address" and "wifi.cloned-mac-address"
settings. Instead of specifying an explicit MAC address, the additional
special values "permanent", "preserve", "random", "random-bia", "stable" and
"stable-bia" are supported.
"permanent" means to use the permanent hardware address. Previously that
was the default if no explict cloned-mac-address was set. The default is
thus still "permanent", but it can be overwritten by global
configuration.
"preserve" means not to configure the MAC address when activating the
device. That was actually the default behavior before introducing MAC
address handling with commit 1b49f941a69af910b0e68530be7339e8053068e5.
"random" and "random-bia" use a randomized MAC address for each
connection. "stable" and "stable-bia" use a generated, stable
address based on some token. The "bia" suffix says to generate a
burned-in address. The stable method by default uses as token the
connection UUID, but the token can be explicitly choosen via
"stable:<TOKEN>" and "stable-bia:<TOKEN>".
On a D-Bus level, the "cloned-mac-address" is a bytestring and thus
cannot express the new forms. It is replaced by the new
"assigned-mac-address" field. For the GObject property, libnm's API,
nmcli, keyfile, etc. the old name "cloned-mac-address" is still used.
Deprecating the old field seems more complicated then just extending
the use of the existing "cloned-mac-address" field, although the name
doesn't match well with the extended meaning.
There is some overlap with the "wifi.mac-address-randomization" setting.
https://bugzilla.gnome.org/show_bug.cgi?id=705545
https://bugzilla.gnome.org/show_bug.cgi?id=708820
https://bugzilla.gnome.org/show_bug.cgi?id=758301
2016-05-24 15:57:16 +02:00
|
|
|
{
|
|
|
|
|
gs_free char *addr = NULL;
|
|
|
|
|
|
2021-04-01 17:28:53 +02:00
|
|
|
if (!_nm_connection_serialize_non_secret(flags))
|
2019-01-02 15:54:18 +01:00
|
|
|
return NULL;
|
|
|
|
|
|
2021-06-29 12:04:00 +02:00
|
|
|
nm_assert(nm_streq0(property_info->name, "assigned-mac-address"));
|
device: extend MAC address handling including randomization for ethernet and wifi
Extend the "ethernet.cloned-mac-address" and "wifi.cloned-mac-address"
settings. Instead of specifying an explicit MAC address, the additional
special values "permanent", "preserve", "random", "random-bia", "stable" and
"stable-bia" are supported.
"permanent" means to use the permanent hardware address. Previously that
was the default if no explict cloned-mac-address was set. The default is
thus still "permanent", but it can be overwritten by global
configuration.
"preserve" means not to configure the MAC address when activating the
device. That was actually the default behavior before introducing MAC
address handling with commit 1b49f941a69af910b0e68530be7339e8053068e5.
"random" and "random-bia" use a randomized MAC address for each
connection. "stable" and "stable-bia" use a generated, stable
address based on some token. The "bia" suffix says to generate a
burned-in address. The stable method by default uses as token the
connection UUID, but the token can be explicitly choosen via
"stable:<TOKEN>" and "stable-bia:<TOKEN>".
On a D-Bus level, the "cloned-mac-address" is a bytestring and thus
cannot express the new forms. It is replaced by the new
"assigned-mac-address" field. For the GObject property, libnm's API,
nmcli, keyfile, etc. the old name "cloned-mac-address" is still used.
Deprecating the old field seems more complicated then just extending
the use of the existing "cloned-mac-address" field, although the name
doesn't match well with the extended meaning.
There is some overlap with the "wifi.mac-address-randomization" setting.
https://bugzilla.gnome.org/show_bug.cgi?id=705545
https://bugzilla.gnome.org/show_bug.cgi?id=708820
https://bugzilla.gnome.org/show_bug.cgi?id=758301
2016-05-24 15:57:16 +02:00
|
|
|
|
|
|
|
|
g_object_get(setting, "cloned-mac-address", &addr, NULL);
|
libnm: fix regression serializing empty "cloned-mac-address"
For "cloned-mac-address", the empty string "" is an invalid
value that is rejected by verify().
Commit 8eed671 changed how the property is serialized to D-Bus.
Before, it was serialized using _nm_utils_hwaddr_to_dbus().
For invalid or empty addresses, this would not serialize the
value on D-Bus (or before commit 76aa6f8e0, it would create
a bogus value with no array elements).
With commit 8eed671, the cloned-mac-address gets also serialized
as "assigned-mac-address" via _nm_utils_hwaddr_cloned_data_synth(),
which would pass on invalid strings that the server would then reject.
That breaks for example nmtui. Try editing a connection with
"cloned-mac-address" set to NULL. Note, as long as you don't edit
the cloned MAC address in nmtui, you can save the modification.
Once you start modifying the entry, you can no longer set an empty
MAC address as the server now receives the invalid empty string.
Thus, the "OK" button fails with
Unable to save connection:
802-3-ethernet.cloned-mac-address:
is not a valid MAC address
It also means, nmtui cannot modify the "cloned-mac-address" field to
become empty.
Fix that problem at various places by coercing "" to NULL.
Fixes: 8eed67122c58540360b617eb42d5df8328e21b5d
https://bugzilla.redhat.com/show_bug.cgi?id=1372799
2016-09-02 15:00:08 +02:00
|
|
|
|
|
|
|
|
/* Before introducing the extended "cloned-mac-address" (and its D-Bus
|
2021-06-18 12:27:12 +02:00
|
|
|
* field "assigned-mac-address"), libnm's nm_utils_hwaddr_to_dbus()
|
libnm: fix regression serializing empty "cloned-mac-address"
For "cloned-mac-address", the empty string "" is an invalid
value that is rejected by verify().
Commit 8eed671 changed how the property is serialized to D-Bus.
Before, it was serialized using _nm_utils_hwaddr_to_dbus().
For invalid or empty addresses, this would not serialize the
value on D-Bus (or before commit 76aa6f8e0, it would create
a bogus value with no array elements).
With commit 8eed671, the cloned-mac-address gets also serialized
as "assigned-mac-address" via _nm_utils_hwaddr_cloned_data_synth(),
which would pass on invalid strings that the server would then reject.
That breaks for example nmtui. Try editing a connection with
"cloned-mac-address" set to NULL. Note, as long as you don't edit
the cloned MAC address in nmtui, you can save the modification.
Once you start modifying the entry, you can no longer set an empty
MAC address as the server now receives the invalid empty string.
Thus, the "OK" button fails with
Unable to save connection:
802-3-ethernet.cloned-mac-address:
is not a valid MAC address
It also means, nmtui cannot modify the "cloned-mac-address" field to
become empty.
Fix that problem at various places by coercing "" to NULL.
Fixes: 8eed67122c58540360b617eb42d5df8328e21b5d
https://bugzilla.redhat.com/show_bug.cgi?id=1372799
2016-09-02 15:00:08 +02:00
|
|
|
* would drop invalid values as it was unable to serialize them.
|
|
|
|
|
*
|
|
|
|
|
* Now, we would like to send invalid values as "assigned-mac-address"
|
|
|
|
|
* over D-Bus and let the server reject them.
|
|
|
|
|
*
|
|
|
|
|
* However, clients used to set the cloned-mac-address property
|
|
|
|
|
* to "" and it just worked as the value was not serialized in
|
|
|
|
|
* an ill form.
|
|
|
|
|
*
|
2016-12-15 15:30:43 +01:00
|
|
|
* To preserve that behavior, serialize "" as NULL.
|
libnm: fix regression serializing empty "cloned-mac-address"
For "cloned-mac-address", the empty string "" is an invalid
value that is rejected by verify().
Commit 8eed671 changed how the property is serialized to D-Bus.
Before, it was serialized using _nm_utils_hwaddr_to_dbus().
For invalid or empty addresses, this would not serialize the
value on D-Bus (or before commit 76aa6f8e0, it would create
a bogus value with no array elements).
With commit 8eed671, the cloned-mac-address gets also serialized
as "assigned-mac-address" via _nm_utils_hwaddr_cloned_data_synth(),
which would pass on invalid strings that the server would then reject.
That breaks for example nmtui. Try editing a connection with
"cloned-mac-address" set to NULL. Note, as long as you don't edit
the cloned MAC address in nmtui, you can save the modification.
Once you start modifying the entry, you can no longer set an empty
MAC address as the server now receives the invalid empty string.
Thus, the "OK" button fails with
Unable to save connection:
802-3-ethernet.cloned-mac-address:
is not a valid MAC address
It also means, nmtui cannot modify the "cloned-mac-address" field to
become empty.
Fix that problem at various places by coercing "" to NULL.
Fixes: 8eed67122c58540360b617eb42d5df8328e21b5d
https://bugzilla.redhat.com/show_bug.cgi?id=1372799
2016-09-02 15:00:08 +02:00
|
|
|
*/
|
|
|
|
|
|
2019-01-02 15:54:18 +01:00
|
|
|
return addr && addr[0] ? g_variant_new_take_string(g_steal_pointer(&addr)) : NULL;
|
device: extend MAC address handling including randomization for ethernet and wifi
Extend the "ethernet.cloned-mac-address" and "wifi.cloned-mac-address"
settings. Instead of specifying an explicit MAC address, the additional
special values "permanent", "preserve", "random", "random-bia", "stable" and
"stable-bia" are supported.
"permanent" means to use the permanent hardware address. Previously that
was the default if no explict cloned-mac-address was set. The default is
thus still "permanent", but it can be overwritten by global
configuration.
"preserve" means not to configure the MAC address when activating the
device. That was actually the default behavior before introducing MAC
address handling with commit 1b49f941a69af910b0e68530be7339e8053068e5.
"random" and "random-bia" use a randomized MAC address for each
connection. "stable" and "stable-bia" use a generated, stable
address based on some token. The "bia" suffix says to generate a
burned-in address. The stable method by default uses as token the
connection UUID, but the token can be explicitly choosen via
"stable:<TOKEN>" and "stable-bia:<TOKEN>".
On a D-Bus level, the "cloned-mac-address" is a bytestring and thus
cannot express the new forms. It is replaced by the new
"assigned-mac-address" field. For the GObject property, libnm's API,
nmcli, keyfile, etc. the old name "cloned-mac-address" is still used.
Deprecating the old field seems more complicated then just extending
the use of the existing "cloned-mac-address" field, although the name
doesn't match well with the extended meaning.
There is some overlap with the "wifi.mac-address-randomization" setting.
https://bugzilla.gnome.org/show_bug.cgi?id=705545
https://bugzilla.gnome.org/show_bug.cgi?id=708820
https://bugzilla.gnome.org/show_bug.cgi?id=758301
2016-05-24 15:57:16 +02:00
|
|
|
}
|
|
|
|
|
|
2019-09-22 10:57:57 +02:00
|
|
|
static gboolean
|
2022-10-21 14:50:27 +02:00
|
|
|
assigned_mac_address_from_dbus(_NM_SETT_INFO_PROP_FROM_DBUS_FCN_ARGS _nm_nil)
|
device: extend MAC address handling including randomization for ethernet and wifi
Extend the "ethernet.cloned-mac-address" and "wifi.cloned-mac-address"
settings. Instead of specifying an explicit MAC address, the additional
special values "permanent", "preserve", "random", "random-bia", "stable" and
"stable-bia" are supported.
"permanent" means to use the permanent hardware address. Previously that
was the default if no explict cloned-mac-address was set. The default is
thus still "permanent", but it can be overwritten by global
configuration.
"preserve" means not to configure the MAC address when activating the
device. That was actually the default behavior before introducing MAC
address handling with commit 1b49f941a69af910b0e68530be7339e8053068e5.
"random" and "random-bia" use a randomized MAC address for each
connection. "stable" and "stable-bia" use a generated, stable
address based on some token. The "bia" suffix says to generate a
burned-in address. The stable method by default uses as token the
connection UUID, but the token can be explicitly choosen via
"stable:<TOKEN>" and "stable-bia:<TOKEN>".
On a D-Bus level, the "cloned-mac-address" is a bytestring and thus
cannot express the new forms. It is replaced by the new
"assigned-mac-address" field. For the GObject property, libnm's API,
nmcli, keyfile, etc. the old name "cloned-mac-address" is still used.
Deprecating the old field seems more complicated then just extending
the use of the existing "cloned-mac-address" field, although the name
doesn't match well with the extended meaning.
There is some overlap with the "wifi.mac-address-randomization" setting.
https://bugzilla.gnome.org/show_bug.cgi?id=705545
https://bugzilla.gnome.org/show_bug.cgi?id=708820
https://bugzilla.gnome.org/show_bug.cgi?id=758301
2016-05-24 15:57:16 +02:00
|
|
|
{
|
2021-06-29 23:51:46 +02:00
|
|
|
nm_assert(nm_streq0(property_info->name, "assigned-mac-address"));
|
device: extend MAC address handling including randomization for ethernet and wifi
Extend the "ethernet.cloned-mac-address" and "wifi.cloned-mac-address"
settings. Instead of specifying an explicit MAC address, the additional
special values "permanent", "preserve", "random", "random-bia", "stable" and
"stable-bia" are supported.
"permanent" means to use the permanent hardware address. Previously that
was the default if no explict cloned-mac-address was set. The default is
thus still "permanent", but it can be overwritten by global
configuration.
"preserve" means not to configure the MAC address when activating the
device. That was actually the default behavior before introducing MAC
address handling with commit 1b49f941a69af910b0e68530be7339e8053068e5.
"random" and "random-bia" use a randomized MAC address for each
connection. "stable" and "stable-bia" use a generated, stable
address based on some token. The "bia" suffix says to generate a
burned-in address. The stable method by default uses as token the
connection UUID, but the token can be explicitly choosen via
"stable:<TOKEN>" and "stable-bia:<TOKEN>".
On a D-Bus level, the "cloned-mac-address" is a bytestring and thus
cannot express the new forms. It is replaced by the new
"assigned-mac-address" field. For the GObject property, libnm's API,
nmcli, keyfile, etc. the old name "cloned-mac-address" is still used.
Deprecating the old field seems more complicated then just extending
the use of the existing "cloned-mac-address" field, although the name
doesn't match well with the extended meaning.
There is some overlap with the "wifi.mac-address-randomization" setting.
https://bugzilla.gnome.org/show_bug.cgi?id=705545
https://bugzilla.gnome.org/show_bug.cgi?id=708820
https://bugzilla.gnome.org/show_bug.cgi?id=758301
2016-05-24 15:57:16 +02:00
|
|
|
|
|
|
|
|
if (_nm_setting_use_legacy_property(setting,
|
|
|
|
|
connection_dict,
|
|
|
|
|
"cloned-mac-address",
|
2021-07-27 10:27:44 +02:00
|
|
|
"assigned-mac-address")) {
|
|
|
|
|
*out_is_modified = FALSE;
|
device: extend MAC address handling including randomization for ethernet and wifi
Extend the "ethernet.cloned-mac-address" and "wifi.cloned-mac-address"
settings. Instead of specifying an explicit MAC address, the additional
special values "permanent", "preserve", "random", "random-bia", "stable" and
"stable-bia" are supported.
"permanent" means to use the permanent hardware address. Previously that
was the default if no explict cloned-mac-address was set. The default is
thus still "permanent", but it can be overwritten by global
configuration.
"preserve" means not to configure the MAC address when activating the
device. That was actually the default behavior before introducing MAC
address handling with commit 1b49f941a69af910b0e68530be7339e8053068e5.
"random" and "random-bia" use a randomized MAC address for each
connection. "stable" and "stable-bia" use a generated, stable
address based on some token. The "bia" suffix says to generate a
burned-in address. The stable method by default uses as token the
connection UUID, but the token can be explicitly choosen via
"stable:<TOKEN>" and "stable-bia:<TOKEN>".
On a D-Bus level, the "cloned-mac-address" is a bytestring and thus
cannot express the new forms. It is replaced by the new
"assigned-mac-address" field. For the GObject property, libnm's API,
nmcli, keyfile, etc. the old name "cloned-mac-address" is still used.
Deprecating the old field seems more complicated then just extending
the use of the existing "cloned-mac-address" field, although the name
doesn't match well with the extended meaning.
There is some overlap with the "wifi.mac-address-randomization" setting.
https://bugzilla.gnome.org/show_bug.cgi?id=705545
https://bugzilla.gnome.org/show_bug.cgi?id=708820
https://bugzilla.gnome.org/show_bug.cgi?id=758301
2016-05-24 15:57:16 +02:00
|
|
|
return TRUE;
|
2021-07-27 10:27:44 +02:00
|
|
|
}
|
device: extend MAC address handling including randomization for ethernet and wifi
Extend the "ethernet.cloned-mac-address" and "wifi.cloned-mac-address"
settings. Instead of specifying an explicit MAC address, the additional
special values "permanent", "preserve", "random", "random-bia", "stable" and
"stable-bia" are supported.
"permanent" means to use the permanent hardware address. Previously that
was the default if no explict cloned-mac-address was set. The default is
thus still "permanent", but it can be overwritten by global
configuration.
"preserve" means not to configure the MAC address when activating the
device. That was actually the default behavior before introducing MAC
address handling with commit 1b49f941a69af910b0e68530be7339e8053068e5.
"random" and "random-bia" use a randomized MAC address for each
connection. "stable" and "stable-bia" use a generated, stable
address based on some token. The "bia" suffix says to generate a
burned-in address. The stable method by default uses as token the
connection UUID, but the token can be explicitly choosen via
"stable:<TOKEN>" and "stable-bia:<TOKEN>".
On a D-Bus level, the "cloned-mac-address" is a bytestring and thus
cannot express the new forms. It is replaced by the new
"assigned-mac-address" field. For the GObject property, libnm's API,
nmcli, keyfile, etc. the old name "cloned-mac-address" is still used.
Deprecating the old field seems more complicated then just extending
the use of the existing "cloned-mac-address" field, although the name
doesn't match well with the extended meaning.
There is some overlap with the "wifi.mac-address-randomization" setting.
https://bugzilla.gnome.org/show_bug.cgi?id=705545
https://bugzilla.gnome.org/show_bug.cgi?id=708820
https://bugzilla.gnome.org/show_bug.cgi?id=758301
2016-05-24 15:57:16 +02:00
|
|
|
|
|
|
|
|
g_object_set(setting,
|
|
|
|
|
"cloned-mac-address",
|
libnm: fix regression serializing empty "cloned-mac-address"
For "cloned-mac-address", the empty string "" is an invalid
value that is rejected by verify().
Commit 8eed671 changed how the property is serialized to D-Bus.
Before, it was serialized using _nm_utils_hwaddr_to_dbus().
For invalid or empty addresses, this would not serialize the
value on D-Bus (or before commit 76aa6f8e0, it would create
a bogus value with no array elements).
With commit 8eed671, the cloned-mac-address gets also serialized
as "assigned-mac-address" via _nm_utils_hwaddr_cloned_data_synth(),
which would pass on invalid strings that the server would then reject.
That breaks for example nmtui. Try editing a connection with
"cloned-mac-address" set to NULL. Note, as long as you don't edit
the cloned MAC address in nmtui, you can save the modification.
Once you start modifying the entry, you can no longer set an empty
MAC address as the server now receives the invalid empty string.
Thus, the "OK" button fails with
Unable to save connection:
802-3-ethernet.cloned-mac-address:
is not a valid MAC address
It also means, nmtui cannot modify the "cloned-mac-address" field to
become empty.
Fix that problem at various places by coercing "" to NULL.
Fixes: 8eed67122c58540360b617eb42d5df8328e21b5d
https://bugzilla.redhat.com/show_bug.cgi?id=1372799
2016-09-02 15:00:08 +02:00
|
|
|
nm_str_not_empty(g_variant_get_string(value, NULL)),
|
device: extend MAC address handling including randomization for ethernet and wifi
Extend the "ethernet.cloned-mac-address" and "wifi.cloned-mac-address"
settings. Instead of specifying an explicit MAC address, the additional
special values "permanent", "preserve", "random", "random-bia", "stable" and
"stable-bia" are supported.
"permanent" means to use the permanent hardware address. Previously that
was the default if no explict cloned-mac-address was set. The default is
thus still "permanent", but it can be overwritten by global
configuration.
"preserve" means not to configure the MAC address when activating the
device. That was actually the default behavior before introducing MAC
address handling with commit 1b49f941a69af910b0e68530be7339e8053068e5.
"random" and "random-bia" use a randomized MAC address for each
connection. "stable" and "stable-bia" use a generated, stable
address based on some token. The "bia" suffix says to generate a
burned-in address. The stable method by default uses as token the
connection UUID, but the token can be explicitly choosen via
"stable:<TOKEN>" and "stable-bia:<TOKEN>".
On a D-Bus level, the "cloned-mac-address" is a bytestring and thus
cannot express the new forms. It is replaced by the new
"assigned-mac-address" field. For the GObject property, libnm's API,
nmcli, keyfile, etc. the old name "cloned-mac-address" is still used.
Deprecating the old field seems more complicated then just extending
the use of the existing "cloned-mac-address" field, although the name
doesn't match well with the extended meaning.
There is some overlap with the "wifi.mac-address-randomization" setting.
https://bugzilla.gnome.org/show_bug.cgi?id=705545
https://bugzilla.gnome.org/show_bug.cgi?id=708820
https://bugzilla.gnome.org/show_bug.cgi?id=758301
2016-05-24 15:57:16 +02:00
|
|
|
NULL);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-18 09:59:40 +02:00
|
|
|
const NMSettInfoPropertType nm_sett_info_propert_type_assigned_mac_address =
|
|
|
|
|
NM_SETT_INFO_PROPERT_TYPE_DBUS_INIT(G_VARIANT_TYPE_STRING,
|
2021-06-29 17:03:37 +02:00
|
|
|
.compare_fcn = _nm_setting_property_compare_fcn_ignore,
|
2022-10-21 14:50:27 +02:00
|
|
|
.to_dbus_fcn = assigned_mac_address_to_dbus,
|
|
|
|
|
.from_dbus_fcn = assigned_mac_address_from_dbus, );
|
2019-09-22 10:57:57 +02:00
|
|
|
|
device: extend MAC address handling including randomization for ethernet and wifi
Extend the "ethernet.cloned-mac-address" and "wifi.cloned-mac-address"
settings. Instead of specifying an explicit MAC address, the additional
special values "permanent", "preserve", "random", "random-bia", "stable" and
"stable-bia" are supported.
"permanent" means to use the permanent hardware address. Previously that
was the default if no explict cloned-mac-address was set. The default is
thus still "permanent", but it can be overwritten by global
configuration.
"preserve" means not to configure the MAC address when activating the
device. That was actually the default behavior before introducing MAC
address handling with commit 1b49f941a69af910b0e68530be7339e8053068e5.
"random" and "random-bia" use a randomized MAC address for each
connection. "stable" and "stable-bia" use a generated, stable
address based on some token. The "bia" suffix says to generate a
burned-in address. The stable method by default uses as token the
connection UUID, but the token can be explicitly choosen via
"stable:<TOKEN>" and "stable-bia:<TOKEN>".
On a D-Bus level, the "cloned-mac-address" is a bytestring and thus
cannot express the new forms. It is replaced by the new
"assigned-mac-address" field. For the GObject property, libnm's API,
nmcli, keyfile, etc. the old name "cloned-mac-address" is still used.
Deprecating the old field seems more complicated then just extending
the use of the existing "cloned-mac-address" field, although the name
doesn't match well with the extended meaning.
There is some overlap with the "wifi.mac-address-randomization" setting.
https://bugzilla.gnome.org/show_bug.cgi?id=705545
https://bugzilla.gnome.org/show_bug.cgi?id=708820
https://bugzilla.gnome.org/show_bug.cgi?id=758301
2016-05-24 15:57:16 +02:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-02-09 11:14:51 +01:00
|
|
|
/* Validate secret-flags. Most settings don't validate them, which is a bug.
|
|
|
|
|
* But we possibly cannot enforce a strict validation now.
|
|
|
|
|
*
|
|
|
|
|
* For new settings, they shall validate the secret-flags strictly. */
|
|
|
|
|
gboolean
|
|
|
|
|
_nm_utils_secret_flags_validate(NMSettingSecretFlags secret_flags,
|
2021-11-09 13:28:54 +01:00
|
|
|
const char *setting_name,
|
|
|
|
|
const char *property_name,
|
2019-02-09 11:14:51 +01:00
|
|
|
NMSettingSecretFlags disallowed_flags,
|
2021-11-09 13:28:54 +01:00
|
|
|
GError **error)
|
2019-02-09 11:14:51 +01:00
|
|
|
{
|
|
|
|
|
if (secret_flags == NM_SETTING_SECRET_FLAG_NONE)
|
|
|
|
|
return TRUE;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-02-09 11:14:51 +01:00
|
|
|
if (NM_FLAGS_ANY(secret_flags, ~NM_SETTING_SECRET_FLAG_ALL)) {
|
|
|
|
|
g_set_error_literal(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("unknown secret flags"));
|
|
|
|
|
if (setting_name)
|
|
|
|
|
g_prefix_error(error, "%s.%s: ", setting_name, property_name);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-02-09 11:14:51 +01:00
|
|
|
if (!nm_utils_is_power_of_two(secret_flags)) {
|
|
|
|
|
g_set_error_literal(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("conflicting secret flags"));
|
|
|
|
|
if (setting_name)
|
|
|
|
|
g_prefix_error(error, "%s.%s: ", setting_name, property_name);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-02-09 11:14:51 +01:00
|
|
|
if (NM_FLAGS_ANY(secret_flags, disallowed_flags)) {
|
|
|
|
|
if (NM_FLAGS_HAS(secret_flags, NM_SETTING_SECRET_FLAG_NOT_REQUIRED)) {
|
|
|
|
|
g_set_error_literal(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("secret flags must not be \"not-required\""));
|
|
|
|
|
if (setting_name)
|
|
|
|
|
g_prefix_error(error, "%s.%s: ", setting_name, property_name);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
g_set_error_literal(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("unsupported secret flags"));
|
|
|
|
|
if (setting_name)
|
|
|
|
|
g_prefix_error(error, "%s.%s: ", setting_name, property_name);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-02-09 11:14:51 +01:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-28 00:36:08 +01:00
|
|
|
gboolean
|
|
|
|
|
_nm_utils_wps_method_validate(NMSettingWirelessSecurityWpsMethod wps_method,
|
2021-11-09 13:28:54 +01:00
|
|
|
const char *setting_name,
|
|
|
|
|
const char *property_name,
|
2019-01-28 00:36:08 +01:00
|
|
|
gboolean wps_required,
|
2021-11-09 13:28:54 +01:00
|
|
|
GError **error)
|
2019-01-28 00:36:08 +01:00
|
|
|
{
|
|
|
|
|
if (wps_method > NM_SETTING_WIRELESS_SECURITY_WPS_METHOD_PIN) {
|
|
|
|
|
g_set_error_literal(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("property is invalid"));
|
|
|
|
|
g_prefix_error(error, "%s.%s: ", setting_name, property_name);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-28 00:36:08 +01:00
|
|
|
if (NM_FLAGS_HAS(wps_method, NM_SETTING_WIRELESS_SECURITY_WPS_METHOD_DISABLED)) {
|
|
|
|
|
if (wps_method != NM_SETTING_WIRELESS_SECURITY_WPS_METHOD_DISABLED) {
|
|
|
|
|
g_set_error_literal(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("can't be simultaneously disabled and enabled"));
|
|
|
|
|
g_prefix_error(error, "%s.%s: ", setting_name, property_name);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
if (wps_required) {
|
|
|
|
|
g_set_error_literal(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("WPS is required"));
|
|
|
|
|
g_prefix_error(error, "%s.%s: ", setting_name, property_name);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-28 00:36:08 +01:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
all: make MAC address randomization algorithm configurable
For the per-connection settings "ethernet.cloned-mac-address"
and "wifi.cloned-mac-address", and for the per-device setting
"wifi.scan-rand-mac-address", we may generate MAC addresses using
either the "random" or "stable" algorithm.
Add new properties "generate-mac-address-mask" that allow to configure
which bits of the MAC address will be scrambled.
By default, the "random" and "stable" algorithms scamble all bits
of the MAC address, including the OUI part and generate a locally-
administered, unicast address.
By specifying a MAC address mask, we can now configure to perserve
parts of the current MAC address of the device. For example, setting
"FF:FF:FF:00:00:00" will preserve the first 3 octects of the current
MAC address.
One can also explicitly specify a MAC address to use instead of the
current MAC address. For example, "FF:FF:FF:00:00:00 68:F7:28:00:00:00"
sets the OUI part of the MAC address to "68:F7:28" while scrambling
the last 3 octects.
Similarly, "02:00:00:00:00:00 00:00:00:00:00:00" will scamble
all bits of the MAC address, except clearing the second-least
significant bit. Thus, creating a burned-in address, globally
administered.
One can also supply a list of MAC addresses like
"FF:FF:FF:00:00:00 68:F7:28:00:00:00 00:0C:29:00:00:00 ..." in which
case a MAC address is choosen randomly.
To fully scamble the MAC address one can configure
"02:00:00:00:00:00 00:00:00:00:00:00 02:00:00:00:00:00".
which also randomly creates either a locally or globally administered
address.
With this, the following macchanger options can be implemented:
`macchanger --random`
This is the default if no mask is configured.
-> ""
while is the same as:
-> "00:00:00:00:00:00"
-> "02:00:00:00:00:00 02:00:00:00:00:00"
`macchanger --random --bia`
-> "02:00:00:00:00:00 00:00:00:00:00:00"
`macchanger --ending`
This option cannot be fully implemented, because macchanger
uses the current MAC address but also implies --bia.
-> "FF:FF:FF:00:00:00"
This would yields the same result only if the current MAC address
is already a burned-in address too. Otherwise, it has not the same
effect as --ending.
-> "FF:FF:FF:00:00:00 <MAC_ADDR>"
Alternatively, instead of using the current MAC address,
spell the OUI part out. But again, that is not really the
same as macchanger does because you explictly have to name
the OUI part to use.
`machanger --another`
`machanger --another_any`
-> "FF:FF:FF:00:00:00 <MAC_ADDR> <MAC_ADDR> ..."
"$(printf "FF:FF:FF:00:00:00 %s\n" "$(sed -n 's/^\([0-9a-fA-F][0-9a-fA-F]\) \([0-9a-fA-F][0-9a-fA-F]\) \([0-9a-fA-F][0-9a-fA-F]\) .*/\1:\2:\3:00:00:00/p' /usr/share/macchanger/wireless.list | xargs)")"
2016-06-22 20:31:39 +02:00
|
|
|
static char *
|
|
|
|
|
_split_word(char *s)
|
|
|
|
|
{
|
|
|
|
|
/* takes @s and truncates the string on the first white-space.
|
|
|
|
|
* then it returns the first word afterwards (again seeking
|
|
|
|
|
* over leading white-space). */
|
|
|
|
|
for (; s[0]; s++) {
|
|
|
|
|
if (g_ascii_isspace(s[0])) {
|
|
|
|
|
s[0] = '\0';
|
|
|
|
|
s++;
|
|
|
|
|
while (g_ascii_isspace(s[0]))
|
|
|
|
|
s++;
|
|
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gboolean
|
2021-11-09 13:28:54 +01:00
|
|
|
_nm_utils_generate_mac_address_mask_parse(const char *value,
|
|
|
|
|
struct ether_addr *out_mask,
|
all: make MAC address randomization algorithm configurable
For the per-connection settings "ethernet.cloned-mac-address"
and "wifi.cloned-mac-address", and for the per-device setting
"wifi.scan-rand-mac-address", we may generate MAC addresses using
either the "random" or "stable" algorithm.
Add new properties "generate-mac-address-mask" that allow to configure
which bits of the MAC address will be scrambled.
By default, the "random" and "stable" algorithms scamble all bits
of the MAC address, including the OUI part and generate a locally-
administered, unicast address.
By specifying a MAC address mask, we can now configure to perserve
parts of the current MAC address of the device. For example, setting
"FF:FF:FF:00:00:00" will preserve the first 3 octects of the current
MAC address.
One can also explicitly specify a MAC address to use instead of the
current MAC address. For example, "FF:FF:FF:00:00:00 68:F7:28:00:00:00"
sets the OUI part of the MAC address to "68:F7:28" while scrambling
the last 3 octects.
Similarly, "02:00:00:00:00:00 00:00:00:00:00:00" will scamble
all bits of the MAC address, except clearing the second-least
significant bit. Thus, creating a burned-in address, globally
administered.
One can also supply a list of MAC addresses like
"FF:FF:FF:00:00:00 68:F7:28:00:00:00 00:0C:29:00:00:00 ..." in which
case a MAC address is choosen randomly.
To fully scamble the MAC address one can configure
"02:00:00:00:00:00 00:00:00:00:00:00 02:00:00:00:00:00".
which also randomly creates either a locally or globally administered
address.
With this, the following macchanger options can be implemented:
`macchanger --random`
This is the default if no mask is configured.
-> ""
while is the same as:
-> "00:00:00:00:00:00"
-> "02:00:00:00:00:00 02:00:00:00:00:00"
`macchanger --random --bia`
-> "02:00:00:00:00:00 00:00:00:00:00:00"
`macchanger --ending`
This option cannot be fully implemented, because macchanger
uses the current MAC address but also implies --bia.
-> "FF:FF:FF:00:00:00"
This would yields the same result only if the current MAC address
is already a burned-in address too. Otherwise, it has not the same
effect as --ending.
-> "FF:FF:FF:00:00:00 <MAC_ADDR>"
Alternatively, instead of using the current MAC address,
spell the OUI part out. But again, that is not really the
same as macchanger does because you explictly have to name
the OUI part to use.
`machanger --another`
`machanger --another_any`
-> "FF:FF:FF:00:00:00 <MAC_ADDR> <MAC_ADDR> ..."
"$(printf "FF:FF:FF:00:00:00 %s\n" "$(sed -n 's/^\([0-9a-fA-F][0-9a-fA-F]\) \([0-9a-fA-F][0-9a-fA-F]\) \([0-9a-fA-F][0-9a-fA-F]\) .*/\1:\2:\3:00:00:00/p' /usr/share/macchanger/wireless.list | xargs)")"
2016-06-22 20:31:39 +02:00
|
|
|
struct ether_addr **out_ouis,
|
2021-11-09 13:28:54 +01:00
|
|
|
gsize *out_ouis_len,
|
|
|
|
|
GError **error)
|
all: make MAC address randomization algorithm configurable
For the per-connection settings "ethernet.cloned-mac-address"
and "wifi.cloned-mac-address", and for the per-device setting
"wifi.scan-rand-mac-address", we may generate MAC addresses using
either the "random" or "stable" algorithm.
Add new properties "generate-mac-address-mask" that allow to configure
which bits of the MAC address will be scrambled.
By default, the "random" and "stable" algorithms scamble all bits
of the MAC address, including the OUI part and generate a locally-
administered, unicast address.
By specifying a MAC address mask, we can now configure to perserve
parts of the current MAC address of the device. For example, setting
"FF:FF:FF:00:00:00" will preserve the first 3 octects of the current
MAC address.
One can also explicitly specify a MAC address to use instead of the
current MAC address. For example, "FF:FF:FF:00:00:00 68:F7:28:00:00:00"
sets the OUI part of the MAC address to "68:F7:28" while scrambling
the last 3 octects.
Similarly, "02:00:00:00:00:00 00:00:00:00:00:00" will scamble
all bits of the MAC address, except clearing the second-least
significant bit. Thus, creating a burned-in address, globally
administered.
One can also supply a list of MAC addresses like
"FF:FF:FF:00:00:00 68:F7:28:00:00:00 00:0C:29:00:00:00 ..." in which
case a MAC address is choosen randomly.
To fully scamble the MAC address one can configure
"02:00:00:00:00:00 00:00:00:00:00:00 02:00:00:00:00:00".
which also randomly creates either a locally or globally administered
address.
With this, the following macchanger options can be implemented:
`macchanger --random`
This is the default if no mask is configured.
-> ""
while is the same as:
-> "00:00:00:00:00:00"
-> "02:00:00:00:00:00 02:00:00:00:00:00"
`macchanger --random --bia`
-> "02:00:00:00:00:00 00:00:00:00:00:00"
`macchanger --ending`
This option cannot be fully implemented, because macchanger
uses the current MAC address but also implies --bia.
-> "FF:FF:FF:00:00:00"
This would yields the same result only if the current MAC address
is already a burned-in address too. Otherwise, it has not the same
effect as --ending.
-> "FF:FF:FF:00:00:00 <MAC_ADDR>"
Alternatively, instead of using the current MAC address,
spell the OUI part out. But again, that is not really the
same as macchanger does because you explictly have to name
the OUI part to use.
`machanger --another`
`machanger --another_any`
-> "FF:FF:FF:00:00:00 <MAC_ADDR> <MAC_ADDR> ..."
"$(printf "FF:FF:FF:00:00:00 %s\n" "$(sed -n 's/^\([0-9a-fA-F][0-9a-fA-F]\) \([0-9a-fA-F][0-9a-fA-F]\) \([0-9a-fA-F][0-9a-fA-F]\) .*/\1:\2:\3:00:00:00/p' /usr/share/macchanger/wireless.list | xargs)")"
2016-06-22 20:31:39 +02:00
|
|
|
{
|
2021-11-09 13:28:54 +01:00
|
|
|
gs_free char *s_free = NULL;
|
|
|
|
|
char *s, *s_next;
|
|
|
|
|
struct ether_addr mask;
|
all: make MAC address randomization algorithm configurable
For the per-connection settings "ethernet.cloned-mac-address"
and "wifi.cloned-mac-address", and for the per-device setting
"wifi.scan-rand-mac-address", we may generate MAC addresses using
either the "random" or "stable" algorithm.
Add new properties "generate-mac-address-mask" that allow to configure
which bits of the MAC address will be scrambled.
By default, the "random" and "stable" algorithms scamble all bits
of the MAC address, including the OUI part and generate a locally-
administered, unicast address.
By specifying a MAC address mask, we can now configure to perserve
parts of the current MAC address of the device. For example, setting
"FF:FF:FF:00:00:00" will preserve the first 3 octects of the current
MAC address.
One can also explicitly specify a MAC address to use instead of the
current MAC address. For example, "FF:FF:FF:00:00:00 68:F7:28:00:00:00"
sets the OUI part of the MAC address to "68:F7:28" while scrambling
the last 3 octects.
Similarly, "02:00:00:00:00:00 00:00:00:00:00:00" will scamble
all bits of the MAC address, except clearing the second-least
significant bit. Thus, creating a burned-in address, globally
administered.
One can also supply a list of MAC addresses like
"FF:FF:FF:00:00:00 68:F7:28:00:00:00 00:0C:29:00:00:00 ..." in which
case a MAC address is choosen randomly.
To fully scamble the MAC address one can configure
"02:00:00:00:00:00 00:00:00:00:00:00 02:00:00:00:00:00".
which also randomly creates either a locally or globally administered
address.
With this, the following macchanger options can be implemented:
`macchanger --random`
This is the default if no mask is configured.
-> ""
while is the same as:
-> "00:00:00:00:00:00"
-> "02:00:00:00:00:00 02:00:00:00:00:00"
`macchanger --random --bia`
-> "02:00:00:00:00:00 00:00:00:00:00:00"
`macchanger --ending`
This option cannot be fully implemented, because macchanger
uses the current MAC address but also implies --bia.
-> "FF:FF:FF:00:00:00"
This would yields the same result only if the current MAC address
is already a burned-in address too. Otherwise, it has not the same
effect as --ending.
-> "FF:FF:FF:00:00:00 <MAC_ADDR>"
Alternatively, instead of using the current MAC address,
spell the OUI part out. But again, that is not really the
same as macchanger does because you explictly have to name
the OUI part to use.
`machanger --another`
`machanger --another_any`
-> "FF:FF:FF:00:00:00 <MAC_ADDR> <MAC_ADDR> ..."
"$(printf "FF:FF:FF:00:00:00 %s\n" "$(sed -n 's/^\([0-9a-fA-F][0-9a-fA-F]\) \([0-9a-fA-F][0-9a-fA-F]\) \([0-9a-fA-F][0-9a-fA-F]\) .*/\1:\2:\3:00:00:00/p' /usr/share/macchanger/wireless.list | xargs)")"
2016-06-22 20:31:39 +02:00
|
|
|
gs_unref_array GArray *ouis = NULL;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail(!error || !*error, FALSE);
|
|
|
|
|
|
|
|
|
|
if (!value || !*value) {
|
|
|
|
|
/* NULL and "" are valid values and both mean the default
|
|
|
|
|
* "q */
|
|
|
|
|
if (out_mask) {
|
|
|
|
|
memset(out_mask, 0, sizeof(*out_mask));
|
|
|
|
|
out_mask->ether_addr_octet[0] |= 0x02;
|
|
|
|
|
}
|
|
|
|
|
NM_SET_OUT(out_ouis, NULL);
|
|
|
|
|
NM_SET_OUT(out_ouis_len, 0);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
all: make MAC address randomization algorithm configurable
For the per-connection settings "ethernet.cloned-mac-address"
and "wifi.cloned-mac-address", and for the per-device setting
"wifi.scan-rand-mac-address", we may generate MAC addresses using
either the "random" or "stable" algorithm.
Add new properties "generate-mac-address-mask" that allow to configure
which bits of the MAC address will be scrambled.
By default, the "random" and "stable" algorithms scamble all bits
of the MAC address, including the OUI part and generate a locally-
administered, unicast address.
By specifying a MAC address mask, we can now configure to perserve
parts of the current MAC address of the device. For example, setting
"FF:FF:FF:00:00:00" will preserve the first 3 octects of the current
MAC address.
One can also explicitly specify a MAC address to use instead of the
current MAC address. For example, "FF:FF:FF:00:00:00 68:F7:28:00:00:00"
sets the OUI part of the MAC address to "68:F7:28" while scrambling
the last 3 octects.
Similarly, "02:00:00:00:00:00 00:00:00:00:00:00" will scamble
all bits of the MAC address, except clearing the second-least
significant bit. Thus, creating a burned-in address, globally
administered.
One can also supply a list of MAC addresses like
"FF:FF:FF:00:00:00 68:F7:28:00:00:00 00:0C:29:00:00:00 ..." in which
case a MAC address is choosen randomly.
To fully scamble the MAC address one can configure
"02:00:00:00:00:00 00:00:00:00:00:00 02:00:00:00:00:00".
which also randomly creates either a locally or globally administered
address.
With this, the following macchanger options can be implemented:
`macchanger --random`
This is the default if no mask is configured.
-> ""
while is the same as:
-> "00:00:00:00:00:00"
-> "02:00:00:00:00:00 02:00:00:00:00:00"
`macchanger --random --bia`
-> "02:00:00:00:00:00 00:00:00:00:00:00"
`macchanger --ending`
This option cannot be fully implemented, because macchanger
uses the current MAC address but also implies --bia.
-> "FF:FF:FF:00:00:00"
This would yields the same result only if the current MAC address
is already a burned-in address too. Otherwise, it has not the same
effect as --ending.
-> "FF:FF:FF:00:00:00 <MAC_ADDR>"
Alternatively, instead of using the current MAC address,
spell the OUI part out. But again, that is not really the
same as macchanger does because you explictly have to name
the OUI part to use.
`machanger --another`
`machanger --another_any`
-> "FF:FF:FF:00:00:00 <MAC_ADDR> <MAC_ADDR> ..."
"$(printf "FF:FF:FF:00:00:00 %s\n" "$(sed -n 's/^\([0-9a-fA-F][0-9a-fA-F]\) \([0-9a-fA-F][0-9a-fA-F]\) \([0-9a-fA-F][0-9a-fA-F]\) .*/\1:\2:\3:00:00:00/p' /usr/share/macchanger/wireless.list | xargs)")"
2016-06-22 20:31:39 +02:00
|
|
|
s_free = g_strdup(value);
|
|
|
|
|
s = s_free;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
all: make MAC address randomization algorithm configurable
For the per-connection settings "ethernet.cloned-mac-address"
and "wifi.cloned-mac-address", and for the per-device setting
"wifi.scan-rand-mac-address", we may generate MAC addresses using
either the "random" or "stable" algorithm.
Add new properties "generate-mac-address-mask" that allow to configure
which bits of the MAC address will be scrambled.
By default, the "random" and "stable" algorithms scamble all bits
of the MAC address, including the OUI part and generate a locally-
administered, unicast address.
By specifying a MAC address mask, we can now configure to perserve
parts of the current MAC address of the device. For example, setting
"FF:FF:FF:00:00:00" will preserve the first 3 octects of the current
MAC address.
One can also explicitly specify a MAC address to use instead of the
current MAC address. For example, "FF:FF:FF:00:00:00 68:F7:28:00:00:00"
sets the OUI part of the MAC address to "68:F7:28" while scrambling
the last 3 octects.
Similarly, "02:00:00:00:00:00 00:00:00:00:00:00" will scamble
all bits of the MAC address, except clearing the second-least
significant bit. Thus, creating a burned-in address, globally
administered.
One can also supply a list of MAC addresses like
"FF:FF:FF:00:00:00 68:F7:28:00:00:00 00:0C:29:00:00:00 ..." in which
case a MAC address is choosen randomly.
To fully scamble the MAC address one can configure
"02:00:00:00:00:00 00:00:00:00:00:00 02:00:00:00:00:00".
which also randomly creates either a locally or globally administered
address.
With this, the following macchanger options can be implemented:
`macchanger --random`
This is the default if no mask is configured.
-> ""
while is the same as:
-> "00:00:00:00:00:00"
-> "02:00:00:00:00:00 02:00:00:00:00:00"
`macchanger --random --bia`
-> "02:00:00:00:00:00 00:00:00:00:00:00"
`macchanger --ending`
This option cannot be fully implemented, because macchanger
uses the current MAC address but also implies --bia.
-> "FF:FF:FF:00:00:00"
This would yields the same result only if the current MAC address
is already a burned-in address too. Otherwise, it has not the same
effect as --ending.
-> "FF:FF:FF:00:00:00 <MAC_ADDR>"
Alternatively, instead of using the current MAC address,
spell the OUI part out. But again, that is not really the
same as macchanger does because you explictly have to name
the OUI part to use.
`machanger --another`
`machanger --another_any`
-> "FF:FF:FF:00:00:00 <MAC_ADDR> <MAC_ADDR> ..."
"$(printf "FF:FF:FF:00:00:00 %s\n" "$(sed -n 's/^\([0-9a-fA-F][0-9a-fA-F]\) \([0-9a-fA-F][0-9a-fA-F]\) \([0-9a-fA-F][0-9a-fA-F]\) .*/\1:\2:\3:00:00:00/p' /usr/share/macchanger/wireless.list | xargs)")"
2016-06-22 20:31:39 +02:00
|
|
|
/* skip over leading whitespace */
|
|
|
|
|
while (g_ascii_isspace(s[0]))
|
|
|
|
|
s++;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
all: make MAC address randomization algorithm configurable
For the per-connection settings "ethernet.cloned-mac-address"
and "wifi.cloned-mac-address", and for the per-device setting
"wifi.scan-rand-mac-address", we may generate MAC addresses using
either the "random" or "stable" algorithm.
Add new properties "generate-mac-address-mask" that allow to configure
which bits of the MAC address will be scrambled.
By default, the "random" and "stable" algorithms scamble all bits
of the MAC address, including the OUI part and generate a locally-
administered, unicast address.
By specifying a MAC address mask, we can now configure to perserve
parts of the current MAC address of the device. For example, setting
"FF:FF:FF:00:00:00" will preserve the first 3 octects of the current
MAC address.
One can also explicitly specify a MAC address to use instead of the
current MAC address. For example, "FF:FF:FF:00:00:00 68:F7:28:00:00:00"
sets the OUI part of the MAC address to "68:F7:28" while scrambling
the last 3 octects.
Similarly, "02:00:00:00:00:00 00:00:00:00:00:00" will scamble
all bits of the MAC address, except clearing the second-least
significant bit. Thus, creating a burned-in address, globally
administered.
One can also supply a list of MAC addresses like
"FF:FF:FF:00:00:00 68:F7:28:00:00:00 00:0C:29:00:00:00 ..." in which
case a MAC address is choosen randomly.
To fully scamble the MAC address one can configure
"02:00:00:00:00:00 00:00:00:00:00:00 02:00:00:00:00:00".
which also randomly creates either a locally or globally administered
address.
With this, the following macchanger options can be implemented:
`macchanger --random`
This is the default if no mask is configured.
-> ""
while is the same as:
-> "00:00:00:00:00:00"
-> "02:00:00:00:00:00 02:00:00:00:00:00"
`macchanger --random --bia`
-> "02:00:00:00:00:00 00:00:00:00:00:00"
`macchanger --ending`
This option cannot be fully implemented, because macchanger
uses the current MAC address but also implies --bia.
-> "FF:FF:FF:00:00:00"
This would yields the same result only if the current MAC address
is already a burned-in address too. Otherwise, it has not the same
effect as --ending.
-> "FF:FF:FF:00:00:00 <MAC_ADDR>"
Alternatively, instead of using the current MAC address,
spell the OUI part out. But again, that is not really the
same as macchanger does because you explictly have to name
the OUI part to use.
`machanger --another`
`machanger --another_any`
-> "FF:FF:FF:00:00:00 <MAC_ADDR> <MAC_ADDR> ..."
"$(printf "FF:FF:FF:00:00:00 %s\n" "$(sed -n 's/^\([0-9a-fA-F][0-9a-fA-F]\) \([0-9a-fA-F][0-9a-fA-F]\) \([0-9a-fA-F][0-9a-fA-F]\) .*/\1:\2:\3:00:00:00/p' /usr/share/macchanger/wireless.list | xargs)")"
2016-06-22 20:31:39 +02:00
|
|
|
/* parse the first mask */
|
|
|
|
|
s_next = _split_word(s);
|
|
|
|
|
if (!nm_utils_hwaddr_aton(s, &mask, ETH_ALEN)) {
|
|
|
|
|
g_set_error(error,
|
|
|
|
|
NM_UTILS_ERROR,
|
|
|
|
|
NM_UTILS_ERROR_UNKNOWN,
|
|
|
|
|
_("not a valid ethernet MAC address for mask at position %lld"),
|
|
|
|
|
(long long) (s - s_free));
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
all: make MAC address randomization algorithm configurable
For the per-connection settings "ethernet.cloned-mac-address"
and "wifi.cloned-mac-address", and for the per-device setting
"wifi.scan-rand-mac-address", we may generate MAC addresses using
either the "random" or "stable" algorithm.
Add new properties "generate-mac-address-mask" that allow to configure
which bits of the MAC address will be scrambled.
By default, the "random" and "stable" algorithms scamble all bits
of the MAC address, including the OUI part and generate a locally-
administered, unicast address.
By specifying a MAC address mask, we can now configure to perserve
parts of the current MAC address of the device. For example, setting
"FF:FF:FF:00:00:00" will preserve the first 3 octects of the current
MAC address.
One can also explicitly specify a MAC address to use instead of the
current MAC address. For example, "FF:FF:FF:00:00:00 68:F7:28:00:00:00"
sets the OUI part of the MAC address to "68:F7:28" while scrambling
the last 3 octects.
Similarly, "02:00:00:00:00:00 00:00:00:00:00:00" will scamble
all bits of the MAC address, except clearing the second-least
significant bit. Thus, creating a burned-in address, globally
administered.
One can also supply a list of MAC addresses like
"FF:FF:FF:00:00:00 68:F7:28:00:00:00 00:0C:29:00:00:00 ..." in which
case a MAC address is choosen randomly.
To fully scamble the MAC address one can configure
"02:00:00:00:00:00 00:00:00:00:00:00 02:00:00:00:00:00".
which also randomly creates either a locally or globally administered
address.
With this, the following macchanger options can be implemented:
`macchanger --random`
This is the default if no mask is configured.
-> ""
while is the same as:
-> "00:00:00:00:00:00"
-> "02:00:00:00:00:00 02:00:00:00:00:00"
`macchanger --random --bia`
-> "02:00:00:00:00:00 00:00:00:00:00:00"
`macchanger --ending`
This option cannot be fully implemented, because macchanger
uses the current MAC address but also implies --bia.
-> "FF:FF:FF:00:00:00"
This would yields the same result only if the current MAC address
is already a burned-in address too. Otherwise, it has not the same
effect as --ending.
-> "FF:FF:FF:00:00:00 <MAC_ADDR>"
Alternatively, instead of using the current MAC address,
spell the OUI part out. But again, that is not really the
same as macchanger does because you explictly have to name
the OUI part to use.
`machanger --another`
`machanger --another_any`
-> "FF:FF:FF:00:00:00 <MAC_ADDR> <MAC_ADDR> ..."
"$(printf "FF:FF:FF:00:00:00 %s\n" "$(sed -n 's/^\([0-9a-fA-F][0-9a-fA-F]\) \([0-9a-fA-F][0-9a-fA-F]\) \([0-9a-fA-F][0-9a-fA-F]\) .*/\1:\2:\3:00:00:00/p' /usr/share/macchanger/wireless.list | xargs)")"
2016-06-22 20:31:39 +02:00
|
|
|
if (s_next[0]) {
|
|
|
|
|
ouis = g_array_sized_new(FALSE, FALSE, sizeof(struct ether_addr), 4);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
all: make MAC address randomization algorithm configurable
For the per-connection settings "ethernet.cloned-mac-address"
and "wifi.cloned-mac-address", and for the per-device setting
"wifi.scan-rand-mac-address", we may generate MAC addresses using
either the "random" or "stable" algorithm.
Add new properties "generate-mac-address-mask" that allow to configure
which bits of the MAC address will be scrambled.
By default, the "random" and "stable" algorithms scamble all bits
of the MAC address, including the OUI part and generate a locally-
administered, unicast address.
By specifying a MAC address mask, we can now configure to perserve
parts of the current MAC address of the device. For example, setting
"FF:FF:FF:00:00:00" will preserve the first 3 octects of the current
MAC address.
One can also explicitly specify a MAC address to use instead of the
current MAC address. For example, "FF:FF:FF:00:00:00 68:F7:28:00:00:00"
sets the OUI part of the MAC address to "68:F7:28" while scrambling
the last 3 octects.
Similarly, "02:00:00:00:00:00 00:00:00:00:00:00" will scamble
all bits of the MAC address, except clearing the second-least
significant bit. Thus, creating a burned-in address, globally
administered.
One can also supply a list of MAC addresses like
"FF:FF:FF:00:00:00 68:F7:28:00:00:00 00:0C:29:00:00:00 ..." in which
case a MAC address is choosen randomly.
To fully scamble the MAC address one can configure
"02:00:00:00:00:00 00:00:00:00:00:00 02:00:00:00:00:00".
which also randomly creates either a locally or globally administered
address.
With this, the following macchanger options can be implemented:
`macchanger --random`
This is the default if no mask is configured.
-> ""
while is the same as:
-> "00:00:00:00:00:00"
-> "02:00:00:00:00:00 02:00:00:00:00:00"
`macchanger --random --bia`
-> "02:00:00:00:00:00 00:00:00:00:00:00"
`macchanger --ending`
This option cannot be fully implemented, because macchanger
uses the current MAC address but also implies --bia.
-> "FF:FF:FF:00:00:00"
This would yields the same result only if the current MAC address
is already a burned-in address too. Otherwise, it has not the same
effect as --ending.
-> "FF:FF:FF:00:00:00 <MAC_ADDR>"
Alternatively, instead of using the current MAC address,
spell the OUI part out. But again, that is not really the
same as macchanger does because you explictly have to name
the OUI part to use.
`machanger --another`
`machanger --another_any`
-> "FF:FF:FF:00:00:00 <MAC_ADDR> <MAC_ADDR> ..."
"$(printf "FF:FF:FF:00:00:00 %s\n" "$(sed -n 's/^\([0-9a-fA-F][0-9a-fA-F]\) \([0-9a-fA-F][0-9a-fA-F]\) \([0-9a-fA-F][0-9a-fA-F]\) .*/\1:\2:\3:00:00:00/p' /usr/share/macchanger/wireless.list | xargs)")"
2016-06-22 20:31:39 +02:00
|
|
|
do {
|
2022-09-08 12:57:10 +02:00
|
|
|
struct ether_addr *new;
|
|
|
|
|
|
all: make MAC address randomization algorithm configurable
For the per-connection settings "ethernet.cloned-mac-address"
and "wifi.cloned-mac-address", and for the per-device setting
"wifi.scan-rand-mac-address", we may generate MAC addresses using
either the "random" or "stable" algorithm.
Add new properties "generate-mac-address-mask" that allow to configure
which bits of the MAC address will be scrambled.
By default, the "random" and "stable" algorithms scamble all bits
of the MAC address, including the OUI part and generate a locally-
administered, unicast address.
By specifying a MAC address mask, we can now configure to perserve
parts of the current MAC address of the device. For example, setting
"FF:FF:FF:00:00:00" will preserve the first 3 octects of the current
MAC address.
One can also explicitly specify a MAC address to use instead of the
current MAC address. For example, "FF:FF:FF:00:00:00 68:F7:28:00:00:00"
sets the OUI part of the MAC address to "68:F7:28" while scrambling
the last 3 octects.
Similarly, "02:00:00:00:00:00 00:00:00:00:00:00" will scamble
all bits of the MAC address, except clearing the second-least
significant bit. Thus, creating a burned-in address, globally
administered.
One can also supply a list of MAC addresses like
"FF:FF:FF:00:00:00 68:F7:28:00:00:00 00:0C:29:00:00:00 ..." in which
case a MAC address is choosen randomly.
To fully scamble the MAC address one can configure
"02:00:00:00:00:00 00:00:00:00:00:00 02:00:00:00:00:00".
which also randomly creates either a locally or globally administered
address.
With this, the following macchanger options can be implemented:
`macchanger --random`
This is the default if no mask is configured.
-> ""
while is the same as:
-> "00:00:00:00:00:00"
-> "02:00:00:00:00:00 02:00:00:00:00:00"
`macchanger --random --bia`
-> "02:00:00:00:00:00 00:00:00:00:00:00"
`macchanger --ending`
This option cannot be fully implemented, because macchanger
uses the current MAC address but also implies --bia.
-> "FF:FF:FF:00:00:00"
This would yields the same result only if the current MAC address
is already a burned-in address too. Otherwise, it has not the same
effect as --ending.
-> "FF:FF:FF:00:00:00 <MAC_ADDR>"
Alternatively, instead of using the current MAC address,
spell the OUI part out. But again, that is not really the
same as macchanger does because you explictly have to name
the OUI part to use.
`machanger --another`
`machanger --another_any`
-> "FF:FF:FF:00:00:00 <MAC_ADDR> <MAC_ADDR> ..."
"$(printf "FF:FF:FF:00:00:00 %s\n" "$(sed -n 's/^\([0-9a-fA-F][0-9a-fA-F]\) \([0-9a-fA-F][0-9a-fA-F]\) \([0-9a-fA-F][0-9a-fA-F]\) .*/\1:\2:\3:00:00:00/p' /usr/share/macchanger/wireless.list | xargs)")"
2016-06-22 20:31:39 +02:00
|
|
|
s = s_next;
|
|
|
|
|
s_next = _split_word(s);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2022-09-08 12:57:10 +02:00
|
|
|
new = nm_g_array_append_new(ouis, struct ether_addr);
|
|
|
|
|
if (!nm_utils_hwaddr_aton(s, new, ETH_ALEN)) {
|
all: make MAC address randomization algorithm configurable
For the per-connection settings "ethernet.cloned-mac-address"
and "wifi.cloned-mac-address", and for the per-device setting
"wifi.scan-rand-mac-address", we may generate MAC addresses using
either the "random" or "stable" algorithm.
Add new properties "generate-mac-address-mask" that allow to configure
which bits of the MAC address will be scrambled.
By default, the "random" and "stable" algorithms scamble all bits
of the MAC address, including the OUI part and generate a locally-
administered, unicast address.
By specifying a MAC address mask, we can now configure to perserve
parts of the current MAC address of the device. For example, setting
"FF:FF:FF:00:00:00" will preserve the first 3 octects of the current
MAC address.
One can also explicitly specify a MAC address to use instead of the
current MAC address. For example, "FF:FF:FF:00:00:00 68:F7:28:00:00:00"
sets the OUI part of the MAC address to "68:F7:28" while scrambling
the last 3 octects.
Similarly, "02:00:00:00:00:00 00:00:00:00:00:00" will scamble
all bits of the MAC address, except clearing the second-least
significant bit. Thus, creating a burned-in address, globally
administered.
One can also supply a list of MAC addresses like
"FF:FF:FF:00:00:00 68:F7:28:00:00:00 00:0C:29:00:00:00 ..." in which
case a MAC address is choosen randomly.
To fully scamble the MAC address one can configure
"02:00:00:00:00:00 00:00:00:00:00:00 02:00:00:00:00:00".
which also randomly creates either a locally or globally administered
address.
With this, the following macchanger options can be implemented:
`macchanger --random`
This is the default if no mask is configured.
-> ""
while is the same as:
-> "00:00:00:00:00:00"
-> "02:00:00:00:00:00 02:00:00:00:00:00"
`macchanger --random --bia`
-> "02:00:00:00:00:00 00:00:00:00:00:00"
`macchanger --ending`
This option cannot be fully implemented, because macchanger
uses the current MAC address but also implies --bia.
-> "FF:FF:FF:00:00:00"
This would yields the same result only if the current MAC address
is already a burned-in address too. Otherwise, it has not the same
effect as --ending.
-> "FF:FF:FF:00:00:00 <MAC_ADDR>"
Alternatively, instead of using the current MAC address,
spell the OUI part out. But again, that is not really the
same as macchanger does because you explictly have to name
the OUI part to use.
`machanger --another`
`machanger --another_any`
-> "FF:FF:FF:00:00:00 <MAC_ADDR> <MAC_ADDR> ..."
"$(printf "FF:FF:FF:00:00:00 %s\n" "$(sed -n 's/^\([0-9a-fA-F][0-9a-fA-F]\) \([0-9a-fA-F][0-9a-fA-F]\) \([0-9a-fA-F][0-9a-fA-F]\) .*/\1:\2:\3:00:00:00/p' /usr/share/macchanger/wireless.list | xargs)")"
2016-06-22 20:31:39 +02:00
|
|
|
g_set_error(error,
|
|
|
|
|
NM_UTILS_ERROR,
|
|
|
|
|
NM_UTILS_ERROR_UNKNOWN,
|
|
|
|
|
_("not a valid ethernet MAC address #%u at position %lld"),
|
|
|
|
|
ouis->len,
|
|
|
|
|
(long long) (s - s_free));
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
} while (s_next[0]);
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
all: make MAC address randomization algorithm configurable
For the per-connection settings "ethernet.cloned-mac-address"
and "wifi.cloned-mac-address", and for the per-device setting
"wifi.scan-rand-mac-address", we may generate MAC addresses using
either the "random" or "stable" algorithm.
Add new properties "generate-mac-address-mask" that allow to configure
which bits of the MAC address will be scrambled.
By default, the "random" and "stable" algorithms scamble all bits
of the MAC address, including the OUI part and generate a locally-
administered, unicast address.
By specifying a MAC address mask, we can now configure to perserve
parts of the current MAC address of the device. For example, setting
"FF:FF:FF:00:00:00" will preserve the first 3 octects of the current
MAC address.
One can also explicitly specify a MAC address to use instead of the
current MAC address. For example, "FF:FF:FF:00:00:00 68:F7:28:00:00:00"
sets the OUI part of the MAC address to "68:F7:28" while scrambling
the last 3 octects.
Similarly, "02:00:00:00:00:00 00:00:00:00:00:00" will scamble
all bits of the MAC address, except clearing the second-least
significant bit. Thus, creating a burned-in address, globally
administered.
One can also supply a list of MAC addresses like
"FF:FF:FF:00:00:00 68:F7:28:00:00:00 00:0C:29:00:00:00 ..." in which
case a MAC address is choosen randomly.
To fully scamble the MAC address one can configure
"02:00:00:00:00:00 00:00:00:00:00:00 02:00:00:00:00:00".
which also randomly creates either a locally or globally administered
address.
With this, the following macchanger options can be implemented:
`macchanger --random`
This is the default if no mask is configured.
-> ""
while is the same as:
-> "00:00:00:00:00:00"
-> "02:00:00:00:00:00 02:00:00:00:00:00"
`macchanger --random --bia`
-> "02:00:00:00:00:00 00:00:00:00:00:00"
`macchanger --ending`
This option cannot be fully implemented, because macchanger
uses the current MAC address but also implies --bia.
-> "FF:FF:FF:00:00:00"
This would yields the same result only if the current MAC address
is already a burned-in address too. Otherwise, it has not the same
effect as --ending.
-> "FF:FF:FF:00:00:00 <MAC_ADDR>"
Alternatively, instead of using the current MAC address,
spell the OUI part out. But again, that is not really the
same as macchanger does because you explictly have to name
the OUI part to use.
`machanger --another`
`machanger --another_any`
-> "FF:FF:FF:00:00:00 <MAC_ADDR> <MAC_ADDR> ..."
"$(printf "FF:FF:FF:00:00:00 %s\n" "$(sed -n 's/^\([0-9a-fA-F][0-9a-fA-F]\) \([0-9a-fA-F][0-9a-fA-F]\) \([0-9a-fA-F][0-9a-fA-F]\) .*/\1:\2:\3:00:00:00/p' /usr/share/macchanger/wireless.list | xargs)")"
2016-06-22 20:31:39 +02:00
|
|
|
NM_SET_OUT(out_mask, mask);
|
|
|
|
|
NM_SET_OUT(out_ouis_len, ouis ? ouis->len : 0);
|
|
|
|
|
NM_SET_OUT(out_ouis,
|
|
|
|
|
ouis ? ((struct ether_addr *) g_array_free(g_steal_pointer(&ouis), FALSE)) : NULL);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-03-24 20:36:00 +01:00
|
|
|
gboolean
|
|
|
|
|
nm_utils_is_valid_iface_name_utf8safe(const char *utf8safe_name)
|
|
|
|
|
{
|
|
|
|
|
gs_free gpointer bin_to_free = NULL;
|
|
|
|
|
gconstpointer bin;
|
|
|
|
|
gsize len;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail(utf8safe_name, FALSE);
|
|
|
|
|
|
2020-05-04 09:52:16 +02:00
|
|
|
bin = nm_utils_buf_utf8safe_unescape(utf8safe_name,
|
|
|
|
|
NM_UTILS_STR_UTF8_SAFE_FLAG_NONE,
|
|
|
|
|
&len,
|
|
|
|
|
&bin_to_free);
|
2019-03-24 20:36:00 +01:00
|
|
|
|
|
|
|
|
if (bin_to_free) {
|
|
|
|
|
/* some unescaping happened... */
|
|
|
|
|
|
|
|
|
|
if (len != strlen(bin)) {
|
|
|
|
|
/* there are embedded NUL chars. Invalid. */
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-12 18:01:13 +01:00
|
|
|
return nm_utils_ifname_valid_kernel(bin, NULL);
|
2019-03-24 20:36:00 +01:00
|
|
|
}
|
|
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
/**
|
2016-12-23 12:52:41 +01:00
|
|
|
* nm_utils_is_valid_iface_name:
|
2023-03-01 01:21:38 +01:00
|
|
|
* @name: (nullable): Name of interface
|
2016-12-23 12:52:41 +01:00
|
|
|
* @error: location to store the error occurring, or %NULL to ignore
|
|
|
|
|
*
|
|
|
|
|
* Validate the network interface name.
|
2014-07-24 08:53:33 -04:00
|
|
|
*
|
|
|
|
|
* This function is a 1:1 copy of the kernel's interface validation
|
|
|
|
|
* function in net/core/dev.c.
|
|
|
|
|
*
|
|
|
|
|
* Returns: %TRUE if interface name is valid, otherwise %FALSE is returned.
|
2019-07-18 16:04:16 +02:00
|
|
|
*
|
|
|
|
|
* Before 1.20, this function did not accept %NULL as @name argument. If you
|
|
|
|
|
* want to run against older versions of libnm, don't pass %NULL.
|
2022-11-07 21:13:28 +01:00
|
|
|
*
|
|
|
|
|
* Since: 1.6
|
2014-07-24 08:53:33 -04:00
|
|
|
*/
|
|
|
|
|
gboolean
|
2016-12-23 12:52:41 +01:00
|
|
|
nm_utils_is_valid_iface_name(const char *name, GError **error)
|
2014-07-24 08:53:33 -04:00
|
|
|
{
|
2020-02-12 18:01:13 +01:00
|
|
|
g_return_val_if_fail(!error || !*error, FALSE);
|
|
|
|
|
|
2020-02-12 17:30:49 +01:00
|
|
|
return nm_utils_ifname_valid_kernel(name, error);
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
|
|
|
|
|
2016-12-23 12:52:41 +01:00
|
|
|
/**
|
|
|
|
|
* nm_utils_iface_valid_name:
|
2023-03-01 01:21:38 +01:00
|
|
|
* @name: (nullable): Name of interface
|
2016-12-23 12:52:41 +01:00
|
|
|
*
|
|
|
|
|
* Validate the network interface name.
|
|
|
|
|
*
|
2020-03-13 19:45:09 +01:00
|
|
|
* Deprecated: 1.6: Use nm_utils_is_valid_iface_name() instead, with better error reporting.
|
2016-12-23 12:52:51 +01:00
|
|
|
*
|
2016-12-23 12:52:41 +01:00
|
|
|
* Returns: %TRUE if interface name is valid, otherwise %FALSE is returned.
|
2019-07-18 16:04:16 +02:00
|
|
|
*
|
|
|
|
|
* Before 1.20, this function did not accept %NULL as @name argument. If you
|
|
|
|
|
* want to run against older versions of libnm, don't pass %NULL.
|
2016-12-23 12:52:41 +01:00
|
|
|
*/
|
|
|
|
|
gboolean
|
|
|
|
|
nm_utils_iface_valid_name(const char *name)
|
|
|
|
|
{
|
|
|
|
|
return nm_utils_is_valid_iface_name(name, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
/**
|
|
|
|
|
* nm_utils_is_uuid:
|
2023-03-01 01:21:38 +01:00
|
|
|
* @str: (nullable): a string that might be a UUID
|
2014-07-24 08:53:33 -04:00
|
|
|
*
|
|
|
|
|
* Checks if @str is a UUID
|
|
|
|
|
*
|
|
|
|
|
* Returns: %TRUE if @str is a UUID, %FALSE if not
|
2019-05-21 18:13:53 +02:00
|
|
|
*
|
|
|
|
|
* In older versions, nm_utils_is_uuid() did not accept %NULL as @str
|
|
|
|
|
* argument. Don't pass %NULL if you run against older versions of libnm.
|
2021-05-27 09:29:21 +02:00
|
|
|
*
|
|
|
|
|
* Deprecated: 1.32: older versions of NetworkManager had a wrong
|
|
|
|
|
* understanding of what makes a valid UUID. This function can thus
|
|
|
|
|
* accept some inputs as valid, which in fact are not valid UUIDs.
|
2014-07-24 08:53:33 -04:00
|
|
|
*/
|
|
|
|
|
gboolean
|
|
|
|
|
nm_utils_is_uuid(const char *str)
|
|
|
|
|
{
|
2021-05-02 22:30:31 +02:00
|
|
|
return nm_uuid_is_valid_nmlegacy(str);
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
|
|
|
|
|
glib-aux: rename IP address related helpers from "nm-inet-utils.h"
- name things related to `in_addr_t`, `struct in6_addr`, `NMIPAddr` as
`nm_ip4_addr_*()`, `nm_ip6_addr_*()`, `nm_ip_addr_*()`, respectively.
- we have a wrapper `nm_inet_ntop()` for `inet_ntop()`. This name
of our wrapper is chosen to be familiar with the libc underlying
function. With this, also name functions that are about string
representations of addresses `nm_inet_*()`, `nm_inet4_*()`,
`nm_inet6_*()`. For example, `nm_inet_parse_str()`,
`nm_inet_is_normalized()`.
<<<<
R() {
git grep -l "$1" | xargs sed -i "s/\<$1\>/$2/g"
}
R NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX NM_CMP_DIRECT_IP4_ADDR_SAME_PREFIX
R NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX NM_CMP_DIRECT_IP6_ADDR_SAME_PREFIX
R NM_UTILS_INET_ADDRSTRLEN NM_INET_ADDRSTRLEN
R _nm_utils_inet4_ntop nm_inet4_ntop
R _nm_utils_inet6_ntop nm_inet6_ntop
R _nm_utils_ip4_get_default_prefix nm_ip4_addr_get_default_prefix
R _nm_utils_ip4_get_default_prefix0 nm_ip4_addr_get_default_prefix0
R _nm_utils_ip4_netmask_to_prefix nm_ip4_addr_netmask_to_prefix
R _nm_utils_ip4_prefix_to_netmask nm_ip4_addr_netmask_from_prefix
R nm_utils_inet4_ntop_dup nm_inet4_ntop_dup
R nm_utils_inet6_ntop_dup nm_inet6_ntop_dup
R nm_utils_inet_ntop nm_inet_ntop
R nm_utils_inet_ntop_dup nm_inet_ntop_dup
R nm_utils_ip4_address_clear_host_address nm_ip4_addr_clear_host_address
R nm_utils_ip4_address_is_link_local nm_ip4_addr_is_link_local
R nm_utils_ip4_address_is_loopback nm_ip4_addr_is_loopback
R nm_utils_ip4_address_is_zeronet nm_ip4_addr_is_zeronet
R nm_utils_ip4_address_same_prefix nm_ip4_addr_same_prefix
R nm_utils_ip4_address_same_prefix_cmp nm_ip4_addr_same_prefix_cmp
R nm_utils_ip6_address_clear_host_address nm_ip6_addr_clear_host_address
R nm_utils_ip6_address_same_prefix nm_ip6_addr_same_prefix
R nm_utils_ip6_address_same_prefix_cmp nm_ip6_addr_same_prefix_cmp
R nm_utils_ip6_is_ula nm_ip6_addr_is_ula
R nm_utils_ip_address_same_prefix nm_ip_addr_same_prefix
R nm_utils_ip_address_same_prefix_cmp nm_ip_addr_same_prefix_cmp
R nm_utils_ip_is_site_local nm_ip_addr_is_site_local
R nm_utils_ipaddr_is_normalized nm_inet_is_normalized
R nm_utils_ipaddr_is_valid nm_inet_is_valid
R nm_utils_ipx_address_clear_host_address nm_ip_addr_clear_host_address
R nm_utils_parse_inaddr nm_inet_parse_str
R nm_utils_parse_inaddr_bin nm_inet_parse_bin
R nm_utils_parse_inaddr_bin_full nm_inet_parse_bin_full
R nm_utils_parse_inaddr_prefix nm_inet_parse_with_prefix_str
R nm_utils_parse_inaddr_prefix_bin nm_inet_parse_with_prefix_bin
R test_nm_utils_ip6_address_same_prefix test_nm_ip_addr_same_prefix
./contrib/scripts/nm-code-format.sh -F
2022-08-19 13:15:20 +02:00
|
|
|
static _nm_thread_local char _nm_utils_inet_ntop_buffer[NM_INET_ADDRSTRLEN];
|
2014-07-24 08:53:33 -04:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_utils_inet4_ntop: (skip)
|
|
|
|
|
* @inaddr: the address that should be converted to string.
|
2014-12-18 12:44:57 -05:00
|
|
|
* @dst: the destination buffer, it must contain at least
|
glib-aux: rename IP address related helpers from "nm-inet-utils.h"
- name things related to `in_addr_t`, `struct in6_addr`, `NMIPAddr` as
`nm_ip4_addr_*()`, `nm_ip6_addr_*()`, `nm_ip_addr_*()`, respectively.
- we have a wrapper `nm_inet_ntop()` for `inet_ntop()`. This name
of our wrapper is chosen to be familiar with the libc underlying
function. With this, also name functions that are about string
representations of addresses `nm_inet_*()`, `nm_inet4_*()`,
`nm_inet6_*()`. For example, `nm_inet_parse_str()`,
`nm_inet_is_normalized()`.
<<<<
R() {
git grep -l "$1" | xargs sed -i "s/\<$1\>/$2/g"
}
R NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX NM_CMP_DIRECT_IP4_ADDR_SAME_PREFIX
R NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX NM_CMP_DIRECT_IP6_ADDR_SAME_PREFIX
R NM_UTILS_INET_ADDRSTRLEN NM_INET_ADDRSTRLEN
R _nm_utils_inet4_ntop nm_inet4_ntop
R _nm_utils_inet6_ntop nm_inet6_ntop
R _nm_utils_ip4_get_default_prefix nm_ip4_addr_get_default_prefix
R _nm_utils_ip4_get_default_prefix0 nm_ip4_addr_get_default_prefix0
R _nm_utils_ip4_netmask_to_prefix nm_ip4_addr_netmask_to_prefix
R _nm_utils_ip4_prefix_to_netmask nm_ip4_addr_netmask_from_prefix
R nm_utils_inet4_ntop_dup nm_inet4_ntop_dup
R nm_utils_inet6_ntop_dup nm_inet6_ntop_dup
R nm_utils_inet_ntop nm_inet_ntop
R nm_utils_inet_ntop_dup nm_inet_ntop_dup
R nm_utils_ip4_address_clear_host_address nm_ip4_addr_clear_host_address
R nm_utils_ip4_address_is_link_local nm_ip4_addr_is_link_local
R nm_utils_ip4_address_is_loopback nm_ip4_addr_is_loopback
R nm_utils_ip4_address_is_zeronet nm_ip4_addr_is_zeronet
R nm_utils_ip4_address_same_prefix nm_ip4_addr_same_prefix
R nm_utils_ip4_address_same_prefix_cmp nm_ip4_addr_same_prefix_cmp
R nm_utils_ip6_address_clear_host_address nm_ip6_addr_clear_host_address
R nm_utils_ip6_address_same_prefix nm_ip6_addr_same_prefix
R nm_utils_ip6_address_same_prefix_cmp nm_ip6_addr_same_prefix_cmp
R nm_utils_ip6_is_ula nm_ip6_addr_is_ula
R nm_utils_ip_address_same_prefix nm_ip_addr_same_prefix
R nm_utils_ip_address_same_prefix_cmp nm_ip_addr_same_prefix_cmp
R nm_utils_ip_is_site_local nm_ip_addr_is_site_local
R nm_utils_ipaddr_is_normalized nm_inet_is_normalized
R nm_utils_ipaddr_is_valid nm_inet_is_valid
R nm_utils_ipx_address_clear_host_address nm_ip_addr_clear_host_address
R nm_utils_parse_inaddr nm_inet_parse_str
R nm_utils_parse_inaddr_bin nm_inet_parse_bin
R nm_utils_parse_inaddr_bin_full nm_inet_parse_bin_full
R nm_utils_parse_inaddr_prefix nm_inet_parse_with_prefix_str
R nm_utils_parse_inaddr_prefix_bin nm_inet_parse_with_prefix_bin
R test_nm_utils_ip6_address_same_prefix test_nm_ip_addr_same_prefix
./contrib/scripts/nm-code-format.sh -F
2022-08-19 13:15:20 +02:00
|
|
|
* <literal>INET_ADDRSTRLEN</literal> or %NM_INET_ADDRSTRLEN
|
2014-12-18 12:44:57 -05:00
|
|
|
* characters. If set to %NULL, it will return a pointer to an internal, static
|
|
|
|
|
* buffer (shared with nm_utils_inet6_ntop()). Beware, that the internal
|
|
|
|
|
* buffer will be overwritten with ever new call of nm_utils_inet4_ntop() or
|
2020-09-14 16:55:05 +02:00
|
|
|
* nm_utils_inet6_ntop() that does not provide its own @dst buffer. Since
|
|
|
|
|
* 1.28, the internal buffer is thread local and thus thread safe. Before
|
|
|
|
|
* it was not thread safe. When in doubt, pass your own
|
2014-12-18 12:44:57 -05:00
|
|
|
* @dst buffer to avoid these issues.
|
2014-07-24 08:53:33 -04:00
|
|
|
*
|
|
|
|
|
* Wrapper for inet_ntop.
|
|
|
|
|
*
|
|
|
|
|
* Returns: the input buffer @dst, or a pointer to an
|
|
|
|
|
* internal, static buffer. This function cannot fail.
|
|
|
|
|
**/
|
|
|
|
|
const char *
|
|
|
|
|
nm_utils_inet4_ntop(in_addr_t inaddr, char *dst)
|
|
|
|
|
{
|
2018-11-26 17:14:19 +01:00
|
|
|
/* relying on the static buffer (by leaving @dst as %NULL) is discouraged.
|
|
|
|
|
* Don't do that!
|
|
|
|
|
*
|
|
|
|
|
* However, still support it to be lenient against mistakes and because
|
|
|
|
|
* this is public API of libnm. */
|
glib-aux: rename IP address related helpers from "nm-inet-utils.h"
- name things related to `in_addr_t`, `struct in6_addr`, `NMIPAddr` as
`nm_ip4_addr_*()`, `nm_ip6_addr_*()`, `nm_ip_addr_*()`, respectively.
- we have a wrapper `nm_inet_ntop()` for `inet_ntop()`. This name
of our wrapper is chosen to be familiar with the libc underlying
function. With this, also name functions that are about string
representations of addresses `nm_inet_*()`, `nm_inet4_*()`,
`nm_inet6_*()`. For example, `nm_inet_parse_str()`,
`nm_inet_is_normalized()`.
<<<<
R() {
git grep -l "$1" | xargs sed -i "s/\<$1\>/$2/g"
}
R NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX NM_CMP_DIRECT_IP4_ADDR_SAME_PREFIX
R NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX NM_CMP_DIRECT_IP6_ADDR_SAME_PREFIX
R NM_UTILS_INET_ADDRSTRLEN NM_INET_ADDRSTRLEN
R _nm_utils_inet4_ntop nm_inet4_ntop
R _nm_utils_inet6_ntop nm_inet6_ntop
R _nm_utils_ip4_get_default_prefix nm_ip4_addr_get_default_prefix
R _nm_utils_ip4_get_default_prefix0 nm_ip4_addr_get_default_prefix0
R _nm_utils_ip4_netmask_to_prefix nm_ip4_addr_netmask_to_prefix
R _nm_utils_ip4_prefix_to_netmask nm_ip4_addr_netmask_from_prefix
R nm_utils_inet4_ntop_dup nm_inet4_ntop_dup
R nm_utils_inet6_ntop_dup nm_inet6_ntop_dup
R nm_utils_inet_ntop nm_inet_ntop
R nm_utils_inet_ntop_dup nm_inet_ntop_dup
R nm_utils_ip4_address_clear_host_address nm_ip4_addr_clear_host_address
R nm_utils_ip4_address_is_link_local nm_ip4_addr_is_link_local
R nm_utils_ip4_address_is_loopback nm_ip4_addr_is_loopback
R nm_utils_ip4_address_is_zeronet nm_ip4_addr_is_zeronet
R nm_utils_ip4_address_same_prefix nm_ip4_addr_same_prefix
R nm_utils_ip4_address_same_prefix_cmp nm_ip4_addr_same_prefix_cmp
R nm_utils_ip6_address_clear_host_address nm_ip6_addr_clear_host_address
R nm_utils_ip6_address_same_prefix nm_ip6_addr_same_prefix
R nm_utils_ip6_address_same_prefix_cmp nm_ip6_addr_same_prefix_cmp
R nm_utils_ip6_is_ula nm_ip6_addr_is_ula
R nm_utils_ip_address_same_prefix nm_ip_addr_same_prefix
R nm_utils_ip_address_same_prefix_cmp nm_ip_addr_same_prefix_cmp
R nm_utils_ip_is_site_local nm_ip_addr_is_site_local
R nm_utils_ipaddr_is_normalized nm_inet_is_normalized
R nm_utils_ipaddr_is_valid nm_inet_is_valid
R nm_utils_ipx_address_clear_host_address nm_ip_addr_clear_host_address
R nm_utils_parse_inaddr nm_inet_parse_str
R nm_utils_parse_inaddr_bin nm_inet_parse_bin
R nm_utils_parse_inaddr_bin_full nm_inet_parse_bin_full
R nm_utils_parse_inaddr_prefix nm_inet_parse_with_prefix_str
R nm_utils_parse_inaddr_prefix_bin nm_inet_parse_with_prefix_bin
R test_nm_utils_ip6_address_same_prefix test_nm_ip_addr_same_prefix
./contrib/scripts/nm-code-format.sh -F
2022-08-19 13:15:20 +02:00
|
|
|
return nm_inet4_ntop(inaddr, dst ?: _nm_utils_inet_ntop_buffer);
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_utils_inet6_ntop: (skip)
|
|
|
|
|
* @in6addr: the address that should be converted to string.
|
2014-12-18 12:44:57 -05:00
|
|
|
* @dst: the destination buffer, it must contain at least
|
glib-aux: rename IP address related helpers from "nm-inet-utils.h"
- name things related to `in_addr_t`, `struct in6_addr`, `NMIPAddr` as
`nm_ip4_addr_*()`, `nm_ip6_addr_*()`, `nm_ip_addr_*()`, respectively.
- we have a wrapper `nm_inet_ntop()` for `inet_ntop()`. This name
of our wrapper is chosen to be familiar with the libc underlying
function. With this, also name functions that are about string
representations of addresses `nm_inet_*()`, `nm_inet4_*()`,
`nm_inet6_*()`. For example, `nm_inet_parse_str()`,
`nm_inet_is_normalized()`.
<<<<
R() {
git grep -l "$1" | xargs sed -i "s/\<$1\>/$2/g"
}
R NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX NM_CMP_DIRECT_IP4_ADDR_SAME_PREFIX
R NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX NM_CMP_DIRECT_IP6_ADDR_SAME_PREFIX
R NM_UTILS_INET_ADDRSTRLEN NM_INET_ADDRSTRLEN
R _nm_utils_inet4_ntop nm_inet4_ntop
R _nm_utils_inet6_ntop nm_inet6_ntop
R _nm_utils_ip4_get_default_prefix nm_ip4_addr_get_default_prefix
R _nm_utils_ip4_get_default_prefix0 nm_ip4_addr_get_default_prefix0
R _nm_utils_ip4_netmask_to_prefix nm_ip4_addr_netmask_to_prefix
R _nm_utils_ip4_prefix_to_netmask nm_ip4_addr_netmask_from_prefix
R nm_utils_inet4_ntop_dup nm_inet4_ntop_dup
R nm_utils_inet6_ntop_dup nm_inet6_ntop_dup
R nm_utils_inet_ntop nm_inet_ntop
R nm_utils_inet_ntop_dup nm_inet_ntop_dup
R nm_utils_ip4_address_clear_host_address nm_ip4_addr_clear_host_address
R nm_utils_ip4_address_is_link_local nm_ip4_addr_is_link_local
R nm_utils_ip4_address_is_loopback nm_ip4_addr_is_loopback
R nm_utils_ip4_address_is_zeronet nm_ip4_addr_is_zeronet
R nm_utils_ip4_address_same_prefix nm_ip4_addr_same_prefix
R nm_utils_ip4_address_same_prefix_cmp nm_ip4_addr_same_prefix_cmp
R nm_utils_ip6_address_clear_host_address nm_ip6_addr_clear_host_address
R nm_utils_ip6_address_same_prefix nm_ip6_addr_same_prefix
R nm_utils_ip6_address_same_prefix_cmp nm_ip6_addr_same_prefix_cmp
R nm_utils_ip6_is_ula nm_ip6_addr_is_ula
R nm_utils_ip_address_same_prefix nm_ip_addr_same_prefix
R nm_utils_ip_address_same_prefix_cmp nm_ip_addr_same_prefix_cmp
R nm_utils_ip_is_site_local nm_ip_addr_is_site_local
R nm_utils_ipaddr_is_normalized nm_inet_is_normalized
R nm_utils_ipaddr_is_valid nm_inet_is_valid
R nm_utils_ipx_address_clear_host_address nm_ip_addr_clear_host_address
R nm_utils_parse_inaddr nm_inet_parse_str
R nm_utils_parse_inaddr_bin nm_inet_parse_bin
R nm_utils_parse_inaddr_bin_full nm_inet_parse_bin_full
R nm_utils_parse_inaddr_prefix nm_inet_parse_with_prefix_str
R nm_utils_parse_inaddr_prefix_bin nm_inet_parse_with_prefix_bin
R test_nm_utils_ip6_address_same_prefix test_nm_ip_addr_same_prefix
./contrib/scripts/nm-code-format.sh -F
2022-08-19 13:15:20 +02:00
|
|
|
* <literal>INET6_ADDRSTRLEN</literal> or %NM_INET_ADDRSTRLEN
|
2014-12-18 12:44:57 -05:00
|
|
|
* characters. If set to %NULL, it will return a pointer to an internal, static
|
|
|
|
|
* buffer (shared with nm_utils_inet4_ntop()). Beware, that the internal
|
|
|
|
|
* buffer will be overwritten with ever new call of nm_utils_inet4_ntop() or
|
2020-09-14 16:55:05 +02:00
|
|
|
* nm_utils_inet6_ntop() that does not provide its own @dst buffer. Since
|
|
|
|
|
* 1.28, the internal buffer is thread local and thus thread safe. Before
|
|
|
|
|
* it was not thread safe. When in doubt, pass your own
|
2014-12-18 12:44:57 -05:00
|
|
|
* @dst buffer to avoid these issues.
|
2014-07-24 08:53:33 -04:00
|
|
|
*
|
|
|
|
|
* Wrapper for inet_ntop.
|
|
|
|
|
*
|
|
|
|
|
* Returns: the input buffer @dst, or a pointer to an
|
|
|
|
|
* internal, static buffer. %NULL is not allowed as @in6addr,
|
|
|
|
|
* otherwise, this function cannot fail.
|
|
|
|
|
**/
|
|
|
|
|
const char *
|
|
|
|
|
nm_utils_inet6_ntop(const struct in6_addr *in6addr, char *dst)
|
|
|
|
|
{
|
2018-11-26 17:14:19 +01:00
|
|
|
/* relying on the static buffer (by leaving @dst as %NULL) is discouraged.
|
|
|
|
|
* Don't do that!
|
|
|
|
|
*
|
|
|
|
|
* However, still support it to be lenient against mistakes and because
|
|
|
|
|
* this is public API of libnm. */
|
2014-07-24 08:53:33 -04:00
|
|
|
g_return_val_if_fail(in6addr, NULL);
|
glib-aux: rename IP address related helpers from "nm-inet-utils.h"
- name things related to `in_addr_t`, `struct in6_addr`, `NMIPAddr` as
`nm_ip4_addr_*()`, `nm_ip6_addr_*()`, `nm_ip_addr_*()`, respectively.
- we have a wrapper `nm_inet_ntop()` for `inet_ntop()`. This name
of our wrapper is chosen to be familiar with the libc underlying
function. With this, also name functions that are about string
representations of addresses `nm_inet_*()`, `nm_inet4_*()`,
`nm_inet6_*()`. For example, `nm_inet_parse_str()`,
`nm_inet_is_normalized()`.
<<<<
R() {
git grep -l "$1" | xargs sed -i "s/\<$1\>/$2/g"
}
R NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX NM_CMP_DIRECT_IP4_ADDR_SAME_PREFIX
R NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX NM_CMP_DIRECT_IP6_ADDR_SAME_PREFIX
R NM_UTILS_INET_ADDRSTRLEN NM_INET_ADDRSTRLEN
R _nm_utils_inet4_ntop nm_inet4_ntop
R _nm_utils_inet6_ntop nm_inet6_ntop
R _nm_utils_ip4_get_default_prefix nm_ip4_addr_get_default_prefix
R _nm_utils_ip4_get_default_prefix0 nm_ip4_addr_get_default_prefix0
R _nm_utils_ip4_netmask_to_prefix nm_ip4_addr_netmask_to_prefix
R _nm_utils_ip4_prefix_to_netmask nm_ip4_addr_netmask_from_prefix
R nm_utils_inet4_ntop_dup nm_inet4_ntop_dup
R nm_utils_inet6_ntop_dup nm_inet6_ntop_dup
R nm_utils_inet_ntop nm_inet_ntop
R nm_utils_inet_ntop_dup nm_inet_ntop_dup
R nm_utils_ip4_address_clear_host_address nm_ip4_addr_clear_host_address
R nm_utils_ip4_address_is_link_local nm_ip4_addr_is_link_local
R nm_utils_ip4_address_is_loopback nm_ip4_addr_is_loopback
R nm_utils_ip4_address_is_zeronet nm_ip4_addr_is_zeronet
R nm_utils_ip4_address_same_prefix nm_ip4_addr_same_prefix
R nm_utils_ip4_address_same_prefix_cmp nm_ip4_addr_same_prefix_cmp
R nm_utils_ip6_address_clear_host_address nm_ip6_addr_clear_host_address
R nm_utils_ip6_address_same_prefix nm_ip6_addr_same_prefix
R nm_utils_ip6_address_same_prefix_cmp nm_ip6_addr_same_prefix_cmp
R nm_utils_ip6_is_ula nm_ip6_addr_is_ula
R nm_utils_ip_address_same_prefix nm_ip_addr_same_prefix
R nm_utils_ip_address_same_prefix_cmp nm_ip_addr_same_prefix_cmp
R nm_utils_ip_is_site_local nm_ip_addr_is_site_local
R nm_utils_ipaddr_is_normalized nm_inet_is_normalized
R nm_utils_ipaddr_is_valid nm_inet_is_valid
R nm_utils_ipx_address_clear_host_address nm_ip_addr_clear_host_address
R nm_utils_parse_inaddr nm_inet_parse_str
R nm_utils_parse_inaddr_bin nm_inet_parse_bin
R nm_utils_parse_inaddr_bin_full nm_inet_parse_bin_full
R nm_utils_parse_inaddr_prefix nm_inet_parse_with_prefix_str
R nm_utils_parse_inaddr_prefix_bin nm_inet_parse_with_prefix_bin
R test_nm_utils_ip6_address_same_prefix test_nm_ip_addr_same_prefix
./contrib/scripts/nm-code-format.sh -F
2022-08-19 13:15:20 +02:00
|
|
|
return nm_inet6_ntop(in6addr, dst ?: _nm_utils_inet_ntop_buffer);
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
|
|
|
|
|
2014-09-16 16:42:46 -04:00
|
|
|
/**
|
|
|
|
|
* nm_utils_ipaddr_valid:
|
2014-12-18 12:44:57 -05:00
|
|
|
* @family: <literal>AF_INET</literal> or <literal>AF_INET6</literal>, or
|
|
|
|
|
* <literal>AF_UNSPEC</literal> to accept either
|
2014-09-16 16:42:46 -04:00
|
|
|
* @ip: an IP address
|
|
|
|
|
*
|
|
|
|
|
* Checks if @ip contains a valid IP address of the given family.
|
|
|
|
|
*
|
2023-03-02 11:59:17 +01:00
|
|
|
* Returns: %TRUE or %FALSE
|
2014-09-16 16:42:46 -04:00
|
|
|
*/
|
|
|
|
|
gboolean
|
|
|
|
|
nm_utils_ipaddr_valid(int family, const char *ip)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail(family == AF_INET || family == AF_INET6 || family == AF_UNSPEC, FALSE);
|
|
|
|
|
|
glib-aux: rename IP address related helpers from "nm-inet-utils.h"
- name things related to `in_addr_t`, `struct in6_addr`, `NMIPAddr` as
`nm_ip4_addr_*()`, `nm_ip6_addr_*()`, `nm_ip_addr_*()`, respectively.
- we have a wrapper `nm_inet_ntop()` for `inet_ntop()`. This name
of our wrapper is chosen to be familiar with the libc underlying
function. With this, also name functions that are about string
representations of addresses `nm_inet_*()`, `nm_inet4_*()`,
`nm_inet6_*()`. For example, `nm_inet_parse_str()`,
`nm_inet_is_normalized()`.
<<<<
R() {
git grep -l "$1" | xargs sed -i "s/\<$1\>/$2/g"
}
R NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX NM_CMP_DIRECT_IP4_ADDR_SAME_PREFIX
R NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX NM_CMP_DIRECT_IP6_ADDR_SAME_PREFIX
R NM_UTILS_INET_ADDRSTRLEN NM_INET_ADDRSTRLEN
R _nm_utils_inet4_ntop nm_inet4_ntop
R _nm_utils_inet6_ntop nm_inet6_ntop
R _nm_utils_ip4_get_default_prefix nm_ip4_addr_get_default_prefix
R _nm_utils_ip4_get_default_prefix0 nm_ip4_addr_get_default_prefix0
R _nm_utils_ip4_netmask_to_prefix nm_ip4_addr_netmask_to_prefix
R _nm_utils_ip4_prefix_to_netmask nm_ip4_addr_netmask_from_prefix
R nm_utils_inet4_ntop_dup nm_inet4_ntop_dup
R nm_utils_inet6_ntop_dup nm_inet6_ntop_dup
R nm_utils_inet_ntop nm_inet_ntop
R nm_utils_inet_ntop_dup nm_inet_ntop_dup
R nm_utils_ip4_address_clear_host_address nm_ip4_addr_clear_host_address
R nm_utils_ip4_address_is_link_local nm_ip4_addr_is_link_local
R nm_utils_ip4_address_is_loopback nm_ip4_addr_is_loopback
R nm_utils_ip4_address_is_zeronet nm_ip4_addr_is_zeronet
R nm_utils_ip4_address_same_prefix nm_ip4_addr_same_prefix
R nm_utils_ip4_address_same_prefix_cmp nm_ip4_addr_same_prefix_cmp
R nm_utils_ip6_address_clear_host_address nm_ip6_addr_clear_host_address
R nm_utils_ip6_address_same_prefix nm_ip6_addr_same_prefix
R nm_utils_ip6_address_same_prefix_cmp nm_ip6_addr_same_prefix_cmp
R nm_utils_ip6_is_ula nm_ip6_addr_is_ula
R nm_utils_ip_address_same_prefix nm_ip_addr_same_prefix
R nm_utils_ip_address_same_prefix_cmp nm_ip_addr_same_prefix_cmp
R nm_utils_ip_is_site_local nm_ip_addr_is_site_local
R nm_utils_ipaddr_is_normalized nm_inet_is_normalized
R nm_utils_ipaddr_is_valid nm_inet_is_valid
R nm_utils_ipx_address_clear_host_address nm_ip_addr_clear_host_address
R nm_utils_parse_inaddr nm_inet_parse_str
R nm_utils_parse_inaddr_bin nm_inet_parse_bin
R nm_utils_parse_inaddr_bin_full nm_inet_parse_bin_full
R nm_utils_parse_inaddr_prefix nm_inet_parse_with_prefix_str
R nm_utils_parse_inaddr_prefix_bin nm_inet_parse_with_prefix_bin
R test_nm_utils_ip6_address_same_prefix test_nm_ip_addr_same_prefix
./contrib/scripts/nm-code-format.sh -F
2022-08-19 13:15:20 +02:00
|
|
|
return nm_inet_is_valid(family, ip);
|
2014-09-16 16:42:46 -04:00
|
|
|
}
|
|
|
|
|
|
2018-03-06 16:10:01 +01:00
|
|
|
/**
|
|
|
|
|
* _nm_utils_dhcp_duid_valid:
|
|
|
|
|
* @duid: the candidate DUID
|
|
|
|
|
*
|
|
|
|
|
* Checks if @duid string contains either a special duid value ("ll",
|
|
|
|
|
* "llt", "lease" or the "stable" variants) or a valid hex DUID.
|
|
|
|
|
*
|
2023-03-02 11:59:17 +01:00
|
|
|
* Returns: %TRUE or %FALSE
|
2018-03-06 16:10:01 +01:00
|
|
|
*/
|
|
|
|
|
gboolean
|
|
|
|
|
_nm_utils_dhcp_duid_valid(const char *duid, GBytes **out_duid_bin)
|
|
|
|
|
{
|
2018-06-11 13:19:40 +02:00
|
|
|
guint8 duid_arr[128 + 2];
|
2018-03-06 16:10:01 +01:00
|
|
|
gsize duid_len;
|
|
|
|
|
|
2018-06-11 13:19:40 +02:00
|
|
|
NM_SET_OUT(out_duid_bin, NULL);
|
2018-03-06 16:10:01 +01:00
|
|
|
|
|
|
|
|
if (!duid)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (NM_IN_STRSET(duid, "lease", "llt", "ll", "stable-llt", "stable-ll", "stable-uuid")) {
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-22 16:59:22 +02:00
|
|
|
if (nm_utils_hexstr2bin_full(duid,
|
|
|
|
|
FALSE,
|
|
|
|
|
FALSE,
|
|
|
|
|
FALSE,
|
|
|
|
|
":",
|
|
|
|
|
0,
|
|
|
|
|
duid_arr,
|
|
|
|
|
sizeof(duid_arr),
|
|
|
|
|
&duid_len)) {
|
2018-06-11 13:19:40 +02:00
|
|
|
/* MAX DUID length is 128 octects + the type code (2 octects). */
|
|
|
|
|
if (duid_len > 2 && duid_len <= (128 + 2)) {
|
|
|
|
|
NM_SET_OUT(out_duid_bin, g_bytes_new(duid_arr, duid_len));
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
}
|
2018-03-06 16:10:01 +01:00
|
|
|
|
2018-06-11 13:19:40 +02:00
|
|
|
return FALSE;
|
2018-03-06 16:10:01 +01:00
|
|
|
}
|
|
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
/**
|
|
|
|
|
* nm_utils_check_virtual_device_compatibility:
|
|
|
|
|
* @virtual_type: a virtual connection type
|
|
|
|
|
* @other_type: a connection type to test against @virtual_type
|
|
|
|
|
*
|
|
|
|
|
* Determines if a connection of type @virtual_type can (in the
|
|
|
|
|
* general case) work with connections of type @other_type.
|
|
|
|
|
*
|
|
|
|
|
* If @virtual_type is %NM_TYPE_SETTING_VLAN, then this checks if
|
|
|
|
|
* @other_type is a valid type for the parent of a VLAN.
|
|
|
|
|
*
|
2024-05-27 17:58:08 +02:00
|
|
|
* If @virtual_type is a "controller" type (eg, %NM_TYPE_SETTING_BRIDGE),
|
2024-07-04 12:45:42 +02:00
|
|
|
* then this checks if @other_type is a valid type for a port of that
|
2024-05-27 17:58:08 +02:00
|
|
|
* controller.
|
2014-07-24 08:53:33 -04:00
|
|
|
*
|
|
|
|
|
* Note that even if this returns %TRUE it is not guaranteed that
|
|
|
|
|
* <emphasis>every</emphasis> connection of type @other_type is
|
|
|
|
|
* compatible with @virtual_type; it may depend on the exact
|
|
|
|
|
* configuration of the two connections, or on the capabilities of an
|
|
|
|
|
* underlying device driver.
|
|
|
|
|
*
|
|
|
|
|
* Returns: %TRUE or %FALSE
|
|
|
|
|
*/
|
|
|
|
|
gboolean
|
|
|
|
|
nm_utils_check_virtual_device_compatibility(GType virtual_type, GType other_type)
|
|
|
|
|
{
|
2017-06-01 13:43:52 +02:00
|
|
|
g_return_val_if_fail(_nm_setting_type_get_base_type_priority(virtual_type)
|
|
|
|
|
!= NM_SETTING_PRIORITY_INVALID,
|
|
|
|
|
FALSE);
|
|
|
|
|
g_return_val_if_fail(_nm_setting_type_get_base_type_priority(other_type)
|
|
|
|
|
!= NM_SETTING_PRIORITY_INVALID,
|
2020-09-28 16:03:33 +02:00
|
|
|
FALSE);
|
|
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
if (virtual_type == NM_TYPE_SETTING_BOND) {
|
2021-08-25 08:18:36 +02:00
|
|
|
return NM_IN_SET(other_type,
|
|
|
|
|
NM_TYPE_SETTING_BOND,
|
|
|
|
|
NM_TYPE_SETTING_BRIDGE,
|
|
|
|
|
NM_TYPE_SETTING_INFINIBAND,
|
|
|
|
|
NM_TYPE_SETTING_TEAM,
|
|
|
|
|
NM_TYPE_SETTING_VLAN,
|
|
|
|
|
NM_TYPE_SETTING_WIRED,
|
|
|
|
|
NM_TYPE_SETTING_WIRELESS);
|
|
|
|
|
}
|
|
|
|
|
if (virtual_type == NM_TYPE_SETTING_BRIDGE) {
|
|
|
|
|
return NM_IN_SET(other_type,
|
|
|
|
|
NM_TYPE_SETTING_BOND,
|
|
|
|
|
NM_TYPE_SETTING_TEAM,
|
|
|
|
|
NM_TYPE_SETTING_VLAN,
|
|
|
|
|
NM_TYPE_SETTING_WIRED);
|
|
|
|
|
}
|
|
|
|
|
if (virtual_type == NM_TYPE_SETTING_TEAM) {
|
|
|
|
|
return NM_IN_SET(other_type,
|
|
|
|
|
NM_TYPE_SETTING_BOND,
|
|
|
|
|
NM_TYPE_SETTING_BRIDGE,
|
|
|
|
|
NM_TYPE_SETTING_TEAM,
|
|
|
|
|
NM_TYPE_SETTING_VLAN,
|
|
|
|
|
NM_TYPE_SETTING_WIRED);
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
2021-08-25 08:18:36 +02:00
|
|
|
if (virtual_type == NM_TYPE_SETTING_VLAN) {
|
|
|
|
|
return NM_IN_SET(other_type,
|
|
|
|
|
NM_TYPE_SETTING_BOND,
|
|
|
|
|
NM_TYPE_SETTING_BRIDGE,
|
|
|
|
|
NM_TYPE_SETTING_TEAM,
|
|
|
|
|
NM_TYPE_SETTING_VLAN,
|
|
|
|
|
NM_TYPE_SETTING_WIRED,
|
|
|
|
|
NM_TYPE_SETTING_WIRELESS);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
2014-12-16 18:13:14 +01:00
|
|
|
|
2020-10-15 10:18:56 +02:00
|
|
|
/*****************************************************************************/
|
2014-12-16 18:13:14 +01:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_utils_bond_mode_int_to_string:
|
|
|
|
|
* @mode: bonding mode as a numeric value
|
|
|
|
|
*
|
|
|
|
|
* Convert bonding mode from integer value to descriptive name.
|
|
|
|
|
* See https://www.kernel.org/doc/Documentation/networking/bonding.txt for
|
|
|
|
|
* available modes.
|
|
|
|
|
*
|
|
|
|
|
* Returns: bonding mode string, or NULL on error
|
2015-01-15 16:42:26 -05:00
|
|
|
*
|
|
|
|
|
* Since: 1.2
|
|
|
|
|
*/
|
2014-12-16 18:13:14 +01:00
|
|
|
const char *
|
|
|
|
|
nm_utils_bond_mode_int_to_string(int mode)
|
|
|
|
|
{
|
2020-10-15 10:18:56 +02:00
|
|
|
return _nm_setting_bond_mode_to_string(mode);
|
2014-12-16 18:13:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_utils_bond_mode_string_to_int:
|
|
|
|
|
* @mode: bonding mode as string
|
|
|
|
|
*
|
|
|
|
|
* Convert bonding mode from string representation to numeric value.
|
|
|
|
|
* See https://www.kernel.org/doc/Documentation/networking/bonding.txt for
|
|
|
|
|
* available modes.
|
|
|
|
|
* The @mode string can be either a descriptive name or a number (as string).
|
|
|
|
|
*
|
|
|
|
|
* Returns: numeric bond mode, or -1 on error
|
2015-01-15 16:42:26 -05:00
|
|
|
*
|
|
|
|
|
* Since: 1.2
|
|
|
|
|
*/
|
2014-12-16 18:13:14 +01:00
|
|
|
int
|
|
|
|
|
nm_utils_bond_mode_string_to_int(const char *mode)
|
|
|
|
|
{
|
2020-10-15 10:18:56 +02:00
|
|
|
return _nm_setting_bond_mode_from_string(mode);
|
2014-12-16 18:13:14 +01:00
|
|
|
}
|
2015-02-22 11:54:03 +01:00
|
|
|
|
2016-10-02 18:22:50 +02:00
|
|
|
/*****************************************************************************/
|
2015-02-22 11:54:03 +01:00
|
|
|
|
2015-05-22 18:52:22 +02:00
|
|
|
#define STRSTRDICTKEY_V1_SET 0x01
|
|
|
|
|
#define STRSTRDICTKEY_V2_SET 0x02
|
|
|
|
|
#define STRSTRDICTKEY_ALL_SET 0x03
|
|
|
|
|
|
|
|
|
|
struct _NMUtilsStrStrDictKey {
|
|
|
|
|
char type;
|
2024-01-23 10:27:13 +01:00
|
|
|
char data[];
|
2015-05-22 18:52:22 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
guint
|
|
|
|
|
_nm_utils_strstrdictkey_hash(gconstpointer a)
|
|
|
|
|
{
|
|
|
|
|
const NMUtilsStrStrDictKey *k = a;
|
2021-11-09 13:28:54 +01:00
|
|
|
const char *p;
|
2017-10-13 14:00:22 +02:00
|
|
|
NMHashState h;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-10-13 14:00:22 +02:00
|
|
|
nm_hash_init(&h, 76642997u);
|
2015-05-22 18:52:22 +02:00
|
|
|
if (k) {
|
|
|
|
|
if (((int) k->type) & ~STRSTRDICTKEY_ALL_SET)
|
|
|
|
|
g_return_val_if_reached(0);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-10-16 12:38:16 +02:00
|
|
|
nm_hash_update_val(&h, k->type);
|
2015-05-22 18:52:22 +02:00
|
|
|
if (k->type & STRSTRDICTKEY_ALL_SET) {
|
2017-10-16 12:38:16 +02:00
|
|
|
p = strchr(k->data, '\0');
|
2015-05-22 18:52:22 +02:00
|
|
|
if (k->type == STRSTRDICTKEY_ALL_SET) {
|
|
|
|
|
/* the key contains two strings. Continue... */
|
2017-10-16 12:38:16 +02:00
|
|
|
p = strchr(p + 1, '\0');
|
2015-05-22 18:52:22 +02:00
|
|
|
}
|
2017-10-16 12:38:16 +02:00
|
|
|
if (p != k->data)
|
|
|
|
|
nm_hash_update(&h, k->data, p - k->data);
|
2015-05-22 18:52:22 +02:00
|
|
|
}
|
|
|
|
|
}
|
2017-10-13 14:00:22 +02:00
|
|
|
return nm_hash_complete(&h);
|
2015-05-22 18:52:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
|
_nm_utils_strstrdictkey_equal(gconstpointer a, gconstpointer b)
|
|
|
|
|
{
|
|
|
|
|
const NMUtilsStrStrDictKey *k1 = a;
|
|
|
|
|
const NMUtilsStrStrDictKey *k2 = b;
|
|
|
|
|
|
|
|
|
|
if (k1 == k2)
|
|
|
|
|
return TRUE;
|
|
|
|
|
if (!k1 || !k2)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (k1->type != k2->type)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (k1->type & STRSTRDICTKEY_ALL_SET) {
|
2020-06-21 21:48:59 +02:00
|
|
|
if (!nm_streq(k1->data, k2->data))
|
2015-05-22 18:52:22 +02:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (k1->type == STRSTRDICTKEY_ALL_SET) {
|
|
|
|
|
gsize l = strlen(k1->data) + 1;
|
|
|
|
|
|
2020-06-21 21:48:59 +02:00
|
|
|
return nm_streq(&k1->data[l], &k2->data[l]);
|
2015-05-22 18:52:22 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NMUtilsStrStrDictKey *
|
|
|
|
|
_nm_utils_strstrdictkey_create(const char *v1, const char *v2)
|
|
|
|
|
{
|
|
|
|
|
char type = 0;
|
|
|
|
|
gsize l1 = 0, l2 = 0;
|
|
|
|
|
NMUtilsStrStrDictKey *k;
|
|
|
|
|
|
|
|
|
|
if (!v1 && !v2)
|
|
|
|
|
return g_malloc0(1);
|
|
|
|
|
|
|
|
|
|
/* we need to distinguish between ("",NULL) and (NULL,"").
|
|
|
|
|
* Thus, in @type we encode which strings we have present
|
|
|
|
|
* as not-NULL. */
|
|
|
|
|
if (v1) {
|
|
|
|
|
type |= STRSTRDICTKEY_V1_SET;
|
|
|
|
|
l1 = strlen(v1) + 1;
|
|
|
|
|
}
|
|
|
|
|
if (v2) {
|
|
|
|
|
type |= STRSTRDICTKEY_V2_SET;
|
|
|
|
|
l2 = strlen(v2) + 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
k = g_malloc(G_STRUCT_OFFSET(NMUtilsStrStrDictKey, data) + l1 + l2);
|
|
|
|
|
k->type = type;
|
|
|
|
|
if (v1)
|
|
|
|
|
memcpy(&k->data[0], v1, l1);
|
|
|
|
|
if (v2)
|
|
|
|
|
memcpy(&k->data[l1], v2, l2);
|
|
|
|
|
|
|
|
|
|
return k;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-26 08:57:02 +01:00
|
|
|
static gboolean
|
2021-11-09 13:28:54 +01:00
|
|
|
validate_dns_option(const char *name,
|
2020-04-20 15:40:43 +02:00
|
|
|
gboolean numeric,
|
2023-11-15 19:53:44 +01:00
|
|
|
int addr_family,
|
2015-05-20 12:31:10 +02:00
|
|
|
const NMUtilsDNSOptionDesc *option_descs)
|
2015-03-26 08:57:02 +01:00
|
|
|
{
|
2015-05-20 12:31:10 +02:00
|
|
|
const NMUtilsDNSOptionDesc *desc;
|
2015-03-26 08:57:02 +01:00
|
|
|
|
|
|
|
|
if (!option_descs)
|
|
|
|
|
return !!*name;
|
|
|
|
|
|
|
|
|
|
for (desc = option_descs; desc->name; desc++) {
|
2023-11-15 19:53:44 +01:00
|
|
|
if (!nm_streq(name, desc->name))
|
|
|
|
|
continue;
|
|
|
|
|
if ((!!numeric) != (!!desc->numeric))
|
|
|
|
|
continue;
|
|
|
|
|
if (addr_family != AF_UNSPEC) {
|
|
|
|
|
if (desc->ipv6_only && addr_family != AF_INET6)
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
return TRUE;
|
2015-03-26 08:57:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2015-08-05 16:33:44 +02:00
|
|
|
* _nm_utils_dns_option_validate:
|
2015-03-26 08:57:02 +01:00
|
|
|
* @option: option string
|
2023-03-01 01:21:38 +01:00
|
|
|
* @out_name: (out) (optional) (nullable): the option name
|
|
|
|
|
* @out_value: (out) (optional): the option value
|
2023-11-15 19:53:44 +01:00
|
|
|
* @addr_family: AF_INET/AF_INET6 to only allow options for the specified address
|
|
|
|
|
* family. AF_UNSPEC to allow either. This argument is ignored, if @option_descs
|
|
|
|
|
* is NULL.
|
2023-03-01 01:21:38 +01:00
|
|
|
* @option_descs: (nullable): an array of NMUtilsDNSOptionDesc which describes the
|
2015-03-26 08:57:02 +01:00
|
|
|
* valid options
|
|
|
|
|
*
|
|
|
|
|
* Parses a DNS option in the form "name" or "name:number" and, if
|
|
|
|
|
* @option_descs is not NULL, checks that the option conforms to one
|
|
|
|
|
* of the provided descriptors. If @option_descs is NULL @ipv6 is
|
|
|
|
|
* not considered.
|
|
|
|
|
*
|
|
|
|
|
* Returns: %TRUE when the parsing was successful and the option is valid,
|
|
|
|
|
* %FALSE otherwise
|
|
|
|
|
*/
|
|
|
|
|
gboolean
|
2021-11-09 13:28:54 +01:00
|
|
|
_nm_utils_dns_option_validate(const char *option,
|
|
|
|
|
char **out_name,
|
|
|
|
|
long *out_value,
|
2023-11-15 19:53:44 +01:00
|
|
|
int addr_family,
|
2015-05-20 12:31:10 +02:00
|
|
|
const NMUtilsDNSOptionDesc *option_descs)
|
2015-03-26 08:57:02 +01:00
|
|
|
{
|
2020-04-20 15:40:43 +02:00
|
|
|
gs_free char *option0_free = NULL;
|
2021-11-09 13:28:54 +01:00
|
|
|
const char *option0;
|
|
|
|
|
const char *option1;
|
|
|
|
|
const char *delim;
|
2020-04-20 15:40:43 +02:00
|
|
|
long option1_num;
|
2015-03-26 08:57:02 +01:00
|
|
|
|
|
|
|
|
g_return_val_if_fail(option != NULL, FALSE);
|
|
|
|
|
|
2023-11-15 19:53:44 +01:00
|
|
|
nm_assert_addr_family_or_unspec(addr_family);
|
|
|
|
|
|
2020-04-20 15:40:43 +02:00
|
|
|
NM_SET_OUT(out_name, NULL);
|
|
|
|
|
NM_SET_OUT(out_value, -1);
|
2015-03-26 08:57:02 +01:00
|
|
|
|
|
|
|
|
if (!option[0])
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2020-04-20 15:40:43 +02:00
|
|
|
delim = strchr(option, ':');
|
|
|
|
|
if (!delim) {
|
2023-11-15 19:53:44 +01:00
|
|
|
if (!validate_dns_option(option, FALSE, addr_family, option_descs))
|
2020-04-20 15:40:43 +02:00
|
|
|
return FALSE;
|
|
|
|
|
NM_SET_OUT(out_name, g_strdup(option));
|
|
|
|
|
return TRUE;
|
2015-03-26 08:57:02 +01:00
|
|
|
}
|
|
|
|
|
|
2020-04-20 15:40:43 +02:00
|
|
|
option1 = &delim[1];
|
2015-03-26 08:57:02 +01:00
|
|
|
|
2020-04-20 15:40:43 +02:00
|
|
|
if (!option1[0])
|
|
|
|
|
return FALSE;
|
|
|
|
|
if (!NM_STRCHAR_ALL(option1, ch, g_ascii_isdigit(ch)))
|
|
|
|
|
return FALSE;
|
2015-03-26 08:57:02 +01:00
|
|
|
|
2020-04-20 15:40:43 +02:00
|
|
|
option0 = nm_strndup_a(300, option, delim - option, &option0_free);
|
|
|
|
|
|
2023-11-15 19:53:44 +01:00
|
|
|
if (!validate_dns_option(option0, TRUE, addr_family, option_descs))
|
2020-04-20 15:40:43 +02:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
option1_num = _nm_utils_ascii_str_to_int64(option1, 10, 0, G_MAXINT32, -1);
|
|
|
|
|
if (option1_num == -1)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
NM_SET_OUT(out_name, g_steal_pointer(&option0_free) ?: g_strdup(option0));
|
|
|
|
|
NM_SET_OUT(out_value, option1_num);
|
|
|
|
|
return TRUE;
|
2015-03-26 08:57:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2015-08-05 16:33:44 +02:00
|
|
|
* _nm_utils_dns_option_find_idx:
|
2023-11-15 20:16:18 +01:00
|
|
|
* @strv: an array of strings of length @strv_len
|
|
|
|
|
* @strv_len: the length of @strv, or -1 for a NULL terminated strv array.
|
2015-03-26 08:57:02 +01:00
|
|
|
* @option: a dns option string
|
|
|
|
|
*
|
|
|
|
|
* Searches for an option in an array of strings. The match is
|
|
|
|
|
* performed only the option name; the option value is ignored.
|
|
|
|
|
*
|
|
|
|
|
* Returns: the index of the option in the array or -1 if was not
|
|
|
|
|
* found.
|
|
|
|
|
*/
|
2017-09-27 11:54:51 +02:00
|
|
|
gssize
|
2023-11-15 20:16:18 +01:00
|
|
|
_nm_utils_dns_option_find_idx(const char *const *strv, gssize strv_len, const char *option)
|
2015-03-26 08:57:02 +01:00
|
|
|
{
|
2020-06-21 21:48:59 +02:00
|
|
|
gs_free char *option_name = NULL;
|
2023-11-15 20:16:18 +01:00
|
|
|
gsize l;
|
|
|
|
|
gsize i;
|
|
|
|
|
|
|
|
|
|
if (strv_len >= 0)
|
|
|
|
|
l = strv_len;
|
|
|
|
|
else
|
|
|
|
|
l = NM_PTRARRAY_LEN(strv);
|
|
|
|
|
|
|
|
|
|
if (l == 0)
|
|
|
|
|
return -1;
|
2015-03-26 08:57:02 +01:00
|
|
|
|
2023-11-15 19:53:44 +01:00
|
|
|
if (!_nm_utils_dns_option_validate(option, &option_name, NULL, AF_UNSPEC, NULL))
|
2015-03-26 08:57:02 +01:00
|
|
|
return -1;
|
|
|
|
|
|
2023-11-15 20:16:18 +01:00
|
|
|
for (i = 0; i < l; i++) {
|
|
|
|
|
const char *str = strv[i];
|
2020-06-21 21:48:59 +02:00
|
|
|
gs_free char *tmp_name = NULL;
|
|
|
|
|
|
2023-11-15 20:16:18 +01:00
|
|
|
if (_nm_utils_dns_option_validate(str, &tmp_name, NULL, AF_UNSPEC, NULL)) {
|
2020-06-21 21:48:59 +02:00
|
|
|
if (nm_streq(tmp_name, option_name))
|
2015-03-26 08:57:02 +01:00
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-05 18:32:23 +02:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_utils_enum_to_str:
|
|
|
|
|
* @type: the %GType of the enum
|
|
|
|
|
* @value: the value to be translated
|
|
|
|
|
*
|
|
|
|
|
* Converts an enum value to its string representation. If the enum is a
|
|
|
|
|
* %G_TYPE_FLAGS the function returns a comma-separated list of matching values.
|
|
|
|
|
* If the value has no corresponding string representation, it is converted
|
|
|
|
|
* to a number. For enums it is converted to a decimal number, for flags
|
|
|
|
|
* to an (unsigned) hex number.
|
|
|
|
|
*
|
|
|
|
|
* Returns: a newly allocated string or %NULL
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.2
|
|
|
|
|
*/
|
|
|
|
|
char *
|
|
|
|
|
nm_utils_enum_to_str(GType type, int value)
|
|
|
|
|
{
|
2018-04-04 09:31:54 +02:00
|
|
|
return _nm_utils_enum_to_str_full(type, value, ", ", NULL);
|
2017-04-05 18:32:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_utils_enum_from_str:
|
|
|
|
|
* @type: the %GType of the enum
|
|
|
|
|
* @str: the input string
|
2023-03-01 01:21:38 +01:00
|
|
|
* @out_value: (out) (optional): the output value
|
|
|
|
|
* @err_token: (out) (optional) (nullable) (transfer full): location to store
|
|
|
|
|
* the first unrecognized token
|
2017-04-05 18:32:23 +02:00
|
|
|
*
|
|
|
|
|
* Converts a string to the matching enum value.
|
|
|
|
|
*
|
|
|
|
|
* If the enum is a %G_TYPE_FLAGS the function returns the logical OR of values
|
|
|
|
|
* matching the comma-separated tokens in the string; if an unknown token is found
|
|
|
|
|
* the function returns %FALSE and stores a pointer to a newly allocated string
|
|
|
|
|
* containing the unrecognized token in @err_token.
|
|
|
|
|
*
|
|
|
|
|
* Returns: %TRUE if the conversion was successful, %FALSE otherwise
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.2
|
|
|
|
|
*/
|
|
|
|
|
gboolean
|
|
|
|
|
nm_utils_enum_from_str(GType type, const char *str, int *out_value, char **err_token)
|
|
|
|
|
{
|
|
|
|
|
return _nm_utils_enum_from_str_full(type, str, out_value, err_token, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_utils_enum_get_values:
|
|
|
|
|
* @type: the %GType of the enum
|
|
|
|
|
* @from: the first element to be returned
|
|
|
|
|
* @to: the last element to be returned
|
|
|
|
|
*
|
|
|
|
|
* Returns the list of possible values for a given enum.
|
|
|
|
|
*
|
|
|
|
|
* Returns: (transfer container): a NULL-terminated dynamically-allocated array of static strings
|
|
|
|
|
* or %NULL on error
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.2
|
|
|
|
|
*/
|
all: don't use gchar/gshort/gint/glong but C types
We commonly don't use the glib typedefs for char/short/int/long,
but their C types directly.
$ git grep '\<g\(char\|short\|int\|long\|float\|double\)\>' | wc -l
587
$ git grep '\<\(char\|short\|int\|long\|float\|double\)\>' | wc -l
21114
One could argue that using the glib typedefs is preferable in
public API (of our glib based libnm library) or where it clearly
is related to glib, like during
g_object_set (obj, PROPERTY, (gint) value, NULL);
However, that argument does not seem strong, because in practice we don't
follow that argument today, and seldomly use the glib typedefs.
Also, the style guide for this would be hard to formalize, because
"using them where clearly related to a glib" is a very loose suggestion.
Also note that glib typedefs will always just be typedefs of the
underlying C types. There is no danger of glib changing the meaning
of these typedefs (because that would be a major API break of glib).
A simple style guide is instead: don't use these typedefs.
No manual actions, I only ran the bash script:
FILES=($(git ls-files '*.[hc]'))
sed -i \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\>\( [^ ]\)/\1\2/g' \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\> /\1 /g' \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\>/\1/g' \
"${FILES[@]}"
2018-07-11 07:40:19 +02:00
|
|
|
const char **
|
|
|
|
|
nm_utils_enum_get_values(GType type, int from, int to)
|
2017-04-05 18:32:23 +02:00
|
|
|
{
|
|
|
|
|
return _nm_utils_enum_get_values(type, from, to);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2017-12-26 09:28:54 +01:00
|
|
|
static gboolean
|
|
|
|
|
_nm_utils_is_json_object_no_validation(const char *str, GError **error)
|
|
|
|
|
{
|
2018-10-04 09:35:35 +02:00
|
|
|
nm_assert(str);
|
|
|
|
|
|
|
|
|
|
/* libjansson also requires only utf-8 encoding. */
|
|
|
|
|
if (!g_utf8_validate(str, -1, NULL)) {
|
|
|
|
|
g_set_error_literal(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("not valid utf-8"));
|
|
|
|
|
return FALSE;
|
2017-12-26 09:28:54 +01:00
|
|
|
}
|
2018-10-04 09:35:35 +02:00
|
|
|
while (g_ascii_isspace(str[0]))
|
|
|
|
|
str++;
|
2017-12-26 09:28:54 +01:00
|
|
|
|
|
|
|
|
/* do some very basic validation to see if this might be a JSON object. */
|
|
|
|
|
if (str[0] == '{') {
|
|
|
|
|
gsize l;
|
|
|
|
|
|
|
|
|
|
l = strlen(str) - 1;
|
|
|
|
|
while (l > 0 && g_ascii_isspace(str[l]))
|
|
|
|
|
l--;
|
|
|
|
|
|
|
|
|
|
if (str[l] == '}')
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_set_error_literal(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("is not a JSON object"));
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-23 10:30:50 +02:00
|
|
|
/**
|
|
|
|
|
* nm_utils_is_json_object:
|
|
|
|
|
* @str: the JSON string to test
|
|
|
|
|
* @error: optional error reason
|
|
|
|
|
*
|
|
|
|
|
* Returns: whether the passed string is valid JSON.
|
|
|
|
|
* If libnm is not compiled with libjansson support, this check will
|
|
|
|
|
* also return %TRUE for possibly invalid inputs. If that is a problem
|
|
|
|
|
* for you, you must validate the JSON yourself.
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.6
|
|
|
|
|
*/
|
2016-03-11 13:17:24 +01:00
|
|
|
gboolean
|
2016-09-23 10:30:50 +02:00
|
|
|
nm_utils_is_json_object(const char *str, GError **error)
|
2016-03-11 13:17:24 +01:00
|
|
|
{
|
2018-01-09 11:12:10 +01:00
|
|
|
nm_auto_decref_json nm_json_t *json = NULL;
|
2021-11-09 13:28:54 +01:00
|
|
|
const NMJsonVt *vt;
|
2018-01-09 11:12:10 +01:00
|
|
|
nm_json_error_t jerror;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2016-03-11 13:17:24 +01:00
|
|
|
g_return_val_if_fail(!error || !*error, FALSE);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2016-03-11 13:17:24 +01:00
|
|
|
if (!str || !str[0]) {
|
|
|
|
|
g_set_error_literal(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
2016-09-23 10:30:50 +02:00
|
|
|
str ? _("value is NULL") : _("value is empty"));
|
2016-03-11 13:17:24 +01:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm: don't use any symbols from jansson.h directly
Some symbols in jansson.h are macros, some are regular functions,
and some are inline functions.
Regular functions must not be used directly, only via dlsym().
Macros must be used directly, but it is non-obvious which symbols
are macros. Hence, for each json_* macro add an nm_json_* alias.
Inline functions are a bit odd. If they are inlined and don't use
any non-inlined symbols from libjansson, they could be used directly.
However, it's non obvious whether both of the conditions are met.
Hence, we reimplement them in nm-json.h. The only function of this kind
is json_decref().
The point is to not use any json_* symbols directly -- except structs
and typedefs.
Seemingly, with this change we don't use any jansson symbols directly.
However, that is not true, as macros like nm_json_object_foreach()
still are implemented based on what is included from <jansson.h>.
Hence, we cannot drop patching the included jansson.h header yet and
still need our wrapper functions.
2018-01-09 09:15:04 +01:00
|
|
|
if (!(vt = nm_json_vt()))
|
2017-12-26 09:28:54 +01:00
|
|
|
return _nm_utils_is_json_object_no_validation(str, error);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-01-09 11:12:10 +01:00
|
|
|
json = vt->nm_json_loads(str, NM_JSON_REJECT_DUPLICATES, &jerror);
|
2016-03-11 13:17:24 +01:00
|
|
|
if (!json) {
|
|
|
|
|
g_set_error(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
2016-09-23 10:30:50 +02:00
|
|
|
_("invalid JSON at position %d (%s)"),
|
|
|
|
|
jerror.position,
|
|
|
|
|
jerror.text);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2016-09-23 10:30:50 +02:00
|
|
|
/* valid JSON (depending on the definition) can also be a literal.
|
|
|
|
|
* Here we only allow objects. */
|
libnm: don't use any symbols from jansson.h directly
Some symbols in jansson.h are macros, some are regular functions,
and some are inline functions.
Regular functions must not be used directly, only via dlsym().
Macros must be used directly, but it is non-obvious which symbols
are macros. Hence, for each json_* macro add an nm_json_* alias.
Inline functions are a bit odd. If they are inlined and don't use
any non-inlined symbols from libjansson, they could be used directly.
However, it's non obvious whether both of the conditions are met.
Hence, we reimplement them in nm-json.h. The only function of this kind
is json_decref().
The point is to not use any json_* symbols directly -- except structs
and typedefs.
Seemingly, with this change we don't use any jansson symbols directly.
However, that is not true, as macros like nm_json_object_foreach()
still are implemented based on what is included from <jansson.h>.
Hence, we cannot drop patching the included jansson.h header yet and
still need our wrapper functions.
2018-01-09 09:15:04 +01:00
|
|
|
if (!nm_json_is_object(json)) {
|
2016-09-23 10:30:50 +02:00
|
|
|
g_set_error_literal(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("is not a JSON object"));
|
2016-03-11 13:17:24 +01:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
libnm: rework team handling of JSON config
Completely refactor the team/JSON handling in libnm's NMSettingTeam and
NMSettingTeamPort.
- team handling was added as rh#1398925. The goal is to have a more
convenient way to set properties than constructing JSON. This requires
libnm to implement the hard task of parsing JSON (and exposing well-understood
properties) and generating JSON (based on these "artificial" properties).
But not only libnm. In particular nmcli and the D-Bus API must make this
"simpler" API accessible.
- since NMSettingTeam and NMSettingTeamPort are conceptually the same,
add "libnm-core/nm-team-utils.h" and NMTeamSetting that tries to
handle the similar code side-by-sdie.
The setting classes now just delegate for everything to NMTeamSetting.
- Previously, there was a very fuzzy understanding of the provided
JSON config. Tighten that up, when setting a JSON config it
regenerates/parses all other properties and tries to make the
best of it. When modifying any abstraction property, the entire
JSON config gets regenerated. In particular, don't try to merge
existing JSON config with the new fields. If the user uses the
abstraction API, then the entire JSON gets replaced.
For example note that nm_setting_team_add_link_watcher() would not
be reflected in the JSON config (a bug). That only accidentally worked
because client would serializing the changed link watcher to
GVariant/D-Bus, then NetworkManager would set it via g_object_set(),
which would renerate the JSON, and finally persist it to disk. But
as far as libnm is concerned, nm_setting_team_add_link_watcher() would
bring the settings instance in an inconsistent state where JSON and
the link watcher property disagree. Setting any property must
immediately update both the JSON and the abstraction API.
- when constucting a team setting from D-Bus, we would previously parse
both "config" and abstraction properties. That is wrong. Since our
settings plugins only support JSON, all information must be present
in the JSON config anyway. So, when "config" is present, only the JSON
must be parsed. In the best case, the other information is redudant and
contributes nothing. In the worse case, they information differs
(which might happen if the client version differs from the server
version). As the settings plugin only supports JSON, it's wrong to
consider redundant, differing information from D-Bus.
- we now only convert string to JSON or back when needed. Previously,
setting a property resulted in parsing several JSON multiple times
(per property). All operations should now scale well and be reasonably
efficient.
- also the property-changed signals are now handled correctly. Since
NMTeamSetting knows the current state of all attributes, it can emit
the exact property changed signals for what changed.
- we no longer use libjansson to generate the JSON. JSON is supposed
to be a machine readable exchange format, hence a major goal is
to be easily handled by applications. While parsing JSON is not so
trivial, writing a well-known set of values to JSON is.
The advantage is that when you build libnm without libjansson support,
then we still can convert the artificial properties to JSON.
- Requiring libjansson in libnm is a burden, because most of the time
it is not needed (as most users don't create team configurations). With
this change we only require it to parse the team settings (no longer to
write them). It should be reasonably simple to use a more minimalistic
JSON parser that is sufficient for us, so that we can get rid of the
libjansson dependency (for libnm). This also avoids the pain that we have
due to the symbol collision of libjansson and libjson-glib.
https://bugzilla.redhat.com/show_bug.cgi?id=1691619
2019-05-06 12:36:41 +02:00
|
|
|
}
|
2016-12-20 16:36:15 +01:00
|
|
|
|
2017-03-02 11:08:34 +01:00
|
|
|
static char *
|
|
|
|
|
attribute_unescape(const char *start, const char *end)
|
|
|
|
|
{
|
|
|
|
|
char *ret, *dest;
|
|
|
|
|
|
|
|
|
|
nm_assert(start <= end);
|
|
|
|
|
dest = ret = g_malloc(end - start + 1);
|
|
|
|
|
|
|
|
|
|
for (; start < end && *start; start++) {
|
|
|
|
|
if (*start == '\\') {
|
|
|
|
|
start++;
|
|
|
|
|
if (!*start)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
*dest++ = *start;
|
|
|
|
|
}
|
|
|
|
|
*dest = '\0';
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-27 13:13:48 +01:00
|
|
|
gboolean
|
|
|
|
|
_nmtst_variant_attribute_spec_assert_sorted(const NMVariantAttributeSpec *const *array, gsize len)
|
|
|
|
|
{
|
|
|
|
|
gsize i;
|
|
|
|
|
|
|
|
|
|
g_assert(array);
|
|
|
|
|
g_assert(len > 0);
|
|
|
|
|
g_assert_cmpint(len, ==, NM_PTRARRAY_LEN(array));
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
|
nm_assert(array[i]->name);
|
|
|
|
|
nm_assert(array[i]->name[0]);
|
|
|
|
|
if (i > 0)
|
|
|
|
|
nm_assert(strcmp(array[i - 1]->name, array[i]->name) < 0);
|
|
|
|
|
}
|
|
|
|
|
nm_assert(!array[i]);
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const NMVariantAttributeSpec *
|
|
|
|
|
_nm_variant_attribute_spec_find_binary_search(const NMVariantAttributeSpec *const *array,
|
|
|
|
|
gsize len,
|
2021-11-09 13:28:54 +01:00
|
|
|
const char *name)
|
2019-11-27 13:13:48 +01:00
|
|
|
{
|
|
|
|
|
gssize idx;
|
|
|
|
|
|
|
|
|
|
G_STATIC_ASSERT_EXPR(G_STRUCT_OFFSET(NMVariantAttributeSpec, name) == 0);
|
|
|
|
|
|
2022-09-27 09:08:35 +02:00
|
|
|
idx =
|
|
|
|
|
nm_ptrarray_find_bsearch((gconstpointer *) array, len, &name, nm_strcmp_p_with_data, NULL);
|
2019-11-27 13:13:48 +01:00
|
|
|
if (idx < 0)
|
|
|
|
|
return NULL;
|
|
|
|
|
return array[idx];
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-02 11:08:34 +01:00
|
|
|
/**
|
|
|
|
|
* nm_utils_parse_variant_attributes:
|
|
|
|
|
* @string: the input string
|
|
|
|
|
* @attr_separator: the attribute separator character
|
|
|
|
|
* @key_value_separator: character separating key and values
|
|
|
|
|
* @ignore_unknown: whether unknown attributes should be ignored
|
|
|
|
|
* @spec: the attribute format specifiers
|
2023-03-01 01:21:38 +01:00
|
|
|
* @error: location to store the error on failure
|
2017-03-02 11:08:34 +01:00
|
|
|
*
|
|
|
|
|
* Parse attributes from a string.
|
|
|
|
|
*
|
2018-03-24 15:18:21 +00:00
|
|
|
* Returns: (transfer full) (element-type utf8 GVariant): a #GHashTable mapping
|
2018-09-14 17:06:36 +02:00
|
|
|
* attribute names to #GVariant values. Warning: the variant are still floating
|
|
|
|
|
* references, owned by the hash table. If you take a reference, ensure to sink
|
|
|
|
|
* the one of the hash table first.
|
2017-03-02 11:08:34 +01:00
|
|
|
*
|
|
|
|
|
* Since: 1.8
|
|
|
|
|
*/
|
|
|
|
|
GHashTable *
|
2021-11-09 13:28:54 +01:00
|
|
|
nm_utils_parse_variant_attributes(const char *string,
|
2017-03-02 11:08:34 +01:00
|
|
|
char attr_separator,
|
|
|
|
|
char key_value_separator,
|
|
|
|
|
gboolean ignore_unknown,
|
|
|
|
|
const NMVariantAttributeSpec *const *spec,
|
2021-11-09 13:28:54 +01:00
|
|
|
GError **error)
|
2017-03-02 11:08:34 +01:00
|
|
|
{
|
2021-11-09 13:28:54 +01:00
|
|
|
gs_unref_hashtable GHashTable *ht = NULL;
|
|
|
|
|
const char *ptr = string, *start = NULL, *sep;
|
|
|
|
|
GVariant *variant;
|
2019-05-01 11:56:29 +02:00
|
|
|
const NMVariantAttributeSpec *const *s;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-03-02 11:08:34 +01:00
|
|
|
g_return_val_if_fail(string, NULL);
|
|
|
|
|
g_return_val_if_fail(attr_separator, NULL);
|
|
|
|
|
g_return_val_if_fail(key_value_separator, NULL);
|
|
|
|
|
g_return_val_if_fail(!error || !*error, NULL);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-11-15 16:06:43 +01:00
|
|
|
ht = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, (GDestroyNotify) g_variant_unref);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-03-02 11:08:34 +01:00
|
|
|
while (TRUE) {
|
|
|
|
|
gs_free char *name = NULL, *value = NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-03-02 11:08:34 +01:00
|
|
|
if (!start)
|
|
|
|
|
start = ptr;
|
|
|
|
|
if (*ptr == '\\') {
|
|
|
|
|
ptr++;
|
|
|
|
|
if (!*ptr) {
|
2017-11-27 19:08:21 +01:00
|
|
|
g_set_error_literal(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_FAILED,
|
|
|
|
|
_("unterminated escape sequence"));
|
2017-03-02 11:08:34 +01:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
goto next;
|
|
|
|
|
}
|
|
|
|
|
if (*ptr == attr_separator || *ptr == '\0') {
|
|
|
|
|
if (ptr == start) {
|
|
|
|
|
/* multiple separators */
|
|
|
|
|
start = NULL;
|
|
|
|
|
goto next;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-03-02 11:08:34 +01:00
|
|
|
/* Find the key-value separator */
|
|
|
|
|
for (sep = start; sep != ptr; sep++) {
|
|
|
|
|
if (*sep == '\\') {
|
|
|
|
|
sep++;
|
|
|
|
|
if (!*sep) {
|
2017-11-27 19:08:21 +01:00
|
|
|
g_set_error_literal(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_FAILED,
|
|
|
|
|
_("unterminated escape sequence"));
|
2017-03-02 11:08:34 +01:00
|
|
|
return NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
}
|
2017-03-02 11:08:34 +01:00
|
|
|
}
|
|
|
|
|
if (*sep == key_value_separator)
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-03-02 11:08:34 +01:00
|
|
|
name = attribute_unescape(start, sep);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-03-02 11:08:34 +01:00
|
|
|
for (s = spec; *s; s++) {
|
libnm-core/utils: add some special properties for the attributes
"no_value" indicates that the the attribute is a single word, not a
key=value pair. If the type is BOOLEAN then the attribute is considered
true, if it's a STRING then the key is used instead of a value.
"consumes_rest" indicates that the particular key takes the unparseable
tail of the string for a value.
This allows parsing tc-style strings. Consider this filter:
,------ regular key/value pair
,-----'----.
root handle 1234: matchall action simple foo bar baz
| | `-----------.-----------'
| | `- "", STRING, consumes_rest
| `------------------- "kind", STRING, no_value
`-------------------------------------- "root', BOOLEAN, no_value
2017-12-04 11:40:32 +01:00
|
|
|
if (g_hash_table_contains(ht, (*s)->name))
|
|
|
|
|
continue;
|
2017-03-02 11:08:34 +01:00
|
|
|
if (nm_streq(name, (*s)->name))
|
|
|
|
|
break;
|
libnm-core/utils: add some special properties for the attributes
"no_value" indicates that the the attribute is a single word, not a
key=value pair. If the type is BOOLEAN then the attribute is considered
true, if it's a STRING then the key is used instead of a value.
"consumes_rest" indicates that the particular key takes the unparseable
tail of the string for a value.
This allows parsing tc-style strings. Consider this filter:
,------ regular key/value pair
,-----'----.
root handle 1234: matchall action simple foo bar baz
| | `-----------.-----------'
| | `- "", STRING, consumes_rest
| `------------------- "kind", STRING, no_value
`-------------------------------------- "root', BOOLEAN, no_value
2017-12-04 11:40:32 +01:00
|
|
|
if ((*s)->no_value && g_variant_type_equal((*s)->type, G_VARIANT_TYPE_STRING))
|
2020-09-28 16:03:33 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
libnm-core/utils: add some special properties for the attributes
"no_value" indicates that the the attribute is a single word, not a
key=value pair. If the type is BOOLEAN then the attribute is considered
true, if it's a STRING then the key is used instead of a value.
"consumes_rest" indicates that the particular key takes the unparseable
tail of the string for a value.
This allows parsing tc-style strings. Consider this filter:
,------ regular key/value pair
,-----'----.
root handle 1234: matchall action simple foo bar baz
| | `-----------.-----------'
| | `- "", STRING, consumes_rest
| `------------------- "kind", STRING, no_value
`-------------------------------------- "root', BOOLEAN, no_value
2017-12-04 11:40:32 +01:00
|
|
|
if (!*s) {
|
|
|
|
|
if (ignore_unknown)
|
2017-03-02 11:08:34 +01:00
|
|
|
goto next;
|
2020-09-28 16:03:33 +02:00
|
|
|
else {
|
libnm-core/utils: add some special properties for the attributes
"no_value" indicates that the the attribute is a single word, not a
key=value pair. If the type is BOOLEAN then the attribute is considered
true, if it's a STRING then the key is used instead of a value.
"consumes_rest" indicates that the particular key takes the unparseable
tail of the string for a value.
This allows parsing tc-style strings. Consider this filter:
,------ regular key/value pair
,-----'----.
root handle 1234: matchall action simple foo bar baz
| | `-----------.-----------'
| | `- "", STRING, consumes_rest
| `------------------- "kind", STRING, no_value
`-------------------------------------- "root', BOOLEAN, no_value
2017-12-04 11:40:32 +01:00
|
|
|
g_set_error(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_FAILED,
|
|
|
|
|
_("unknown attribute '%s'"),
|
2020-09-28 16:03:33 +02:00
|
|
|
name);
|
2017-03-02 11:08:34 +01:00
|
|
|
return NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
libnm-core/utils: add some special properties for the attributes
"no_value" indicates that the the attribute is a single word, not a
key=value pair. If the type is BOOLEAN then the attribute is considered
true, if it's a STRING then the key is used instead of a value.
"consumes_rest" indicates that the particular key takes the unparseable
tail of the string for a value.
This allows parsing tc-style strings. Consider this filter:
,------ regular key/value pair
,-----'----.
root handle 1234: matchall action simple foo bar baz
| | `-----------.-----------'
| | `- "", STRING, consumes_rest
| `------------------- "kind", STRING, no_value
`-------------------------------------- "root', BOOLEAN, no_value
2017-12-04 11:40:32 +01:00
|
|
|
if ((*s)->no_value) {
|
|
|
|
|
if ((*s)->consumes_rest) {
|
|
|
|
|
value = g_strdup(start);
|
2017-03-02 11:08:34 +01:00
|
|
|
ptr = strchr(start, '\0');
|
|
|
|
|
} else {
|
libnm-core/utils: add some special properties for the attributes
"no_value" indicates that the the attribute is a single word, not a
key=value pair. If the type is BOOLEAN then the attribute is considered
true, if it's a STRING then the key is used instead of a value.
"consumes_rest" indicates that the particular key takes the unparseable
tail of the string for a value.
This allows parsing tc-style strings. Consider this filter:
,------ regular key/value pair
,-----'----.
root handle 1234: matchall action simple foo bar baz
| | `-----------.-----------'
| | `- "", STRING, consumes_rest
| `------------------- "kind", STRING, no_value
`-------------------------------------- "root', BOOLEAN, no_value
2017-12-04 11:40:32 +01:00
|
|
|
value = g_steal_pointer(&name);
|
2020-09-28 16:03:33 +02:00
|
|
|
}
|
|
|
|
|
} else {
|
2017-03-02 11:08:34 +01:00
|
|
|
if (*sep != key_value_separator) {
|
|
|
|
|
g_set_error(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_FAILED,
|
|
|
|
|
_("missing key-value separator '%c' after '%s'"),
|
libnm-core/utils: add some special properties for the attributes
"no_value" indicates that the the attribute is a single word, not a
key=value pair. If the type is BOOLEAN then the attribute is considered
true, if it's a STRING then the key is used instead of a value.
"consumes_rest" indicates that the particular key takes the unparseable
tail of the string for a value.
This allows parsing tc-style strings. Consider this filter:
,------ regular key/value pair
,-----'----.
root handle 1234: matchall action simple foo bar baz
| | `-----------.-----------'
| | `- "", STRING, consumes_rest
| `------------------- "kind", STRING, no_value
`-------------------------------------- "root', BOOLEAN, no_value
2017-12-04 11:40:32 +01:00
|
|
|
key_value_separator,
|
|
|
|
|
name);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm-core/utils: add some special properties for the attributes
"no_value" indicates that the the attribute is a single word, not a
key=value pair. If the type is BOOLEAN then the attribute is considered
true, if it's a STRING then the key is used instead of a value.
"consumes_rest" indicates that the particular key takes the unparseable
tail of the string for a value.
This allows parsing tc-style strings. Consider this filter:
,------ regular key/value pair
,-----'----.
root handle 1234: matchall action simple foo bar baz
| | `-----------.-----------'
| | `- "", STRING, consumes_rest
| `------------------- "kind", STRING, no_value
`-------------------------------------- "root', BOOLEAN, no_value
2017-12-04 11:40:32 +01:00
|
|
|
/* The attribute and key/value separators are the same. Look for the next one. */
|
|
|
|
|
if (ptr == sep)
|
|
|
|
|
goto next;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm-core/utils: add some special properties for the attributes
"no_value" indicates that the the attribute is a single word, not a
key=value pair. If the type is BOOLEAN then the attribute is considered
true, if it's a STRING then the key is used instead of a value.
"consumes_rest" indicates that the particular key takes the unparseable
tail of the string for a value.
This allows parsing tc-style strings. Consider this filter:
,------ regular key/value pair
,-----'----.
root handle 1234: matchall action simple foo bar baz
| | `-----------.-----------'
| | `- "", STRING, consumes_rest
| `------------------- "kind", STRING, no_value
`-------------------------------------- "root', BOOLEAN, no_value
2017-12-04 11:40:32 +01:00
|
|
|
value = attribute_unescape(sep + 1, ptr);
|
2020-09-28 16:03:33 +02:00
|
|
|
}
|
|
|
|
|
|
libnm-core/utils: add some special properties for the attributes
"no_value" indicates that the the attribute is a single word, not a
key=value pair. If the type is BOOLEAN then the attribute is considered
true, if it's a STRING then the key is used instead of a value.
"consumes_rest" indicates that the particular key takes the unparseable
tail of the string for a value.
This allows parsing tc-style strings. Consider this filter:
,------ regular key/value pair
,-----'----.
root handle 1234: matchall action simple foo bar baz
| | `-----------.-----------'
| | `- "", STRING, consumes_rest
| `------------------- "kind", STRING, no_value
`-------------------------------------- "root', BOOLEAN, no_value
2017-12-04 11:40:32 +01:00
|
|
|
if (g_variant_type_equal((*s)->type, G_VARIANT_TYPE_UINT32)) {
|
2017-03-02 11:08:34 +01:00
|
|
|
gint64 num = _nm_utils_ascii_str_to_int64(value, 10, 0, G_MAXUINT32, -1);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-03-02 11:08:34 +01:00
|
|
|
if (num == -1) {
|
|
|
|
|
g_set_error(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_FAILED,
|
libnm-core/utils: add some special properties for the attributes
"no_value" indicates that the the attribute is a single word, not a
key=value pair. If the type is BOOLEAN then the attribute is considered
true, if it's a STRING then the key is used instead of a value.
"consumes_rest" indicates that the particular key takes the unparseable
tail of the string for a value.
This allows parsing tc-style strings. Consider this filter:
,------ regular key/value pair
,-----'----.
root handle 1234: matchall action simple foo bar baz
| | `-----------.-----------'
| | `- "", STRING, consumes_rest
| `------------------- "kind", STRING, no_value
`-------------------------------------- "root', BOOLEAN, no_value
2017-12-04 11:40:32 +01:00
|
|
|
_("invalid uint32 value '%s' for attribute '%s'"),
|
|
|
|
|
value,
|
|
|
|
|
(*s)->name);
|
2017-03-02 11:08:34 +01:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
variant = g_variant_new_uint32(num);
|
2020-05-25 16:07:11 +02:00
|
|
|
} else if (g_variant_type_equal((*s)->type, G_VARIANT_TYPE_INT32)) {
|
|
|
|
|
gint64 num =
|
|
|
|
|
_nm_utils_ascii_str_to_int64(value, 10, G_MININT32, G_MAXINT32, G_MAXINT64);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-25 16:07:11 +02:00
|
|
|
if (num == G_MAXINT64) {
|
|
|
|
|
g_set_error(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_FAILED,
|
|
|
|
|
_("invalid int32 value '%s' for attribute '%s'"),
|
|
|
|
|
value,
|
|
|
|
|
(*s)->name);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
variant = g_variant_new_int32(num);
|
|
|
|
|
} else if (g_variant_type_equal((*s)->type, G_VARIANT_TYPE_UINT64)) {
|
|
|
|
|
guint64 num = _nm_utils_ascii_str_to_uint64(value, 10, 0, G_MAXUINT64, G_MAXUINT64);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-25 16:07:11 +02:00
|
|
|
if (num == G_MAXUINT64 && errno != 0) {
|
|
|
|
|
g_set_error(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_FAILED,
|
|
|
|
|
_("invalid uint64 value '%s' for attribute '%s'"),
|
|
|
|
|
value,
|
|
|
|
|
(*s)->name);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
variant = g_variant_new_uint64(num);
|
2017-03-02 11:08:34 +01:00
|
|
|
} else if (g_variant_type_equal((*s)->type, G_VARIANT_TYPE_BYTE)) {
|
|
|
|
|
gint64 num = _nm_utils_ascii_str_to_int64(value, 10, 0, G_MAXUINT8, -1);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-03-02 11:08:34 +01:00
|
|
|
if (num == -1) {
|
|
|
|
|
g_set_error(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_FAILED,
|
libnm-core/utils: add some special properties for the attributes
"no_value" indicates that the the attribute is a single word, not a
key=value pair. If the type is BOOLEAN then the attribute is considered
true, if it's a STRING then the key is used instead of a value.
"consumes_rest" indicates that the particular key takes the unparseable
tail of the string for a value.
This allows parsing tc-style strings. Consider this filter:
,------ regular key/value pair
,-----'----.
root handle 1234: matchall action simple foo bar baz
| | `-----------.-----------'
| | `- "", STRING, consumes_rest
| `------------------- "kind", STRING, no_value
`-------------------------------------- "root', BOOLEAN, no_value
2017-12-04 11:40:32 +01:00
|
|
|
_("invalid uint8 value '%s' for attribute '%s'"),
|
|
|
|
|
value,
|
|
|
|
|
(*s)->name);
|
2017-03-02 11:08:34 +01:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
variant = g_variant_new_byte((guchar) num);
|
|
|
|
|
} else if (g_variant_type_equal((*s)->type, G_VARIANT_TYPE_BOOLEAN)) {
|
2017-11-24 12:27:53 +01:00
|
|
|
int b;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm-core/utils: add some special properties for the attributes
"no_value" indicates that the the attribute is a single word, not a
key=value pair. If the type is BOOLEAN then the attribute is considered
true, if it's a STRING then the key is used instead of a value.
"consumes_rest" indicates that the particular key takes the unparseable
tail of the string for a value.
This allows parsing tc-style strings. Consider this filter:
,------ regular key/value pair
,-----'----.
root handle 1234: matchall action simple foo bar baz
| | `-----------.-----------'
| | `- "", STRING, consumes_rest
| `------------------- "kind", STRING, no_value
`-------------------------------------- "root', BOOLEAN, no_value
2017-12-04 11:40:32 +01:00
|
|
|
b = (*s)->no_value ? TRUE : _nm_utils_ascii_str_to_bool(value, -1);
|
2017-11-24 12:27:53 +01:00
|
|
|
if (b == -1) {
|
2017-03-02 11:08:34 +01:00
|
|
|
g_set_error(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_FAILED,
|
libnm-core/utils: add some special properties for the attributes
"no_value" indicates that the the attribute is a single word, not a
key=value pair. If the type is BOOLEAN then the attribute is considered
true, if it's a STRING then the key is used instead of a value.
"consumes_rest" indicates that the particular key takes the unparseable
tail of the string for a value.
This allows parsing tc-style strings. Consider this filter:
,------ regular key/value pair
,-----'----.
root handle 1234: matchall action simple foo bar baz
| | `-----------.-----------'
| | `- "", STRING, consumes_rest
| `------------------- "kind", STRING, no_value
`-------------------------------------- "root', BOOLEAN, no_value
2017-12-04 11:40:32 +01:00
|
|
|
_("invalid boolean value '%s' for attribute '%s'"),
|
|
|
|
|
value,
|
|
|
|
|
(*s)->name);
|
2017-03-02 11:08:34 +01:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
variant = g_variant_new_boolean(b);
|
|
|
|
|
} else if (g_variant_type_equal((*s)->type, G_VARIANT_TYPE_STRING)) {
|
|
|
|
|
variant = g_variant_new_take_string(g_steal_pointer(&value));
|
2017-12-04 14:38:21 +01:00
|
|
|
} else if (g_variant_type_equal((*s)->type, G_VARIANT_TYPE_BYTESTRING)) {
|
|
|
|
|
variant = g_variant_new_bytestring(value);
|
2017-03-02 11:08:34 +01:00
|
|
|
} else {
|
|
|
|
|
g_set_error(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_FAILED,
|
libnm-core/utils: add some special properties for the attributes
"no_value" indicates that the the attribute is a single word, not a
key=value pair. If the type is BOOLEAN then the attribute is considered
true, if it's a STRING then the key is used instead of a value.
"consumes_rest" indicates that the particular key takes the unparseable
tail of the string for a value.
This allows parsing tc-style strings. Consider this filter:
,------ regular key/value pair
,-----'----.
root handle 1234: matchall action simple foo bar baz
| | `-----------.-----------'
| | `- "", STRING, consumes_rest
| `------------------- "kind", STRING, no_value
`-------------------------------------- "root', BOOLEAN, no_value
2017-12-04 11:40:32 +01:00
|
|
|
_("unsupported attribute '%s' of type '%s'"),
|
|
|
|
|
(*s)->name,
|
2017-03-02 11:08:34 +01:00
|
|
|
(char *) (*s)->type);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm-core/utils: add some special properties for the attributes
"no_value" indicates that the the attribute is a single word, not a
key=value pair. If the type is BOOLEAN then the attribute is considered
true, if it's a STRING then the key is used instead of a value.
"consumes_rest" indicates that the particular key takes the unparseable
tail of the string for a value.
This allows parsing tc-style strings. Consider this filter:
,------ regular key/value pair
,-----'----.
root handle 1234: matchall action simple foo bar baz
| | `-----------.-----------'
| | `- "", STRING, consumes_rest
| `------------------- "kind", STRING, no_value
`-------------------------------------- "root', BOOLEAN, no_value
2017-12-04 11:40:32 +01:00
|
|
|
g_hash_table_insert(ht, g_strdup((*s)->name), variant);
|
2017-03-02 11:08:34 +01:00
|
|
|
start = NULL;
|
|
|
|
|
}
|
|
|
|
|
next:
|
|
|
|
|
if (*ptr == '\0')
|
|
|
|
|
break;
|
|
|
|
|
ptr++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return g_steal_pointer(&ht);
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-07 21:13:28 +01:00
|
|
|
/**
|
2018-06-18 18:46:52 +02:00
|
|
|
* nm_utils_format_variant_attributes:
|
|
|
|
|
* @attributes: (element-type utf8 GVariant): a #GHashTable mapping attribute names to #GVariant values
|
|
|
|
|
* @attr_separator: the attribute separator character
|
|
|
|
|
* @key_value_separator: character separating key and values
|
|
|
|
|
*
|
|
|
|
|
* Format attributes to a string.
|
|
|
|
|
*
|
|
|
|
|
* Returns: (transfer full): the string representing attributes, or %NULL
|
|
|
|
|
* in case there are no attributes
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.8
|
|
|
|
|
*/
|
|
|
|
|
char *
|
|
|
|
|
nm_utils_format_variant_attributes(GHashTable *attributes,
|
|
|
|
|
char attr_separator,
|
|
|
|
|
char key_value_separator)
|
|
|
|
|
{
|
2020-05-14 16:43:32 +02:00
|
|
|
return _nm_utils_format_variant_attributes(attributes,
|
2020-07-07 18:03:48 +02:00
|
|
|
NULL,
|
2020-05-14 16:43:32 +02:00
|
|
|
attr_separator,
|
|
|
|
|
key_value_separator);
|
2017-03-02 11:08:34 +01:00
|
|
|
}
|
|
|
|
|
|
2016-12-20 16:36:15 +01:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2022-11-07 21:13:28 +01:00
|
|
|
/**
|
|
|
|
|
* nm_utils_get_timestamp_msec:
|
2018-06-15 14:15:27 +02:00
|
|
|
*
|
|
|
|
|
* Gets current time in milliseconds of CLOCK_BOOTTIME.
|
|
|
|
|
*
|
|
|
|
|
* Returns: time in milliseconds
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
*/
|
|
|
|
|
gint64
|
|
|
|
|
nm_utils_get_timestamp_msec(void)
|
|
|
|
|
{
|
2019-07-23 11:52:19 +02:00
|
|
|
gint64 ts;
|
2018-06-15 14:15:27 +02:00
|
|
|
|
2020-01-28 16:21:23 +01:00
|
|
|
ts = nm_utils_clock_gettime_msec(CLOCK_BOOTTIME);
|
2019-07-23 11:52:19 +02:00
|
|
|
if (ts >= 0)
|
|
|
|
|
return ts;
|
2018-06-15 14:15:27 +02:00
|
|
|
|
2019-07-23 11:52:19 +02:00
|
|
|
if (ts == -EINVAL) {
|
2018-06-15 14:15:27 +02:00
|
|
|
/* The fallback to CLOCK_MONOTONIC is taken only if we're running on a
|
|
|
|
|
* criminally old kernel, prior to 2.6.39 (released on 18 May, 2011).
|
|
|
|
|
* That happens during buildcheck on old builders, we don't expect to
|
|
|
|
|
* be actually runs on kernels that old. */
|
2020-01-28 16:21:23 +01:00
|
|
|
ts = nm_utils_clock_gettime_msec(CLOCK_MONOTONIC);
|
2019-07-23 11:52:19 +02:00
|
|
|
if (ts >= 0)
|
|
|
|
|
return ts;
|
2018-06-15 14:15:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_return_val_if_reached(-1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2016-12-20 16:36:15 +01:00
|
|
|
/**
|
|
|
|
|
* nm_utils_version:
|
|
|
|
|
*
|
|
|
|
|
* Returns: the version ID of the libnm version. That is, the %NM_VERSION
|
|
|
|
|
* at runtime.
|
|
|
|
|
*
|
2022-11-07 21:13:28 +01:00
|
|
|
* Since: 1.6
|
2016-12-20 16:36:15 +01:00
|
|
|
*/
|
|
|
|
|
guint
|
|
|
|
|
nm_utils_version(void)
|
|
|
|
|
{
|
|
|
|
|
return NM_VERSION;
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-27 16:48:30 +01:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
bluetooth: refactor BlueZ handling and let NMBluezManager cache ObjectManager data
This is a complete refactoring of the bluetooth code.
Now that BlueZ 4 support was dropped, the separation of NMBluezManager
and NMBluez5Manager makes no sense. They should be merged.
At that point, notice that BlueZ 5's D-Bus API is fully centered around
D-Bus's ObjectManager interface. Using that interface, we basically only
call GetManagedObjects() once and register to InterfacesAdded,
InterfacesRemoved and PropertiesChanged signals. There is no need to
fetch individual properties ever.
Note how NMBluezDevice used to query the D-Bus properties itself by
creating a GDBusProxy. This is redundant, because when using the ObjectManager
interfaces, we have all information already.
Instead, let NMBluezManager basically become the client-side cache of
all of BlueZ's ObjectManager interface. NMBluezDevice was mostly concerned
about caching the D-Bus interface's state, tracking suitable profiles
(pan_connection), and moderate between bluez and NMDeviceBt.
These tasks don't get simpler by moving them to a seprate file. Let them
also be handled by NMBluezManager.
I mean, just look how it was previously: NMBluez5Manager registers to
ObjectManager interface and sees a device appearing. It creates a
NMBluezDevice object and registers to its "initialized" and
"notify:usable" signal. In the meantime, NMBluezDevice fetches the
relevant information from D-Bus (although it was already present in the
data provided by the ObjectManager) and eventually emits these usable
and initialized signals.
Then, NMBlue5Manager emits a "bdaddr-added" signal, for which NMBluezManager
creates the NMDeviceBt instance. NMBluezManager, NMBluez5Manager and
NMBluezDevice are strongly cooperating to the point that it is simpler
to merge them.
This is not mere refactoring. This patch aims to make everything
asynchronously and always cancellable. Also, it aims to fix races
and inconsistencies of the state.
- Registering to a NAP server now waits for the response and delays
activation of the NMDeviceBridge accordingly.
- For NAP connections we now watch the bnep0 interface in platform, and tear
down the device when it goes away. Bluez doesn't send us a notification
on D-Bus in that case.
- Rework establishing a DUN connection. It no longer uses blocking
connect() and does not block until rfcomm device appears. It's
all async now. It also watches the rfcomm file descriptor for
POLLERR/POLLHUP to notice disconnect.
- drop nm_device_factory_emit_component_added() and instead let
NMDeviceBt directly register to the WWan factory's "added" signal.
2019-08-11 10:43:53 +02:00
|
|
|
NM_UTILS_FLAGS2STR_DEFINE(nm_bluetooth_capability_to_string,
|
|
|
|
|
NMBluetoothCapabilities,
|
|
|
|
|
NM_UTILS_FLAGS2STR(NM_BT_CAPABILITY_NONE, "NONE"),
|
|
|
|
|
NM_UTILS_FLAGS2STR(NM_BT_CAPABILITY_DUN, "DUN"),
|
2020-10-19 16:37:41 +02:00
|
|
|
NM_UTILS_FLAGS2STR(NM_BT_CAPABILITY_NAP, "NAP"), );
|
bluetooth: refactor BlueZ handling and let NMBluezManager cache ObjectManager data
This is a complete refactoring of the bluetooth code.
Now that BlueZ 4 support was dropped, the separation of NMBluezManager
and NMBluez5Manager makes no sense. They should be merged.
At that point, notice that BlueZ 5's D-Bus API is fully centered around
D-Bus's ObjectManager interface. Using that interface, we basically only
call GetManagedObjects() once and register to InterfacesAdded,
InterfacesRemoved and PropertiesChanged signals. There is no need to
fetch individual properties ever.
Note how NMBluezDevice used to query the D-Bus properties itself by
creating a GDBusProxy. This is redundant, because when using the ObjectManager
interfaces, we have all information already.
Instead, let NMBluezManager basically become the client-side cache of
all of BlueZ's ObjectManager interface. NMBluezDevice was mostly concerned
about caching the D-Bus interface's state, tracking suitable profiles
(pan_connection), and moderate between bluez and NMDeviceBt.
These tasks don't get simpler by moving them to a seprate file. Let them
also be handled by NMBluezManager.
I mean, just look how it was previously: NMBluez5Manager registers to
ObjectManager interface and sees a device appearing. It creates a
NMBluezDevice object and registers to its "initialized" and
"notify:usable" signal. In the meantime, NMBluezDevice fetches the
relevant information from D-Bus (although it was already present in the
data provided by the ObjectManager) and eventually emits these usable
and initialized signals.
Then, NMBlue5Manager emits a "bdaddr-added" signal, for which NMBluezManager
creates the NMDeviceBt instance. NMBluezManager, NMBluez5Manager and
NMBluezDevice are strongly cooperating to the point that it is simpler
to merge them.
This is not mere refactoring. This patch aims to make everything
asynchronously and always cancellable. Also, it aims to fix races
and inconsistencies of the state.
- Registering to a NAP server now waits for the response and delays
activation of the NMDeviceBridge accordingly.
- For NAP connections we now watch the bnep0 interface in platform, and tear
down the device when it goes away. Bluez doesn't send us a notification
on D-Bus in that case.
- Rework establishing a DUN connection. It no longer uses blocking
connect() and does not block until rfcomm device appears. It's
all async now. It also watches the rfcomm file descriptor for
POLLERR/POLLHUP to notice disconnect.
- drop nm_device_factory_emit_component_added() and instead let
NMDeviceBt directly register to the WWan factory's "added" signal.
2019-08-11 10:43:53 +02:00
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2018-12-27 16:48:30 +01:00
|
|
|
/**
|
2019-03-02 17:10:25 +01:00
|
|
|
* nm_utils_base64secret_decode:
|
2018-12-27 16:48:30 +01:00
|
|
|
* @base64_key: the (possibly invalid) base64 encode key.
|
|
|
|
|
* @required_key_len: the expected (binary) length of the key after
|
|
|
|
|
* decoding. If the length does not match, the validation fails.
|
2023-03-02 12:18:30 +01:00
|
|
|
* @out_key: (out) (optional): an optional output buffer for the binary
|
2018-12-27 16:48:30 +01:00
|
|
|
* key. If given, it will be filled with exactly @required_key_len
|
|
|
|
|
* bytes.
|
|
|
|
|
*
|
|
|
|
|
* Returns: %TRUE if the input key is a valid base64 encoded key
|
|
|
|
|
* with @required_key_len bytes.
|
2019-03-02 17:10:25 +01:00
|
|
|
*
|
|
|
|
|
* Since: 1.16
|
2018-12-27 16:48:30 +01:00
|
|
|
*/
|
|
|
|
|
gboolean
|
2019-03-02 17:10:25 +01:00
|
|
|
nm_utils_base64secret_decode(const char *base64_key, gsize required_key_len, guint8 *out_key)
|
2018-12-27 16:48:30 +01:00
|
|
|
{
|
2020-05-12 21:48:20 +02:00
|
|
|
nm_auto_free guint8 *bin_arr = NULL;
|
2018-12-27 16:48:30 +01:00
|
|
|
gsize base64_key_len;
|
|
|
|
|
gsize bin_len;
|
|
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
if (!base64_key)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
base64_key_len = strlen(base64_key);
|
|
|
|
|
|
2022-04-11 17:52:46 +02:00
|
|
|
r = nm_unbase64mem_full(base64_key, base64_key_len, TRUE, &bin_arr, &bin_len);
|
2018-12-27 16:48:30 +01:00
|
|
|
if (r < 0)
|
|
|
|
|
return FALSE;
|
|
|
|
|
if (bin_len != required_key_len) {
|
|
|
|
|
nm_explicit_bzero(bin_arr, bin_len);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (out_key)
|
|
|
|
|
memcpy(out_key, bin_arr, required_key_len);
|
|
|
|
|
|
|
|
|
|
nm_explicit_bzero(bin_arr, bin_len);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gboolean
|
2019-03-02 17:10:25 +01:00
|
|
|
nm_utils_base64secret_normalize(const char *base64_key,
|
|
|
|
|
gsize required_key_len,
|
2021-11-09 13:28:54 +01:00
|
|
|
char **out_base64_key_norm)
|
2018-12-27 16:48:30 +01:00
|
|
|
{
|
|
|
|
|
gs_free guint8 *buf_free = NULL;
|
|
|
|
|
guint8 buf_static[200];
|
2021-11-09 13:28:54 +01:00
|
|
|
guint8 *buf;
|
2018-12-27 16:48:30 +01:00
|
|
|
|
|
|
|
|
if (required_key_len > sizeof(buf_static)) {
|
|
|
|
|
buf_free = g_new(guint8, required_key_len);
|
|
|
|
|
buf = buf_free;
|
|
|
|
|
} else
|
|
|
|
|
buf = buf_static;
|
|
|
|
|
|
2019-03-02 17:10:25 +01:00
|
|
|
if (!nm_utils_base64secret_decode(base64_key, required_key_len, buf)) {
|
2018-12-27 16:48:30 +01:00
|
|
|
NM_SET_OUT(out_base64_key_norm, NULL);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NM_SET_OUT(out_base64_key_norm, g_base64_encode(buf, required_key_len));
|
|
|
|
|
nm_explicit_bzero(buf, required_key_len);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
2019-03-16 17:21:35 +01:00
|
|
|
|
2021-06-29 14:37:16 +02:00
|
|
|
GVariant *
|
libnm: use macros function arguments for NMSettInfoPropertType
These functions tend to have many arguments. They are also quite som
boilerplate to implement the hundereds of properties we have, while
we want that properties have common behaviors and similarities.
Instead of repeatedly spelling out the function arguments, use a macro.
Advantages:
- the usage of a _NM_SETT_INFO_PROP_*_FCN_ARGS macro signals that this
is an implementation of a property. You can now grep for these macros
to find all implementation. That was previously rather imprecise, you
could only `git grep '\.to_dbus_fcn'` to find the uses, but not the
implementations.
As the goal is to keep properties "similar", there is a desire to
reduce the number of similar implementations and to find them.
- changing the arguments now no longer will require you to go through
all implementations. At least not, if you merely add an argument that
has a reasonable default behavior and does not require explicit
handling by most implementation.
- it's convenient to be able to patch the argument list to let the
compiler help to reason about something. For example, the
"connection_dict" argument to from_dbus_fcn() is usually unused.
If you'd like to find who uses it, rename the parameter, and
review the (few) compiler errors.
- it does save 573 LOC of boilerplate with no actual logic or useful
information. I argue, that this simplifies the code and review, by
increasing the relative amount of actually meaningful code.
Disadvantages:
- the user no longer directly sees the argument list. They would need
cscope/ctags or an IDE to jump to the macro definition and conveniently
see all arguments.
Also use _nm_nil, so that clang-format interprets this as a function
parameter list. Otherwise, it formats the function differently.
2021-07-26 23:45:31 +02:00
|
|
|
_nm_utils_bridge_vlans_to_dbus(_NM_SETT_INFO_PROP_TO_DBUS_FCN_ARGS _nm_nil)
|
2019-03-16 17:21:35 +01:00
|
|
|
{
|
|
|
|
|
gs_unref_ptrarray GPtrArray *vlans = NULL;
|
|
|
|
|
GVariantBuilder builder;
|
|
|
|
|
guint i;
|
2021-11-09 13:28:54 +01:00
|
|
|
const char *property_name = property_info->name;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-04-24 17:41:32 +02:00
|
|
|
nm_assert(property_name);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-04-24 17:41:32 +02:00
|
|
|
g_object_get(setting, property_name, &vlans, NULL);
|
2019-03-16 17:21:35 +01:00
|
|
|
g_variant_builder_init(&builder, G_VARIANT_TYPE("aa{sv}"));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-16 17:21:35 +01:00
|
|
|
if (vlans) {
|
|
|
|
|
for (i = 0; i < vlans->len; i++) {
|
2021-11-09 13:28:54 +01:00
|
|
|
NMBridgeVlan *vlan = vlans->pdata[i];
|
2019-03-16 17:21:35 +01:00
|
|
|
GVariantBuilder vlan_builder;
|
2019-04-15 15:14:33 +02:00
|
|
|
guint16 vid_start, vid_end;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-04-15 15:14:33 +02:00
|
|
|
nm_bridge_vlan_get_vid_range(vlan, &vid_start, &vid_end);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-16 17:21:35 +01:00
|
|
|
g_variant_builder_init(&vlan_builder, G_VARIANT_TYPE_VARDICT);
|
2019-04-15 15:14:33 +02:00
|
|
|
g_variant_builder_add(&vlan_builder,
|
|
|
|
|
"{sv}",
|
|
|
|
|
"vid-start",
|
|
|
|
|
g_variant_new_uint16(vid_start));
|
|
|
|
|
g_variant_builder_add(&vlan_builder, "{sv}", "vid-end", g_variant_new_uint16(vid_end));
|
2019-03-16 17:21:35 +01:00
|
|
|
g_variant_builder_add(&vlan_builder,
|
|
|
|
|
"{sv}",
|
|
|
|
|
"pvid",
|
|
|
|
|
g_variant_new_boolean(nm_bridge_vlan_is_pvid(vlan)));
|
|
|
|
|
g_variant_builder_add(&vlan_builder,
|
|
|
|
|
"{sv}",
|
|
|
|
|
"untagged",
|
|
|
|
|
g_variant_new_boolean(nm_bridge_vlan_is_untagged(vlan)));
|
|
|
|
|
g_variant_builder_add(&builder, "a{sv}", &vlan_builder);
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-16 17:21:35 +01:00
|
|
|
return g_variant_builder_end(&builder);
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-29 14:37:16 +02:00
|
|
|
gboolean
|
libnm: use macros function arguments for NMSettInfoPropertType
These functions tend to have many arguments. They are also quite som
boilerplate to implement the hundereds of properties we have, while
we want that properties have common behaviors and similarities.
Instead of repeatedly spelling out the function arguments, use a macro.
Advantages:
- the usage of a _NM_SETT_INFO_PROP_*_FCN_ARGS macro signals that this
is an implementation of a property. You can now grep for these macros
to find all implementation. That was previously rather imprecise, you
could only `git grep '\.to_dbus_fcn'` to find the uses, but not the
implementations.
As the goal is to keep properties "similar", there is a desire to
reduce the number of similar implementations and to find them.
- changing the arguments now no longer will require you to go through
all implementations. At least not, if you merely add an argument that
has a reasonable default behavior and does not require explicit
handling by most implementation.
- it's convenient to be able to patch the argument list to let the
compiler help to reason about something. For example, the
"connection_dict" argument to from_dbus_fcn() is usually unused.
If you'd like to find who uses it, rename the parameter, and
review the (few) compiler errors.
- it does save 573 LOC of boilerplate with no actual logic or useful
information. I argue, that this simplifies the code and review, by
increasing the relative amount of actually meaningful code.
Disadvantages:
- the user no longer directly sees the argument list. They would need
cscope/ctags or an IDE to jump to the macro definition and conveniently
see all arguments.
Also use _nm_nil, so that clang-format interprets this as a function
parameter list. Otherwise, it formats the function differently.
2021-07-26 23:45:31 +02:00
|
|
|
_nm_utils_bridge_vlans_from_dbus(_NM_SETT_INFO_PROP_FROM_DBUS_FCN_ARGS _nm_nil)
|
2019-03-16 17:21:35 +01:00
|
|
|
{
|
|
|
|
|
gs_unref_ptrarray GPtrArray *vlans = NULL;
|
|
|
|
|
GVariantIter vlan_iter;
|
2021-11-09 13:28:54 +01:00
|
|
|
GVariant *vlan_var;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-16 17:21:35 +01:00
|
|
|
g_return_val_if_fail(g_variant_is_of_type(value, G_VARIANT_TYPE("aa{sv}")), FALSE);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-16 17:21:35 +01:00
|
|
|
vlans = g_ptr_array_new_with_free_func((GDestroyNotify) nm_bridge_vlan_unref);
|
|
|
|
|
g_variant_iter_init(&vlan_iter, value);
|
|
|
|
|
while (g_variant_iter_next(&vlan_iter, "@a{sv}", &vlan_var)) {
|
2019-03-29 12:16:37 +01:00
|
|
|
_nm_unused gs_unref_variant GVariant *var_unref = vlan_var;
|
2021-11-09 13:28:54 +01:00
|
|
|
NMBridgeVlan *vlan;
|
2019-04-15 15:14:33 +02:00
|
|
|
guint16 vid_start, vid_end;
|
2019-03-16 17:21:35 +01:00
|
|
|
gboolean pvid = FALSE, untagged = FALSE;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-04-15 15:14:33 +02:00
|
|
|
if (!g_variant_lookup(vlan_var, "vid-start", "q", &vid_start))
|
|
|
|
|
continue;
|
|
|
|
|
if (vid_start < NM_BRIDGE_VLAN_VID_MIN || vid_start > NM_BRIDGE_VLAN_VID_MAX)
|
|
|
|
|
continue;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-04-15 15:14:33 +02:00
|
|
|
if (!g_variant_lookup(vlan_var, "vid-end", "q", &vid_end))
|
|
|
|
|
continue;
|
|
|
|
|
if (vid_end < NM_BRIDGE_VLAN_VID_MIN || vid_end > NM_BRIDGE_VLAN_VID_MAX)
|
2019-03-16 17:21:35 +01:00
|
|
|
continue;
|
2019-04-15 15:14:33 +02:00
|
|
|
if (vid_start > vid_end)
|
2019-03-16 17:21:35 +01:00
|
|
|
continue;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-08-02 11:29:42 +02:00
|
|
|
if (!g_variant_lookup(vlan_var, "pvid", "b", &pvid))
|
|
|
|
|
pvid = FALSE;
|
2019-04-15 15:14:33 +02:00
|
|
|
if (pvid && vid_start != vid_end)
|
|
|
|
|
continue;
|
2019-08-02 11:29:42 +02:00
|
|
|
if (!g_variant_lookup(vlan_var, "untagged", "b", &untagged))
|
|
|
|
|
untagged = FALSE;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-04-15 15:14:33 +02:00
|
|
|
vlan = nm_bridge_vlan_new(vid_start, vid_end);
|
2019-03-16 17:21:35 +01:00
|
|
|
nm_bridge_vlan_set_untagged(vlan, untagged);
|
|
|
|
|
nm_bridge_vlan_set_pvid(vlan, pvid);
|
|
|
|
|
g_ptr_array_add(vlans, vlan);
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2021-06-29 23:51:46 +02:00
|
|
|
g_object_set(setting, property_info->name, vlans, NULL);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-16 17:21:35 +01:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-29 14:37:16 +02:00
|
|
|
NMTernary
|
|
|
|
|
_nm_utils_bridge_compare_vlans(GPtrArray *vlans_a, GPtrArray *vlans_b)
|
|
|
|
|
{
|
|
|
|
|
guint l = nm_g_ptr_array_len(vlans_a);
|
|
|
|
|
guint i;
|
|
|
|
|
|
|
|
|
|
if (l != nm_g_ptr_array_len(vlans_b))
|
|
|
|
|
return FALSE;
|
|
|
|
|
for (i = 0; i < l; i++) {
|
|
|
|
|
if (nm_bridge_vlan_cmp(vlans_a->pdata[i], vlans_b->pdata[i]))
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
2019-09-22 10:57:57 +02:00
|
|
|
|
2019-03-16 17:21:35 +01:00
|
|
|
gboolean
|
2021-11-09 13:28:54 +01:00
|
|
|
_nm_utils_bridge_vlan_verify_list(GPtrArray *vlans,
|
2019-03-16 17:21:35 +01:00
|
|
|
gboolean check_normalizable,
|
2021-11-09 13:28:54 +01:00
|
|
|
GError **error,
|
2019-03-16 17:21:35 +01:00
|
|
|
const char *setting,
|
|
|
|
|
const char *property)
|
|
|
|
|
{
|
2021-11-09 13:28:54 +01:00
|
|
|
guint i;
|
2019-03-16 17:21:35 +01:00
|
|
|
gs_unref_hashtable GHashTable *h = NULL;
|
|
|
|
|
gboolean pvid_found = FALSE;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-04-17 15:40:32 +02:00
|
|
|
if (!vlans || vlans->len <= 1)
|
2019-03-16 17:21:35 +01:00
|
|
|
return TRUE;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-16 17:21:35 +01:00
|
|
|
if (check_normalizable) {
|
2019-04-17 15:40:32 +02:00
|
|
|
guint16 vid_prev_end, vid_start, vid_end;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-04-17 15:40:32 +02:00
|
|
|
nm_assert(_nm_utils_bridge_vlan_verify_list(vlans, FALSE, NULL, setting, property));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-04-17 15:40:32 +02:00
|
|
|
nm_bridge_vlan_get_vid_range(vlans->pdata[0], NULL, &vid_prev_end);
|
2019-03-16 17:21:35 +01:00
|
|
|
for (i = 1; i < vlans->len; i++) {
|
2019-04-17 15:40:32 +02:00
|
|
|
const NMBridgeVlan *vlan = vlans->pdata[i];
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-04-17 15:40:32 +02:00
|
|
|
nm_bridge_vlan_get_vid_range(vlan, &vid_start, &vid_end);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-04-17 15:40:32 +02:00
|
|
|
if (vid_prev_end > vid_start) {
|
2019-03-16 17:21:35 +01:00
|
|
|
g_set_error(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("Bridge VLANs %d and %d are not sorted by ascending vid"),
|
2019-04-17 15:40:32 +02:00
|
|
|
vid_prev_end,
|
|
|
|
|
vid_start);
|
2019-03-16 17:21:35 +01:00
|
|
|
g_prefix_error(error, "%s.%s: ", setting, property);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-04-17 15:40:32 +02:00
|
|
|
vid_prev_end = vid_end;
|
2019-03-16 17:21:35 +01:00
|
|
|
}
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-16 17:21:35 +01:00
|
|
|
h = g_hash_table_new(nm_direct_hash, NULL);
|
|
|
|
|
for (i = 0; i < vlans->len; i++) {
|
|
|
|
|
NMBridgeVlan *vlan = vlans->pdata[i];
|
2019-04-15 15:14:33 +02:00
|
|
|
guint16 v, vid_start, vid_end;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-04-15 15:14:33 +02:00
|
|
|
nm_bridge_vlan_get_vid_range(vlan, &vid_start, &vid_end);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-04-15 15:14:33 +02:00
|
|
|
for (v = vid_start; v <= vid_end; v++) {
|
2023-12-11 11:30:02 +01:00
|
|
|
if (!g_hash_table_add(h, GUINT_TO_POINTER(v))) {
|
2019-04-15 15:14:33 +02:00
|
|
|
g_set_error(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("duplicate bridge VLAN vid %u"),
|
|
|
|
|
v);
|
2019-03-16 17:21:35 +01:00
|
|
|
g_prefix_error(error, "%s.%s: ", setting, property);
|
|
|
|
|
return FALSE;
|
2019-04-17 15:40:32 +02:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
}
|
|
|
|
|
|
2019-04-17 15:40:32 +02:00
|
|
|
if (nm_bridge_vlan_is_pvid(vlan)) {
|
|
|
|
|
if (vid_start != vid_end || pvid_found) {
|
|
|
|
|
g_set_error_literal(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("only one VLAN can be the PVID"));
|
|
|
|
|
g_prefix_error(error, "%s.%s: ", setting, property);
|
|
|
|
|
return FALSE;
|
2019-04-15 15:14:33 +02:00
|
|
|
}
|
2019-04-17 15:40:32 +02:00
|
|
|
pvid_found = TRUE;
|
2019-04-15 15:14:33 +02:00
|
|
|
}
|
2019-03-16 17:21:35 +01:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-03-16 17:21:35 +01:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
2019-05-26 23:39:25 +02:00
|
|
|
|
2022-11-18 17:43:57 +01:00
|
|
|
GVariant *
|
|
|
|
|
_nm_utils_ranges_to_dbus(_NM_SETT_INFO_PROP_TO_DBUS_FCN_ARGS _nm_nil)
|
|
|
|
|
{
|
|
|
|
|
gs_unref_ptrarray GPtrArray *ranges = NULL;
|
|
|
|
|
GVariantBuilder builder;
|
|
|
|
|
const char *property_name = property_info->name;
|
|
|
|
|
guint i;
|
|
|
|
|
|
|
|
|
|
nm_assert(property_name);
|
|
|
|
|
|
|
|
|
|
g_object_get(setting, property_name, &ranges, NULL);
|
|
|
|
|
g_variant_builder_init(&builder, G_VARIANT_TYPE("aa{sv}"));
|
|
|
|
|
|
|
|
|
|
if (ranges) {
|
|
|
|
|
for (i = 0; i < ranges->len; i++) {
|
|
|
|
|
NMRange *range = ranges->pdata[i];
|
|
|
|
|
GVariantBuilder range_builder;
|
|
|
|
|
|
|
|
|
|
g_variant_builder_init(&range_builder, G_VARIANT_TYPE_VARDICT);
|
|
|
|
|
g_variant_builder_add(&range_builder,
|
|
|
|
|
"{sv}",
|
|
|
|
|
"start",
|
|
|
|
|
g_variant_new_uint64(range->start));
|
|
|
|
|
g_variant_builder_add(&range_builder, "{sv}", "end", g_variant_new_uint64(range->end));
|
|
|
|
|
|
|
|
|
|
g_variant_builder_add(&builder, "a{sv}", &range_builder);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return g_variant_builder_end(&builder);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
|
_nm_utils_ranges_from_dbus(_NM_SETT_INFO_PROP_FROM_DBUS_FCN_ARGS _nm_nil)
|
|
|
|
|
{
|
|
|
|
|
gs_unref_ptrarray GPtrArray *ranges = NULL;
|
|
|
|
|
GVariantIter iter;
|
|
|
|
|
GVariant *range_var;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail(g_variant_is_of_type(value, G_VARIANT_TYPE("aa{sv}")), FALSE);
|
|
|
|
|
|
|
|
|
|
ranges = g_ptr_array_new_with_free_func((GDestroyNotify) nm_range_unref);
|
|
|
|
|
g_variant_iter_init(&iter, value);
|
|
|
|
|
while (g_variant_iter_next(&iter, "@a{sv}", &range_var)) {
|
|
|
|
|
_nm_unused gs_unref_variant GVariant *var_unref = range_var;
|
|
|
|
|
gint64 start;
|
|
|
|
|
gint64 end;
|
|
|
|
|
|
|
|
|
|
if (!g_variant_lookup(range_var, "start", "t", &start))
|
|
|
|
|
continue;
|
|
|
|
|
if (!g_variant_lookup(range_var, "end", "t", &end))
|
|
|
|
|
continue;
|
|
|
|
|
if (start > end)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
g_ptr_array_add(ranges, nm_range_new(start, end));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_object_set(setting, property_info->name, ranges, NULL);
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NMTernary
|
|
|
|
|
_nm_utils_ranges_cmp(_NM_SETT_INFO_PROP_COMPARE_FCN_ARGS _nm_nil)
|
|
|
|
|
{
|
|
|
|
|
const GPtrArray *ranges_a = NULL;
|
|
|
|
|
const GPtrArray *ranges_b = NULL;
|
|
|
|
|
guint len;
|
|
|
|
|
guint i;
|
|
|
|
|
|
|
|
|
|
if (nm_streq0(nm_setting_get_name(set_a), NM_SETTING_OVS_PORT_SETTING_NAME)
|
|
|
|
|
&& nm_streq0(property_info->name, NM_SETTING_OVS_PORT_TRUNKS)) {
|
|
|
|
|
ranges_a = _nm_setting_ovs_port_get_trunks_arr(NM_SETTING_OVS_PORT(set_a));
|
|
|
|
|
if (set_b)
|
|
|
|
|
ranges_b = _nm_setting_ovs_port_get_trunks_arr(NM_SETTING_OVS_PORT(set_b));
|
|
|
|
|
} else {
|
|
|
|
|
nm_assert_not_reached();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
len = nm_g_ptr_array_len(ranges_a);
|
|
|
|
|
if (len != nm_g_ptr_array_len(ranges_b))
|
|
|
|
|
return FALSE;
|
|
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
|
if (nm_range_cmp(ranges_a->pdata[i], ranges_b->pdata[i]))
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-15 10:27:10 +02:00
|
|
|
gboolean
|
|
|
|
|
_nm_utils_iaid_verify(const char *str, gint64 *out_value)
|
|
|
|
|
{
|
2023-02-20 15:58:20 +01:00
|
|
|
gint64 i64;
|
|
|
|
|
guint32 u32;
|
2019-10-15 10:27:10 +02:00
|
|
|
|
|
|
|
|
NM_SET_OUT(out_value, -1);
|
|
|
|
|
|
|
|
|
|
if (!str || !str[0])
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (NM_IAID_IS_SPECIAL(str))
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
2023-02-20 15:58:20 +01:00
|
|
|
if (NM_STRCHAR_ALL(str, ch, g_ascii_isxdigit(ch) || NM_IN_SET(ch, 'x', ':'))) {
|
|
|
|
|
if ((i64 = _nm_utils_ascii_str_to_int64(str, 0, 0, G_MAXUINT32, -1)) != -1) {
|
|
|
|
|
NM_SET_OUT(out_value, i64);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (nm_dhcp_iaid_from_hexstr(str, &u32)) {
|
|
|
|
|
NM_SET_OUT(out_value, u32);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
2019-10-15 10:27:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2019-07-09 11:26:02 +02:00
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
|
_nm_utils_validate_dhcp_hostname_flags(NMDhcpHostnameFlags flags, int addr_family, GError **error)
|
|
|
|
|
{
|
|
|
|
|
NMDhcpHostnameFlags unknown;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-07-09 11:26:02 +02:00
|
|
|
unknown = flags;
|
|
|
|
|
unknown &= ~(NM_DHCP_HOSTNAME_FLAG_FQDN_ENCODED | NM_DHCP_HOSTNAME_FLAG_FQDN_SERV_UPDATE
|
|
|
|
|
| NM_DHCP_HOSTNAME_FLAG_FQDN_NO_UPDATE | NM_DHCP_HOSTNAME_FLAG_FQDN_CLEAR_FLAGS);
|
|
|
|
|
if (unknown) {
|
|
|
|
|
g_set_error(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("unknown flags 0x%x"),
|
|
|
|
|
(guint) unknown);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-07-09 11:26:02 +02:00
|
|
|
if (NM_FLAGS_ALL(flags,
|
|
|
|
|
NM_DHCP_HOSTNAME_FLAG_FQDN_NO_UPDATE
|
|
|
|
|
| NM_DHCP_HOSTNAME_FLAG_FQDN_SERV_UPDATE)) {
|
|
|
|
|
g_set_error_literal(
|
|
|
|
|
error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("'fqdn-no-update' and 'fqdn-serv-update' flags cannot be set at the same time"));
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-07-09 11:26:02 +02:00
|
|
|
if (NM_FLAGS_HAS(flags, NM_DHCP_HOSTNAME_FLAG_FQDN_CLEAR_FLAGS)
|
|
|
|
|
&& NM_FLAGS_ANY(flags,
|
|
|
|
|
NM_DHCP_HOSTNAME_FLAG_FQDN_SERV_UPDATE | NM_DHCP_HOSTNAME_FLAG_FQDN_ENCODED
|
|
|
|
|
| NM_DHCP_HOSTNAME_FLAG_FQDN_NO_UPDATE)) {
|
|
|
|
|
g_set_error_literal(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("'fqdn-clear-flags' flag is incompatible with other FQDN flags"));
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-07-09 11:26:02 +02:00
|
|
|
if (addr_family == AF_INET6 && (flags & NM_DHCP_HOSTNAME_FLAG_FQDN_ENCODED)) {
|
|
|
|
|
g_set_error_literal(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("DHCPv6 does not support the E (encoded) FQDN flag"));
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-07-09 11:26:02 +02:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
libnm: add nm_utils_ensure_gtypes() helper to API
"gen-metadata-nm-settings-libnm-core.xml" now contains also the names of
the NMSetting types, like "NMSettingConnection". That can be useful
to create NMSetting instances generically (that is, without knowing
the C API that gets called).
So you might be tempted to run
#!/bin/python
import gi
gi.require_version("NM", "1.0")
from gi.repository import GObject, NM
connection = NM.SimpleConnection()
# NM.utils_ensure_gtypes()
gtype_name = "NMSetting6Lowpan"
gtype = GObject.type_from_name(gtype_name)
setting = GObject.new(gtype)
connection.add_setting(setting)
However, without NM.utils_ensure_gtypes() that would not work, because
the GType is not yet created. For a user who doesn't know a priory all
setting types, it's not entirely clear how to make this work. Well, a
GObject introspection user could iterate over al NM.Setting* names and
try to instantiate the classes. However, that is still cumbersome, and not
accessible to a C user (without GI) and the currently loaded libnm
library may be newer and have unknown setting types.
In particular plain C user would need to know to call all the right
nm_setting_*_get_type(), functions, so it needs to know all the existing
52 type getters (and cannot support those from a newer libnm version).
With nm_utils_ensure_gtypes(), the user can get the typename and create
instances generically only using g_type_from_name().
Possible alternatives:
- libnm also has _nm_utils_init() which runs as __attribute__((constructor)).
We could also always instantiate all GType there. However, I don't like running
non-trivial, absolutely necessary code before main().
- hook nm_setting_get_type() to create all GType for the NMSetting
subclasses too. The problem is, that it's not entirely trivial to
avoid deadlock.
- hook nm_connection_get_type() to create all NMSetting types. That
would not deadlock, but it still is questionable whether we should
automatically, at non-obvious times instantiate all GTypes.
2022-11-04 17:06:35 +01:00
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_utils_ensure_gtypes:
|
|
|
|
|
*
|
|
|
|
|
* This ensures that all NMSetting GTypes are created. For example,
|
|
|
|
|
* after this call, g_type_from_name("NMSettingConnection") will work.
|
|
|
|
|
*
|
|
|
|
|
* This cannot fail and does nothing if the type already exists.
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.42
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
nm_utils_ensure_gtypes(void)
|
|
|
|
|
{
|
|
|
|
|
NMMetaSettingType meta_type;
|
|
|
|
|
|
|
|
|
|
for (meta_type = 0; meta_type < _NM_META_SETTING_TYPE_NUM; meta_type++)
|
|
|
|
|
nm_meta_setting_infos[meta_type].get_setting_gtype();
|
|
|
|
|
}
|
2025-09-26 21:04:04 +02:00
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|