dhcp: merge branch 'elear:mud'

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/463
This commit is contained in:
Thomas Haller 2020-04-24 10:17:14 +02:00
commit 6d0741ec9b
33 changed files with 1014 additions and 555 deletions

2
NEWS
View file

@ -8,6 +8,8 @@ The API is subject to change and not guaranteed to be compatible
with the later release.
USE AT YOUR OWN RISK. NOT RECOMMENDED FOR PRODUCTION USE!
* Add MUD URL property for connection profiles (RFC 8520) and set it
for DHCP and DHCPv6 requests.
* IPv6 SLAAC: improved the reaction of IPv6 SLAAC to renumbering events:
- honor PIO Valid Lifetimes < 2 hours.
- cap the Preferred Lifetime of PIOs to the "Router Lifetime" value

View file

@ -5227,6 +5227,9 @@ static const NMMetaPropertyInfo *const property_infos_CONNECTION[] = {
),
),
),
PROPERTY_INFO_WITH_DESC (NM_SETTING_CONNECTION_MUD_URL,
.property_type = &_pt_gobject_string,
),
PROPERTY_INFO_WITH_DESC (NM_SETTING_CONNECTION_WAIT_DEVICE_TIMEOUT,
.property_type = &_pt_gobject_int,
),

View file

@ -152,6 +152,7 @@
#define DESCRIBE_DOC_NM_SETTING_CONNECTION_MASTER N_("Interface name of the master device or UUID of the master connection.")
#define DESCRIBE_DOC_NM_SETTING_CONNECTION_MDNS N_("Whether mDNS is enabled for the connection. The permitted values are: \"yes\" (2) register hostname and resolving for the connection, \"no\" (0) disable mDNS for the interface, \"resolve\" (1) do not register hostname but allow resolving of mDNS host names and \"default\" (-1) to allow lookup of a global default in NetworkManager.conf. If unspecified, \"default\" ultimately depends on the DNS plugin (which for systemd-resolved currently means \"no\"). This feature requires a plugin which supports mDNS. Otherwise the setting has no effect. One such plugin is dns-systemd-resolved.")
#define DESCRIBE_DOC_NM_SETTING_CONNECTION_METERED N_("Whether the connection is metered. When updating this property on a currently activated connection, the change takes effect immediately.")
#define DESCRIBE_DOC_NM_SETTING_CONNECTION_MUD_URL N_("If configured, set to a Manufacturer Usage Description (MUD) URL that points to manufacturer-recommended network policies for IoT devices. It is transmitted as a DHCPv4 or DHCPv6 option.")
#define DESCRIBE_DOC_NM_SETTING_CONNECTION_MULTI_CONNECT N_("Specifies whether the profile can be active multiple times at a particular moment. The value is of type NMConnectionMultiConnect.")
#define DESCRIBE_DOC_NM_SETTING_CONNECTION_PERMISSIONS N_("An array of strings defining what access a given user has to this connection. If this is NULL or empty, all users are allowed to access this connection; otherwise users are allowed if and only if they are in this list. When this is not empty, the connection can be active only when one of the specified users is logged into an active session. Each entry is of the form \"[type]:[id]:[reserved]\"; for example, \"user:dcbw:blah\". At this time only the \"user\" [type] is allowed. Any other values are ignored and reserved for future use. [id] is the username that this permission refers to, which may not contain the \":\" character. Any [reserved] information present must be ignored and is reserved for future use. All of [type], [id], and [reserved] must be valid UTF-8.")
#define DESCRIBE_DOC_NM_SETTING_CONNECTION_READ_ONLY N_("FALSE if the connection can be modified using the provided settings service's D-Bus interface with the right privileges, or TRUE if the connection is read-only and cannot be modified.")

View file

@ -502,12 +502,12 @@ NAME UUID TYPE DEVICE
con-1 5fcfd6d7-1e63-3332-8826-a7eda103792d ethernet --
<<<
size: 1263
size: 1306
location: clients/tests/test-client.py:test_002()/23
cmd: $NMCLI c s con-1
lang: C
returncode: 0
stdout: 1138 bytes
stdout: 1181 bytes
>>>
connection.id: con-1
connection.uuid: 5fcfd6d7-1e63-3332-8826-a7eda103792d
@ -532,15 +532,16 @@ connection.metered: unknown
connection.lldp: default
connection.mdns: -1 (default)
connection.llmnr: -1 (default)
connection.mud-url: --
connection.wait-device-timeout: -1
<<<
size: 1275
size: 1318
location: clients/tests/test-client.py:test_002()/24
cmd: $NMCLI c s con-1
lang: pl_PL.UTF-8
returncode: 0
stdout: 1140 bytes
stdout: 1183 bytes
>>>
connection.id: con-1
connection.uuid: 5fcfd6d7-1e63-3332-8826-a7eda103792d
@ -565,6 +566,7 @@ connection.metered: nieznane
connection.lldp: default
connection.mdns: -1 (default)
connection.llmnr: -1 (default)
connection.mud-url: --
connection.wait-device-timeout: -1
<<<

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -16,6 +16,7 @@
#include "nm-setting-bridge.h"
#include "nm-setting-team.h"
#include "nm-setting-vlan.h"
#include "systemd/nm-sd-utils-shared.h"
/**
* SECTION:nm-setting-connection
@ -63,6 +64,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMSettingConnection,
PROP_STABLE_ID,
PROP_AUTH_RETRIES,
PROP_WAIT_DEVICE_TIMEOUT,
PROP_MUD_URL,
);
typedef struct {
@ -76,6 +78,7 @@ typedef struct {
char *master;
char *slave_type;
char *zone;
char *mud_url;
guint64 timestamp;
int autoconnect_priority;
int autoconnect_retries;
@ -750,6 +753,23 @@ nm_setting_connection_get_secondary (NMSettingConnection *setting, guint32 idx)
return (const char *) g_slist_nth_data (priv->secondaries, idx);
}
/**
* nm_setting_connection_get_mud_url:
* @setting: the #NMSettingConnection
*
* Returns the value contained in the #NMSettingConnection:mud-url
* property.
*
* Since: 1.26
**/
const char *
nm_setting_connection_get_mud_url (NMSettingConnection *setting)
{
g_return_val_if_fail (NM_IS_SETTING_CONNECTION (setting), NULL);
return NM_SETTING_CONNECTION_GET_PRIVATE (setting)->mud_url;
}
/**
* nm_setting_connection_add_secondary:
* @setting: the #NMSettingConnection
@ -1211,6 +1231,27 @@ after_interface_name:
return FALSE;
}
if (priv->mud_url) {
if (!priv->mud_url[0]) {
g_set_error_literal (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("property is empty"));
g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), NM_SETTING_CONNECTION_MUD_URL);
return FALSE;
}
if (strlen (priv->mud_url) > 255) {
g_set_error_literal (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("DHCP option cannot be longer than 255 characters"));
g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), NM_SETTING_CONNECTION_MUD_URL);
return FALSE;
}
if (!nm_sd_http_url_is_valid (priv->mud_url)) {
g_set_error_literal (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("MUD URL is not a valid URL"));
g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), NM_SETTING_CONNECTION_MUD_URL);
return FALSE;
}
}
/* *** errors above here should be always fatal, below NORMALIZABLE_ERROR *** */
if (!priv->uuid) {
@ -1467,6 +1508,9 @@ get_property (GObject *object, guint prop_id,
case PROP_WAIT_DEVICE_TIMEOUT:
g_value_set_int (value, priv->wait_device_timeout);
break;
case PROP_MUD_URL:
g_value_set_string (value, priv->mud_url);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -1562,6 +1606,10 @@ set_property (GObject *object, guint prop_id,
case PROP_WAIT_DEVICE_TIMEOUT:
priv->wait_device_timeout = g_value_get_int (value);
break;
case PROP_MUD_URL:
g_free (priv->mud_url);
priv->mud_url = g_value_dup_string (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -1611,6 +1659,7 @@ finalize (GObject *object)
g_free (priv->zone);
g_free (priv->master);
g_free (priv->slave_type);
g_free (priv->mud_url);
g_slist_free_full (priv->permissions, (GDestroyNotify) permission_free);
g_slist_free_full (priv->secondaries, g_free);
@ -2286,6 +2335,30 @@ nm_setting_connection_class_init (NMSettingConnectionClass *klass)
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
/**
* NMSettingConnection:mud-url:
*
* If configured, set to a Manufacturer Usage Description (MUD) URL that points
* to manufacturer-recommended network policies for IoT devices. It is transmitted
* as a DHCPv4 or DHCPv6 option.
*
* Since: 1.26
**/
/* ---ifcfg-rh---
* property: mud-url
* variable: MUD_URL
* values: a valid URL that points to recommended policy for this device
* description: MUD_URL to be sent by device (See RFC 8520).
* example: https://yourdevice.example.com/model.json
* ---end---
*/
obj_properties[PROP_MUD_URL] =
g_param_spec_string (NM_SETTING_CONNECTION_MUD_URL, "", "",
NULL,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
_nm_setting_class_commit_full (setting_class, NM_META_SETTING_TYPE_CONNECTION,

View file

@ -52,6 +52,7 @@ G_BEGIN_DECLS
#define NM_SETTING_CONNECTION_MDNS "mdns"
#define NM_SETTING_CONNECTION_LLMNR "llmnr"
#define NM_SETTING_CONNECTION_WAIT_DEVICE_TIMEOUT "wait-device-timeout"
#define NM_SETTING_CONNECTION_MUD_URL "mud-url"
/* Types for property values */
/**
@ -204,6 +205,9 @@ NMSettingConnectionLlmnr nm_setting_connection_get_llmnr (NMSettingConnection *
NM_AVAILABLE_IN_1_20
gint32 nm_setting_connection_get_wait_device_timeout (NMSettingConnection *setting);
NM_AVAILABLE_IN_1_26
const char *nm_setting_connection_get_mud_url (NMSettingConnection *setting);
G_END_DECLS
#endif /* __NM_SETTING_CONNECTION_H__ */

View file

@ -3334,6 +3334,7 @@ test_connection_diff_a_only (void)
{ NM_SETTING_CONNECTION_AUTH_RETRIES, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_CONNECTION_MDNS, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_CONNECTION_LLMNR, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_CONNECTION_MUD_URL, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_CONNECTION_WAIT_DEVICE_TIMEOUT, NM_SETTING_DIFF_RESULT_IN_A },
{ NULL, NM_SETTING_DIFF_RESULT_UNKNOWN }
} },

View file

@ -1695,3 +1695,8 @@ global:
nm_setting_vrf_get_type;
nm_setting_vrf_new;
} libnm_1_22_8;
libnm_1_26_0 {
global:
nm_setting_connection_get_mud_url;
} libnm_1_24_0;

View file

@ -13,6 +13,7 @@
#include "hexdecoct.h"
#include "hostname-util.h"
#include "path-util.h"
#include "web-util.h"
/*****************************************************************************/
@ -94,3 +95,40 @@ gboolean nm_sd_hostname_is_valid (const char *s, bool allow_trailing_dot)
{
return hostname_is_valid (s, allow_trailing_dot);
}
/*****************************************************************************/
static gboolean
_http_url_is_valid (const char *url)
{
if ( !url
|| !url[0])
return FALSE;
if (NM_STR_HAS_PREFIX (url, "http://"))
url += NM_STRLEN ("http://");
else if (NM_STR_HAS_PREFIX (url, "https://"))
url += NM_STRLEN ("https://");
else
return FALSE;
if (!url[0])
return FALSE;
return !NM_STRCHAR_ANY (url, ch, (guchar) ch >= 128u);
}
gboolean
nm_sd_http_url_is_valid (const char *url)
{
gboolean v;
/* http_url_is_valid() is part of our API, as we use it to validate connection
* properties. That means, it's behavior must remain stable (or only change
* with care).
*
* Thus, reimplement it, and make sure that our implementation agrees. */
v = _http_url_is_valid (url);
nm_assert (v == http_url_is_valid (url));
return v;
}

View file

@ -34,4 +34,8 @@ int nm_sd_dns_name_to_wire_format (const char *domain,
int nm_sd_dns_name_is_valid (const char *s);
gboolean nm_sd_hostname_is_valid(const char *s, bool allow_trailing_dot);
/*****************************************************************************/
gboolean nm_sd_http_url_is_valid (const char *url);
#endif /* __NM_SD_UTILS_SHARED_H__ */

View file

@ -24,21 +24,25 @@ bool http_etag_is_valid(const char *etag) {
}
#endif /* NM_IGNORED */
bool http_url_is_valid(const char *url) {
const char *p;
if (isempty(url))
return false;
p = STARTSWITH_SET(url, "http://", "https://");
if (!p)
return false;
if (isempty(p))
return false;
return ascii_is_valid(p);
}
/* NM: we use http_url_is_valid() for our own code, and it must not
* change behavior. If a re-import results in a merge-conflict, you must
* ensure that it does not change behavior, and possibly do something
* about that. */
/**/ bool http_url_is_valid(const char *url) {
/**/ const char *p;
/**/
/**/ if (isempty(url))
/**/ return false;
/**/
/**/ p = STARTSWITH_SET(url, "http://", "https://");
/**/ if (!p)
/**/ return false;
/**/
/**/ if (isempty(p))
/**/ return false;
/**/
/**/ return ascii_is_valid(p);
/**/ }
#if 0 /* NM_IGNORED */
bool documentation_url_is_valid(const char *url) {

View file

@ -8427,6 +8427,7 @@ dhcp4_start (NMDevice *self)
gs_unref_bytes GBytes *bcast_hwaddr = NULL;
gs_unref_bytes GBytes *client_id = NULL;
NMConnection *connection;
NMSettingConnection *s_con;
GError *error = NULL;
const NMPlatformLink *pllink;
@ -8435,6 +8436,9 @@ dhcp4_start (NMDevice *self)
s_ip4 = nm_connection_get_setting_ip4_config (connection);
s_con = nm_connection_get_setting_connection (connection);
nm_assert (s_con);
/* Clear old exported DHCP options */
nm_dbus_object_clear_and_unexport (&priv->dhcp_data_4.config);
priv->dhcp_data_4.config = nm_dhcp_config_new (AF_INET);
@ -8461,6 +8465,7 @@ dhcp4_start (NMDevice *self)
nm_setting_ip_config_get_dhcp_hostname (s_ip4),
nm_setting_ip4_config_get_dhcp_fqdn (NM_SETTING_IP4_CONFIG (s_ip4)),
get_dhcp_hostname_flags (self, AF_INET),
nm_setting_connection_get_mud_url (s_con),
client_id,
get_dhcp_timeout (self, AF_INET),
priv->dhcp_anycast_address,
@ -9211,12 +9216,15 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection)
GError *error = NULL;
guint32 iaid;
gboolean iaid_explicit;
NMSettingConnection *s_con;
const NMPlatformIP6Address *ll_addr = NULL;
g_assert (connection);
g_return_val_if_fail (connection, FALSE);
s_ip6 = nm_connection_get_setting_ip6_config (connection);
g_assert (s_ip6);
nm_assert (s_ip6);
s_con = nm_connection_get_setting_connection (connection);
nm_assert (s_con);
if (priv->ext_ip6_config_captured) {
ll_addr = nm_ip6_config_find_first_address (priv->ext_ip6_config_captured,
@ -9251,6 +9259,7 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection)
nm_setting_ip_config_get_dhcp_send_hostname (s_ip6),
nm_setting_ip_config_get_dhcp_hostname (s_ip6),
get_dhcp_hostname_flags (self, AF_INET6),
nm_setting_connection_get_mud_url (s_con),
duid,
enforce_duid,
iaid,

View file

@ -50,6 +50,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMDhcpClient,
PROP_IAID_EXPLICIT,
PROP_HOSTNAME,
PROP_HOSTNAME_FLAGS,
PROP_MUD_URL,
);
typedef struct _NMDhcpClientPrivate {
@ -60,6 +61,7 @@ typedef struct _NMDhcpClientPrivate {
char * uuid;
GBytes * client_id;
char * hostname;
char * mud_url;
pid_t pid;
guint timeout_id;
guint watch_id;
@ -312,6 +314,14 @@ nm_dhcp_client_get_use_fqdn (NMDhcpClient *self)
return NM_DHCP_CLIENT_GET_PRIVATE (self)->use_fqdn;
}
const char *
nm_dhcp_client_get_mud_url (NMDhcpClient *self)
{
g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), NULL);
return NM_DHCP_CLIENT_GET_PRIVATE (self)->mud_url;
}
/*****************************************************************************/
static const char *state_table[NM_DHCP_STATE_MAX + 1] = {
@ -1052,6 +1062,10 @@ set_property (GObject *object, guint prop_id,
/* construct-only */
priv->hostname_flags = g_value_get_uint (value);
break;
case PROP_MUD_URL:
/* construct-only */
priv->mud_url = g_value_dup_string (value);
break;
case PROP_ROUTE_TABLE:
priv->route_table = g_value_get_uint (value);
break;
@ -1102,6 +1116,7 @@ dispose (GObject *object)
nm_clear_g_free (&priv->iface);
nm_clear_g_free (&priv->hostname);
nm_clear_g_free (&priv->uuid);
nm_clear_g_free (&priv->mud_url);
nm_clear_pointer (&priv->client_id, g_bytes_unref);
nm_clear_pointer (&priv->hwaddr, g_bytes_unref);
nm_clear_pointer (&priv->bcast_hwaddr, g_bytes_unref);
@ -1191,6 +1206,12 @@ nm_dhcp_client_class_init (NMDhcpClientClass *client_class)
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
obj_properties[PROP_MUD_URL] =
g_param_spec_string (NM_DHCP_CLIENT_MUD_URL, "", "",
NULL,
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
obj_properties[PROP_ROUTE_TABLE] =
g_param_spec_uint (NM_DHCP_CLIENT_ROUTE_TABLE, "", "",
0, G_MAXUINT32, RT_TABLE_MAIN,

View file

@ -30,6 +30,7 @@
#define NM_DHCP_CLIENT_INTERFACE "iface"
#define NM_DHCP_CLIENT_MULTI_IDX "multi-idx"
#define NM_DHCP_CLIENT_HOSTNAME "hostname"
#define NM_DHCP_CLIENT_MUD_URL "mud-url"
#define NM_DHCP_CLIENT_ROUTE_METRIC "route-metric"
#define NM_DHCP_CLIENT_ROUTE_TABLE "route-table"
#define NM_DHCP_CLIENT_TIMEOUT "timeout"
@ -141,6 +142,7 @@ gboolean nm_dhcp_client_get_iaid_explicit (NMDhcpClient *self);
GBytes *nm_dhcp_client_get_client_id (NMDhcpClient *self);
const char *nm_dhcp_client_get_hostname (NMDhcpClient *self);
const char *nm_dhcp_client_get_mud_url (NMDhcpClient *self);
NMDhcpHostnameFlags nm_dhcp_client_get_hostname_flags (NMDhcpClient *self);

View file

@ -33,6 +33,13 @@
#define ALSOREQ_TAG "also request "
#define REQ_TAG "request "
#define MUDURLv4_DEF "option mudurl code 161 = text;\n"
#define MUDURLv4_FMT "send mudurl \"%s\";\n"
#define MUDURLv6_DEF "option dhcp6.mudurl code 112 = text;\n"
#define MUDURLv6_FMT "send dhcp6.mudurl \"%s\";\n"
static void
add_request (GPtrArray *array, const char *item)
{
@ -183,6 +190,19 @@ add_hostname6 (GString *str,
}
}
static void add_mud_url_config(GString *str, const char *mud_url, int addr_family)
{
if (mud_url) {
if (addr_family == AF_INET) {
g_string_append (str, MUDURLv4_DEF);
g_string_append_printf (str, MUDURLv4_FMT, mud_url);
} else {
g_string_append (str, MUDURLv6_DEF);
g_string_append_printf (str, MUDURLv6_FMT, mud_url);
}
}
}
static GBytes *
read_client_id (const char *str)
{
@ -286,6 +306,7 @@ nm_dhcp_dhclient_create_config (const char *interface,
guint32 timeout,
gboolean use_fqdn,
NMDhcpHostnameFlags hostname_flags,
const char *mud_url,
const char *orig_path,
const char *orig_contents,
GBytes **out_new_client_id)
@ -451,6 +472,7 @@ nm_dhcp_dhclient_create_config (const char *interface,
g_string_append_printf (new_contents, "timeout %u;\n", timeout);
}
add_mud_url_config (new_contents, mud_url, addr_family);
if (addr_family == AF_INET) {
add_ip4_config (new_contents, client_id, hostname, use_fqdn, hostname_flags);
add_request (reqs, "rfc3442-classless-static-routes");

View file

@ -17,6 +17,7 @@ char *nm_dhcp_dhclient_create_config (const char *interface,
guint32 timeout,
gboolean use_fqdn,
NMDhcpHostnameFlags hostname_flags,
const char *mud_url,
const char *orig_path,
const char *orig_contents,
GBytes **out_new_client_id);

View file

@ -147,6 +147,7 @@ merge_dhclient_config (NMDhcpDhclient *self,
guint32 timeout,
gboolean use_fqdn,
NMDhcpHostnameFlags hostname_flags,
const char *mud_url,
const char *orig_path,
GBytes **out_new_client_id,
GError **error)
@ -176,6 +177,7 @@ merge_dhclient_config (NMDhcpDhclient *self,
timeout,
use_fqdn,
hostname_flags,
mud_url,
orig_path,
orig,
out_new_client_id);
@ -268,6 +270,7 @@ create_dhclient_config (NMDhcpDhclient *self,
guint32 timeout,
gboolean use_fqdn,
NMDhcpHostnameFlags hostname_flags,
const char *mud_url,
GBytes **out_new_client_id)
{
gs_free char *orig = NULL;
@ -296,6 +299,7 @@ create_dhclient_config (NMDhcpDhclient *self,
timeout,
use_fqdn,
hostname_flags,
mud_url,
orig,
out_new_client_id,
&error)) {
@ -496,6 +500,7 @@ ip4_start (NMDhcpClient *client,
nm_dhcp_client_get_timeout (client),
nm_dhcp_client_get_use_fqdn (client),
nm_dhcp_client_get_hostname_flags (client),
nm_dhcp_client_get_mud_url (client),
&new_client_id);
if (!priv->conf_file) {
nm_utils_error_set_literal (error,
@ -540,6 +545,7 @@ ip6_start (NMDhcpClient *client,
nm_dhcp_client_get_timeout (client),
TRUE,
nm_dhcp_client_get_hostname_flags (client),
nm_dhcp_client_get_mud_url (client),
NULL);
if (!priv->conf_file) {
nm_utils_error_set_literal (error,

View file

@ -220,6 +220,7 @@ client_start (NMDhcpManager *self,
const char *hostname,
gboolean hostname_use_fqdn,
NMDhcpHostnameFlags hostname_flags,
const char *mud_url,
gboolean info_only,
NMSettingIP6ConfigPrivacy privacy,
const char *last_ip4_address,
@ -303,6 +304,7 @@ client_start (NMDhcpManager *self,
NM_DHCP_CLIENT_IAID, (guint) iaid,
NM_DHCP_CLIENT_IAID_EXPLICIT, iaid_explicit,
NM_DHCP_CLIENT_HOSTNAME, hostname,
NM_DHCP_CLIENT_MUD_URL, mud_url,
NM_DHCP_CLIENT_ROUTE_TABLE, (guint) route_table,
NM_DHCP_CLIENT_ROUTE_METRIC, (guint) route_metric,
NM_DHCP_CLIENT_TIMEOUT, (guint) timeout,
@ -382,6 +384,7 @@ nm_dhcp_manager_start_ip4 (NMDhcpManager *self,
const char *dhcp_hostname,
const char *dhcp_fqdn,
NMDhcpHostnameFlags hostname_flags,
const char *mud_url,
GBytes *dhcp_client_id,
guint32 timeout,
const char *dhcp_anycast_addr,
@ -440,6 +443,7 @@ nm_dhcp_manager_start_ip4 (NMDhcpManager *self,
hostname,
use_fqdn,
hostname_flags,
mud_url,
FALSE,
0,
last_ip_address,
@ -462,6 +466,7 @@ nm_dhcp_manager_start_ip6 (NMDhcpManager *self,
gboolean send_hostname,
const char *dhcp_hostname,
NMDhcpHostnameFlags hostname_flags,
const char *mud_url,
GBytes *duid,
gboolean enforce_duid,
guint32 iaid,
@ -503,6 +508,7 @@ nm_dhcp_manager_start_ip6 (NMDhcpManager *self,
hostname,
TRUE,
hostname_flags,
mud_url,
info_only,
privacy,
NULL,

View file

@ -43,6 +43,7 @@ NMDhcpClient * nm_dhcp_manager_start_ip4 (NMDhcpManager *manager,
const char *dhcp_hostname,
const char *dhcp_fqdn,
NMDhcpHostnameFlags hostname_flags,
const char *mud_url,
GBytes *dhcp_client_id,
guint32 timeout,
const char *dhcp_anycast_addr,
@ -62,6 +63,7 @@ NMDhcpClient * nm_dhcp_manager_start_ip6 (NMDhcpManager *manager,
gboolean send_hostname,
const char *dhcp_hostname,
NMDhcpHostnameFlags hostname_flags,
const char *mud_url,
GBytes *duid,
gboolean enforce_duid,
guint32 iaid,

View file

@ -68,6 +68,20 @@ G_DEFINE_TYPE (NMDhcpNettools, nm_dhcp_nettools, NM_TYPE_DHCP_CLIENT)
/*****************************************************************************/
static void
set_error_nettools (GError **error, int r, const char *message)
{
/* the error code returned from n_dhcp4_* API is either a negative
* errno, or a positive internal error code. Generate different messages
* for these. */
if (r < 0)
nm_utils_error_set_errno (error, r, "%s: %s", message);
else
nm_utils_error_set (error, r, "%s (code %d)", message, r);
}
/*****************************************************************************/
#define DHCP_MAX_FQDN_LENGTH 255
enum {
@ -681,11 +695,10 @@ lease_parse_metered (NDhcp4ClientLease *lease,
int r;
r = n_dhcp4_client_lease_query (lease, NM_DHCP_OPTION_DHCP4_VENDOR_SPECIFIC, &data, &n_data);
if (r) {
if (r)
metered = FALSE;
} else {
else
metered = !!memmem (data, n_data, "ANDROID_METERED", NM_STRLEN ("ANDROID_METERED"));
}
/* TODO: expose the vendor specific option when present */
nm_ip4_config_set_metered (ip4_config, metered);
@ -1023,9 +1036,8 @@ dhcp4_event_handle (NMDhcpNettools *self,
case N_DHCP4_CLIENT_EVENT_OFFER:
/* always accept the first lease */
r = n_dhcp4_client_lease_select (event->offer.lease);
if (r) {
if (r)
_LOGW ("selecting lease failed: %d", r);
}
break;
case N_DHCP4_CLIENT_EVENT_RETRACTED:
case N_DHCP4_CLIENT_EVENT_EXPIRED:
@ -1170,7 +1182,7 @@ nettools_create (NMDhcpNettools *self,
r = n_dhcp4_client_config_new (&config);
if (r) {
nm_utils_error_set_errno (error, r, "failed to create client-config: %s");
set_error_nettools (error, r, "failed to create client-config");
return FALSE;
}
@ -1184,13 +1196,13 @@ nettools_create (NMDhcpNettools *self,
client_id_arr,
NM_MIN (client_id_len, 1 + _NM_SD_MAX_CLIENT_ID_LEN));
if (r) {
nm_utils_error_set_errno (error, r, "failed to set client-id: %s");
set_error_nettools (error, r, "failed to set client-id");
return FALSE;
}
r = n_dhcp4_client_new (&client, config);
if (r) {
nm_utils_error_set (error, NM_UTILS_ERROR_UNKNOWN, "failed to create client: error %d", r);
set_error_nettools (error, r, "failed to create client");
return FALSE;
}
@ -1224,7 +1236,7 @@ _accept (NMDhcpClient *client,
r = n_dhcp4_client_lease_accept (priv->lease);
if (r) {
nm_utils_error_set_errno (error, r, "failed to accept lease: %s");
set_error_nettools (error, r, "failed to accept lease");
return FALSE;
}
@ -1248,7 +1260,7 @@ decline (NMDhcpClient *client,
r = n_dhcp4_client_lease_decline (priv->lease, error_message);
if (r) {
nm_utils_error_set_errno (error, r, "failed to decline lease: %s");
set_error_nettools (error, r, "failed to decline lease");
return FALSE;
}
@ -1285,6 +1297,7 @@ ip4_start (NMDhcpClient *client,
gs_free char *lease_file = NULL;
struct in_addr last_addr = { 0 };
const char *hostname;
const char *mud_url;
int r, i;
g_return_val_if_fail (!priv->probe, FALSE);
@ -1294,7 +1307,7 @@ ip4_start (NMDhcpClient *client,
r = n_dhcp4_client_probe_config_new (&config);
if (r) {
nm_utils_error_set_errno (error, r, "failed to create dhcp-client-probe-config: %s");
set_error_nettools (error, r, "failed to create dhcp-client-probe-config");
return FALSE;
}
@ -1341,6 +1354,17 @@ ip4_start (NMDhcpClient *client,
}
}
mud_url = nm_dhcp_client_get_mud_url (client);
if (mud_url) {
r = n_dhcp4_client_probe_config_append_option (config,
NM_DHCP_OPTION_DHCP4_MUD_URL,
mud_url,
strlen (mud_url));
if (r) {
set_error_nettools (error, r, "failed to set MUD URL");
return FALSE;
}
}
hostname = nm_dhcp_client_get_hostname (client);
if (hostname) {
if (nm_dhcp_client_get_use_fqdn (client)) {
@ -1359,7 +1383,10 @@ ip4_start (NMDhcpClient *client,
sizeof (buffer) - 3,
FALSE);
if (r <= 0) {
nm_utils_error_set_errno (error, r, "failed to convert DHCP FQDN: %s");
if (r < 0)
nm_utils_error_set_errno (error, r, "failed to convert DHCP FQDN: %s");
else
nm_utils_error_set (error, r, "failed to convert DHCP FQDN");
return FALSE;
}
fqdn_len = r;
@ -1377,7 +1404,7 @@ ip4_start (NMDhcpClient *client,
buffer,
3 + fqdn_len);
if (r) {
nm_utils_error_set_errno (error, r, "failed to set DHCP FQDN: %s");
set_error_nettools (error, r, "failed to set DHCP FQDN");
return FALSE;
}
} else {
@ -1386,7 +1413,7 @@ ip4_start (NMDhcpClient *client,
hostname,
strlen (hostname));
if (r) {
nm_utils_error_set_errno (error, r, "failed to set DHCP hostname: %s");
set_error_nettools (error, r, "failed to set DHCP hostname");
return FALSE;
}
}
@ -1397,7 +1424,7 @@ ip4_start (NMDhcpClient *client,
r = n_dhcp4_client_probe (priv->client, &priv->probe, config);
if (r) {
nm_utils_error_set_errno (error, r, "failed to start DHCP client: %s");
set_error_nettools (error, r, "failed to start DHCP client");
return FALSE;
}

View file

@ -126,6 +126,7 @@ const NMDhcpOption _nm_dhcp_option_dhcp4_options[] = {
REQ (NM_DHCP_OPTION_DHCP4_TFTP_SERVER_ADDRESS, "tftp_server_address", FALSE ),
REQ (NM_DHCP_OPTION_DHCP4_V4_PORTPARAMS, "v4_portparams", FALSE ),
REQ (NM_DHCP_OPTION_DHCP4_V4_CAPTIVE_PORTAL, "v4_captive_portal", FALSE ),
REQ (NM_DHCP_OPTION_DHCP4_MUD_URL, "mud_url", FALSE ),
REQ (NM_DHCP_OPTION_DHCP4_LOADER_CONFIGFILE, "loader_configfile", FALSE ),
REQ (NM_DHCP_OPTION_DHCP4_LOADER_PATHPREFIX, "loader_pathprefix", FALSE ),
REQ (NM_DHCP_OPTION_DHCP4_LOADER_REBOOTTIME, "loader_reboottime", FALSE ),
@ -182,6 +183,7 @@ const NMDhcpOption _nm_dhcp_option_dhcp6_options[] = {
REQ (NM_DHCP_OPTION_DHCP6_DNS_SERVERS, "dhcp6_name_servers", TRUE ),
REQ (NM_DHCP_OPTION_DHCP6_DOMAIN_LIST, "dhcp6_domain_search", TRUE ),
REQ (NM_DHCP_OPTION_DHCP6_SNTP_SERVERS, "dhcp6_sntp_servers", TRUE ),
REQ (NM_DHCP_OPTION_DHCP6_MUD_URL, "dhcp6_mud_url", FALSE ),
/* Internal values */
REQ (NM_DHCP_OPTION_DHCP6_NM_IP_ADDRESS, "ip6_address", FALSE ),

View file

@ -110,6 +110,7 @@ typedef enum {
NM_DHCP_OPTION_DHCP4_TFTP_SERVER_ADDRESS = 150,
NM_DHCP_OPTION_DHCP4_V4_PORTPARAMS = 159,
NM_DHCP_OPTION_DHCP4_V4_CAPTIVE_PORTAL = 160,
NM_DHCP_OPTION_DHCP4_MUD_URL = 161,
NM_DHCP_OPTION_DHCP4_LOADER_CONFIGFILE = 209,
NM_DHCP_OPTION_DHCP4_LOADER_PATHPREFIX = 210,
NM_DHCP_OPTION_DHCP4_LOADER_REBOOTTIME = 211,
@ -159,6 +160,7 @@ typedef enum {
NM_DHCP_OPTION_DHCP6_DNS_SERVERS = 23,
NM_DHCP_OPTION_DHCP6_DOMAIN_LIST = 24,
NM_DHCP_OPTION_DHCP6_SNTP_SERVERS = 31,
NM_DHCP_OPTION_DHCP6_MUD_URL = 112,
/* Internal values */
NM_DHCP_OPTION_DHCP6_NM_IP_ADDRESS = 1026,
NM_DHCP_OPTION_DHCP6_NM_PREFIXLEN = 1027,

View file

@ -573,6 +573,7 @@ ip4_start (NMDhcpClient *client,
size_t client_id_len;
struct in_addr last_addr = { 0 };
const char *hostname;
const char *mud_url;
int r, i;
g_return_val_if_fail (!priv->client4, FALSE);
@ -688,6 +689,15 @@ ip4_start (NMDhcpClient *client,
}
}
mud_url = nm_dhcp_client_get_mud_url (client);
if (mud_url) {
r = sd_dhcp_client_set_mud_url (sd_client, mud_url);
if (r < 0) {
nm_utils_error_set_errno (error, r, "failed to set DHCP MUDURL: %s");
return FALSE;
}
}
r = sd_dhcp_client_set_callback (sd_client, dhcp_event_cb, client);
if (r < 0) {
nm_utils_error_set_errno (error, r, "failed to set callback: %s");
@ -894,6 +904,7 @@ ip6_start (NMDhcpClient *client,
nm_auto (sd_dhcp6_client_unrefp) sd_dhcp6_client *sd_client = NULL;
GBytes *hwaddr;
const char *hostname;
const char *mud_url;
int r, i;
const guint8 *duid_arr;
gsize duid_len;
@ -976,6 +987,15 @@ ip6_start (NMDhcpClient *client,
}
}
mud_url = nm_dhcp_client_get_mud_url (client);
if (mud_url) {
r = sd_dhcp6_client_set_request_mud_url (sd_client, mud_url);
if (r < 0) {
nm_utils_error_set_errno (error, r, "failed to set mud-url: %s");
return FALSE;
}
}
if (needed_prefixes > 0) {
if (needed_prefixes > 1)
_LOGW ("dhcp-client6: only one prefix request is supported");

View file

@ -21,6 +21,7 @@
#include "nm-test-utils-core.h"
#define TEST_DIR NM_BUILD_SRCDIR"/src/dhcp/tests"
#define TEST_MUDURL "https://example.com/mud.json"
static void
test_config (const char *orig,
@ -33,7 +34,8 @@ test_config (const char *orig,
const char *dhcp_client_id,
GBytes *expected_new_client_id,
const char *iface,
const char *anycast_addr)
const char *anycast_addr,
const char *mud_url)
{
gs_free char *new = NULL;
gs_unref_bytes GBytes *client_id = NULL;
@ -52,6 +54,7 @@ test_config (const char *orig,
timeout,
use_fqdn,
hostname_flags,
mud_url,
"/path/to/dhclient.conf",
orig,
&new_client_id);
@ -100,7 +103,37 @@ test_orig_missing (void)
orig_missing_expected,
AF_INET, NULL, 0, FALSE,
NM_DHCP_HOSTNAME_FLAG_NONE,
NULL, NULL, "eth0", NULL);
NULL, NULL, "eth0", NULL, NULL);
}
/*****************************************************************************/
static const char *orig_missing_add_mud_url_expected = \
"# Created by NetworkManager\n"
"\n"
"option mudurl code 161 = text;\n"
"send mudurl \"https://example.com/mud.json\";\n\n"
"option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n"
"option ms-classless-static-routes code 249 = array of unsigned integer 8;\n"
"option wpad code 252 = string;\n"
"\n"
"also request rfc3442-classless-static-routes;\n"
"also request ms-classless-static-routes;\n"
"also request static-routes;\n"
"also request wpad;\n"
"also request ntp-servers;\n"
"also request root-path;\n"
"\n";
static void
test_orig_missing_add_mud_url (void)
{
test_config (NULL,
orig_missing_add_mud_url_expected,
AF_INET, NULL, 0, FALSE,
NM_DHCP_HOSTNAME_FLAG_NONE,
NULL, NULL, "eth0", NULL, TEST_MUDURL);
}
/*****************************************************************************/
@ -135,6 +168,7 @@ test_override_client_id (void)
"11:22:33:44:55:66",
NULL,
"eth0",
NULL,
NULL);
}
@ -166,6 +200,7 @@ test_quote_client_id (void)
"abcd",
NULL,
"eth0",
NULL,
NULL);
}
@ -197,6 +232,7 @@ test_quote_client_id_2 (void)
"a\\bc",
NULL,
"eth0",
NULL,
NULL);
}
@ -228,6 +264,7 @@ test_hex_zero_client_id (void)
"00:11:22:33",
NULL,
"eth0",
NULL,
NULL);
}
@ -259,6 +296,7 @@ test_ascii_client_id (void)
"qb:cd:ef:12:34:56",
NULL,
"eth0",
NULL,
NULL);
}
@ -290,6 +328,7 @@ test_hex_single_client_id (void)
"ab:cd:e:12:34:56",
NULL,
"eth0",
NULL,
NULL);
}
@ -329,6 +368,7 @@ test_existing_hex_client_id (void)
NULL,
new_client_id,
"eth0",
NULL,
NULL);
}
@ -367,6 +407,7 @@ test_existing_escaped_client_id (void)
NULL,
new_client_id,
"eth0",
NULL,
NULL);
}
@ -409,6 +450,7 @@ test_existing_ascii_client_id (void)
NULL,
new_client_id,
"eth0",
NULL,
NULL);
}
/*****************************************************************************/
@ -443,6 +485,7 @@ test_fqdn (void)
NULL,
NULL,
"eth0",
NULL,
NULL);
}
@ -486,6 +529,7 @@ test_fqdn_options_override (void)
TRUE, NULL,
NULL,
"eth0",
NULL,
NULL);
}
@ -521,6 +565,7 @@ test_override_hostname (void)
NULL,
NULL,
"eth0",
NULL,
NULL);
}
@ -550,6 +595,7 @@ test_override_hostname6 (void)
NULL,
NULL,
"eth0",
NULL,
NULL);
}
@ -576,6 +622,7 @@ test_nonfqdn_hostname6 (void)
NULL,
NULL,
"eth0",
NULL,
NULL);
}
@ -613,6 +660,7 @@ test_existing_alsoreq (void)
NULL,
NULL,
"eth0",
NULL,
NULL);
}
@ -653,6 +701,7 @@ test_existing_req (void)
NULL,
NULL,
"eth0",
NULL,
NULL);
}
@ -694,6 +743,7 @@ test_existing_multiline_alsoreq (void)
NULL,
NULL,
"eth0",
NULL,
NULL);
}
@ -934,6 +984,7 @@ test_interface1 (void)
NULL,
NULL,
"eth0",
NULL,
NULL);
}
@ -981,6 +1032,7 @@ test_interface2 (void)
NULL,
NULL,
"eth1",
NULL,
NULL);
}
@ -1093,6 +1145,7 @@ test_structured (void)
NULL,
new_client_id,
"eth0",
NULL,
NULL);
}
@ -1149,6 +1202,7 @@ test_config_req_intf (void)
NULL,
NULL,
"eth0",
NULL,
NULL);
}
@ -1162,6 +1216,7 @@ main (int argc, char **argv)
nmtst_init_with_logging (&argc, &argv, NULL, "DEFAULT");
g_test_add_func ("/dhcp/dhclient/orig_missing", test_orig_missing);
g_test_add_func ("/dhcp/dhclient/orig_missing_add_mud_url", test_orig_missing_add_mud_url);
g_test_add_func ("/dhcp/dhclient/override_client_id", test_override_client_id);
g_test_add_func ("/dhcp/dhclient/quote_client_id/1", test_quote_client_id);
g_test_add_func ("/dhcp/dhclient/quote_client_id/2", test_quote_client_id_2);

View file

@ -64,6 +64,7 @@ static struct {
char *dhcp4_clientid;
char *dhcp4_hostname;
char *dhcp4_fqdn;
char *mud_url;
char *iid_str;
NMSettingIP6ConfigAddrGenMode addr_gen_mode;
char *logging_backend;
@ -523,6 +524,7 @@ main (int argc, char *argv[])
global_opt.dhcp4_hostname,
global_opt.dhcp4_fqdn,
NM_DHCP_HOSTNAME_FLAGS_FQDN_DEFAULT_IP4,
global_opt.mud_url,
client_id,
NM_DHCP_TIMEOUT_DEFAULT,
NULL,

View file

@ -582,6 +582,11 @@ make_connection_setting (const char *file,
g_object_set (s_con, NM_SETTING_CONNECTION_WAIT_DEVICE_TIMEOUT, (int) vint64, NULL);
}
nm_clear_g_free (&value);
v = svGetValueStr (ifcfg, "MUD_URL", &value);
if (v)
g_object_set (s_con, NM_SETTING_CONNECTION_MUD_URL, v, NULL);
i_val = NM_SETTING_CONNECTION_MDNS_DEFAULT;
if (!svGetValueEnum (ifcfg, "MDNS",
nm_setting_connection_mdns_get_type (),

View file

@ -893,6 +893,7 @@ const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[] = {
_KEY_TYPE ("METRIC", NMS_IFCFG_KEY_TYPE_IS_NUMBERED ),
_KEY_TYPE ("MODE", NMS_IFCFG_KEY_TYPE_IS_PLAIN ),
_KEY_TYPE ("MTU", NMS_IFCFG_KEY_TYPE_IS_PLAIN ),
_KEY_TYPE ("MUD_URL", NMS_IFCFG_KEY_TYPE_IS_PLAIN ),
_KEY_TYPE ("MULTI_CONNECT", NMS_IFCFG_KEY_TYPE_IS_PLAIN ),
_KEY_TYPE ("MVRP", NMS_IFCFG_KEY_TYPE_IS_PLAIN ),
_KEY_TYPE ("NAME", NMS_IFCFG_KEY_TYPE_IS_PLAIN ),

View file

@ -33,7 +33,7 @@ typedef struct {
NMSIfcfgKeyTypeFlags key_flags;
} NMSIfcfgKeyTypeInfo;
extern const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[232];
extern const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[233];
const NMSIfcfgKeyTypeInfo *nms_ifcfg_well_known_key_find_info (const char *key, gssize *out_idx);

View file

@ -1792,7 +1792,7 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg)
NMSettingConnectionMdns mdns;
NMSettingConnectionLlmnr llmnr;
guint32 vuint32;
const char *tmp;
const char *tmp, *mud_url;
svSetValueStr (ifcfg, "NAME", nm_setting_connection_get_id (s_con));
svSetValueStr (ifcfg, "UUID", nm_setting_connection_get_uuid (s_con));
@ -1867,6 +1867,9 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg)
svSetValueStr (ifcfg, "TEAM_MASTER_UUID", NULL);
svSetValueStr (ifcfg, "TEAM_MASTER", NULL);
mud_url = nm_setting_connection_get_mud_url (s_con);
svSetValueStr (ifcfg, "MUD_URL", mud_url);
master = nm_setting_connection_get_master (s_con);
if (master) {
/* The reader prefers the *_UUID variants, however we still try to resolve

View file

@ -371,7 +371,7 @@ int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option)
return 0;
}
int sd_dhcp6_client_set_request_mud_url(sd_dhcp6_client *client, char *mudurl) {
int sd_dhcp6_client_set_request_mud_url(sd_dhcp6_client *client, const char *mudurl) {
assert_return(client, -EINVAL);
assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);

View file

@ -123,7 +123,7 @@ int sd_dhcp6_client_set_request_option(
uint16_t option);
int sd_dhcp6_client_set_request_mud_url(
sd_dhcp6_client *client,
char *mudurl);
const char *mudurl);
int sd_dhcp6_client_set_prefix_delegation_hint(
sd_dhcp6_client *client,
uint8_t prefixlen,