diff options
Diffstat (limited to 'src/core/dhcp')
-rw-r--r-- | src/core/dhcp/README.next.md | 103 | ||||
-rw-r--r-- | src/core/dhcp/nm-dhcp-client.c | 1087 | ||||
-rw-r--r-- | src/core/dhcp/nm-dhcp-client.h | 259 | ||||
-rw-r--r-- | src/core/dhcp/nm-dhcp-dhclient-utils.c | 1 | ||||
-rw-r--r-- | src/core/dhcp/nm-dhcp-dhclient.c | 145 | ||||
-rw-r--r-- | src/core/dhcp/nm-dhcp-dhcpcanon.c | 2 | ||||
-rw-r--r-- | src/core/dhcp/nm-dhcp-dhcpcd.c | 22 | ||||
-rw-r--r-- | src/core/dhcp/nm-dhcp-manager.c | 321 | ||||
-rw-r--r-- | src/core/dhcp/nm-dhcp-manager.h | 48 | ||||
-rw-r--r-- | src/core/dhcp/nm-dhcp-nettools.c | 338 | ||||
-rw-r--r-- | src/core/dhcp/nm-dhcp-systemd.c | 334 | ||||
-rw-r--r-- | src/core/dhcp/nm-dhcp-utils.c | 299 | ||||
-rw-r--r-- | src/core/dhcp/nm-dhcp-utils.h | 31 | ||||
-rw-r--r-- | src/core/dhcp/tests/test-dhcp-dhclient.c | 1 | ||||
-rw-r--r-- | src/core/dhcp/tests/test-dhcp-utils.c | 567 |
15 files changed, 1536 insertions, 2022 deletions
diff --git a/src/core/dhcp/README.next.md b/src/core/dhcp/README.next.md new file mode 100644 index 0000000000..88fa6683c7 --- /dev/null +++ b/src/core/dhcp/README.next.md @@ -0,0 +1,103 @@ +`NMDhcpClient` +============== + +Using `NMDhcpClient` still requires a lot of logic in `NMDevice`. The main goal +is to simplify `NMDevice`, so `NMDhcpClient` must become more complicated to +provide a simpler (but robust) API. + +NMDevice has basically two timeouts (talking about IPv4, but it applies +similarly to IPv6): `ipv4.dhcp-timeout` and `ipv4.required-timeout`. They +control how long NMDevice is willing to try, before failing the activation +altogether. Note that with `ipv4.may-fail=yes`, we may very well never want to +fail the activation entirely, regardless how DHCP is doing. In that case we +want to stay up, but also constantly retrying whether we cannot get a lease and +recover. + +Currently, if `NMDhcpClient` signals a failure, then it's basically up to +`NMDevice` to schedule and retry. That is complicated, and we should move the +complexity out of `NMDevice`. + +`NMDhcpClient` should have a simpler API: + +- `nm_dhcp_manager_start_ip[46]()`: creates (and starts) a `NMDhcpClient` + instance. The difference is, this function tries really hard not to fail + to create an `NMDhcpClient`. There is no explicit `start()`, but note that the + instance must not emit any signals before the next maincontext iteration. That is, + it only will call back the user after a timeout/idle or some other IO event, which + happens during a future iteration of the maincontext. + +- `nm_dhcp_client_stop()`: when `NMDevice` is done with the `NMDhcpClient` + instance, it will stop it and throw it away. This method exists because + `NMDhcpClient` is a `GObject` and ref-counted. Thus, we don't want to rely on + the last unref to stop the instance, but have an explicit stop. After stop, the + instance is defunct and won't emit any signals anymore. The class does not need + to support restarting a stopped instance. If `NMDevice` wants to restart DHCP, it + should create a new one. `NMDevice` would only want to do that, if the parameters + change, hence a new instance is in order (and no need for the complexity of + restart in `NMDhcpClient`). + +- as already now, `NMDhcpClient` is not very configurable. You provide most + (all) parameters during `nm_dhcp_manager_start_ip[46]()`, and then it keeps + running until stop. + +- `NMDhcpClient` exposes a simple state to the user: + + 1. "no lease, but good". When starting, there is no lease, but we are + optimistic to get one. This is the inital state, but we can also get back to + this state after we had a lease (which might expire). + + 1. "has a lease". Here there is no need to distinguish whether the current + lease was the first we received, or whether this was an update. In this state, + the instance has a lease and we are good. + + 1. "no lease, but bad". `NMDhcpClient` tries really hard, and "bad" does not + mean that it gave up. It will keep retrying, it's just that there is little + hope of getting a new lease. This happens, when you try to run DHCP on a Layer3 + link (WireGuard). There is little hope to succeed, but `NMDhcpClient` + (theoretically) will retry and may recover from this. Another example is when + we fail to start dhclient because it's not installed. In that case, we are not + optimistic to recover, however `NMDhcpDhclient` will retry (with backoff + timeout) and might still recover from this. For most cases, `NMDevice` will + treat the no-lease cases the same, but in case of "bad" it might give up + earlier. + +When a lease expires, that does not necessarily mean that we are now in a bad +state. It might mean that the DHCP server is temporarily down, but we might +recover from that easily. "bad" really means, something is wrong on our side +which prevents us from getting a lease. Also, imagine `dhclient` dies (we would +try to restart, but assume that fails too), but we still have a valid lease, +then possibly `NMDhcpClient` should still pretend all is good and we still have +a lease until it expires. It may be we can recover before that happens. The +point of all of this, is to hide errors as much as possibly and automatically +recover. `NMDevice` will decide to tear down, if we didn't get a lease after +`ipv4.dhcp-timeout`. That's the main criteria, and it might not even +distinguish between "no lease, but good" and "no lease, but bad". + +- `NMDhcpClient` will also take care of the `ipv4.dhcp-timeout` grace period. + That timeout is provided during start, and starts ticking whenever there is + no lease. When it expires, a timeout signal gets emitted. That's it. This is + independent from the 3 states above, and only saves `NMDevice` from scheduling + this timer themselves. + This is NM_DHCP_CLIENT_NOTIFY_TYPE_NO_LEASE_TIMEOUT notification. + +- for nettools, `nm_dhcp_client_can_accept()` indicates that when we receive a + lease, we need to accept/decline it first. In that case, `NMDevice` +optionally does ACD first, then configures the IP address first and calls +`nm_dhcp_client_accept()`. In case of ACD conflict, it will call +`nm_dhcp_client_decline()` (which optimally causes `NMDhcpClient` to get a +different lease). With this, the above state "has a lease" has actually three +flavors: "has a lease but not yet ACD probed" and "has a lease but +accepted/declined" (but `NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED` gets only emitted +when we get the lease, not when we accept/decline it). With `dhclient`, when we +receive a lease, it means "has a lease but accepted" right away. + +- for IPv6 prefix delegation, there is also `needed_prefixes` and + `NM_DHCP_CLIENT_NOTIFY_TYPE_PREFIX_DELEGATED`. Currently `needed_prefixes` needs + to be specified during start (which simplifies things). Maybe `needed_prefixes` + should be changable at runtime. Otherwise, whether we have prefixes is similar + to whether we have a lease, and the simple 3 states apply. + +When NetworkManager quits, it may want to leave the interface up. In that case, +we still always want to stop the DHCP client, but possibly not deconfiguring +the interface. I don't think that this concerns `NMDhcpClient`, because `NMDhcpClient` +only provides the lease information and `NMDevice` is responsible to configure it. diff --git a/src/core/dhcp/nm-dhcp-client.c b/src/core/dhcp/nm-dhcp-client.c index f88c79c0be..6f71a44501 100644 --- a/src/core/dhcp/nm-dhcp-client.c +++ b/src/core/dhcp/nm-dhcp-client.c @@ -20,9 +20,13 @@ #include "NetworkManagerUtils.h" #include "nm-utils.h" +#include "nm-l3cfg.h" +#include "nm-l3-config-data.h" #include "nm-dhcp-utils.h" #include "nm-dhcp-options.h" #include "libnm-platform/nm-platform.h" +#include "nm-hostname-manager.h" +#include "libnm-systemd-shared/nm-sd-utils-shared.h" #include "nm-dhcp-client-logging.h" @@ -32,53 +36,19 @@ enum { SIGNAL_NOTIFY, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = {0}; -NM_GOBJECT_PROPERTIES_DEFINE(NMDhcpClient, - PROP_ADDR_FAMILY, - PROP_ANYCAST_ADDRESS, - PROP_FLAGS, - PROP_HWADDR, - PROP_BROADCAST_HWADDR, - PROP_IFACE, - PROP_IFINDEX, - PROP_MULTI_IDX, - PROP_ROUTE_METRIC, - PROP_ROUTE_TABLE, - PROP_TIMEOUT, - PROP_UUID, - PROP_IAID, - PROP_IAID_EXPLICIT, - PROP_HOSTNAME, - PROP_HOSTNAME_FLAGS, - PROP_MUD_URL, - PROP_VENDOR_CLASS_IDENTIFIER, - PROP_REJECT_SERVERS, ); +NM_GOBJECT_PROPERTIES_DEFINE(NMDhcpClient, PROP_CONFIG, ); typedef struct _NMDhcpClientPrivate { - NMDedupMultiIndex * multi_idx; - char * iface; - GBytes * hwaddr; - GBytes * bcast_hwaddr; - char * uuid; - GBytes * client_id; - char * hostname; - const char ** reject_servers; - char * mud_url; - char * anycast_address; - GBytes * vendor_class_identifier; - pid_t pid; - guint timeout_id; - guint watch_id; - int addr_family; - int ifindex; - guint32 route_table; - guint32 route_metric; - guint32 timeout; - guint32 iaid; - NMDhcpState state; - NMDhcpHostnameFlags hostname_flags; - NMDhcpClientFlags client_flags; - bool iaid_explicit : 1; - bool is_stopped : 1; + NMDhcpClientConfig config; + const NML3ConfigData *l3cd; + GSource * no_lease_timeout_source; + pid_t pid; + guint timeout_id; + guint watch_id; + NMDhcpState state; + bool iaid_explicit : 1; + bool is_stopped : 1; + GBytes * effective_client_id; } NMDhcpClientPrivate; G_DEFINE_ABSTRACT_TYPE(NMDhcpClient, nm_dhcp_client, G_TYPE_OBJECT) @@ -98,25 +68,6 @@ _emit_notify(NMDhcpClient *self, const NMDhcpClientNotifyData *notify_data) g_signal_emit(G_OBJECT(self), signals[SIGNAL_NOTIFY], 0, notify_data); } -static void -_emit_notify_state_changed(NMDhcpClient *self, - NMDhcpState dhcp_state, - NMIPConfig * ip_config, - GHashTable * options) -{ - const NMDhcpClientNotifyData notify_data = { - .notify_type = NM_DHCP_CLIENT_NOTIFY_TYPE_STATE_CHANGED, - .state_changed = - { - .dhcp_state = dhcp_state, - .ip_config = ip_config, - .options = options, - }, - }; - - _emit_notify(self, ¬ify_data); -} - /*****************************************************************************/ pid_t @@ -127,149 +78,24 @@ nm_dhcp_client_get_pid(NMDhcpClient *self) return NM_DHCP_CLIENT_GET_PRIVATE(self)->pid; } -NMDedupMultiIndex * -nm_dhcp_client_get_multi_idx(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), NULL); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->multi_idx; -} - -const char * -nm_dhcp_client_get_iface(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), NULL); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->iface; -} - -int -nm_dhcp_client_get_ifindex(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), -1); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->ifindex; -} - -int -nm_dhcp_client_get_addr_family(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), AF_UNSPEC); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->addr_family; -} - -const char * -nm_dhcp_client_get_uuid(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), NULL); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->uuid; -} - -GBytes * -nm_dhcp_client_get_hw_addr(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), NULL); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->hwaddr; -} - -GBytes * -nm_dhcp_client_get_broadcast_hw_addr(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), NULL); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->bcast_hwaddr; -} - -guint32 -nm_dhcp_client_get_route_table(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), RT_TABLE_MAIN); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->route_table; -} - -void -nm_dhcp_client_set_route_table(NMDhcpClient *self, guint32 route_table) -{ - NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - - if (route_table != priv->route_table) { - priv->route_table = route_table; - _notify(self, PROP_ROUTE_TABLE); - } -} - -guint32 -nm_dhcp_client_get_route_metric(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), G_MAXUINT32); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->route_metric; -} - -void -nm_dhcp_client_set_route_metric(NMDhcpClient *self, guint32 route_metric) -{ - NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - - if (route_metric != priv->route_metric) { - priv->route_metric = route_metric; - _notify(self, PROP_ROUTE_METRIC); - } -} - -guint32 -nm_dhcp_client_get_timeout(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), 0); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->timeout; -} - -guint32 -nm_dhcp_client_get_iaid(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), 0); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->iaid; -} - -gboolean -nm_dhcp_client_get_iaid_explicit(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), FALSE); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->iaid_explicit; -} - -GBytes * -nm_dhcp_client_get_client_id(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), NULL); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->client_id; -} - static void -_set_client_id(NMDhcpClient *self, GBytes *client_id, gboolean take) +_set_effective_client_id(NMDhcpClient *self, GBytes *client_id, gboolean take) { NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); nm_assert(!client_id || g_bytes_get_size(client_id) >= 2); - if (priv->client_id == client_id - || (priv->client_id && client_id && g_bytes_equal(priv->client_id, client_id))) { + if (priv->effective_client_id == client_id + || (priv->effective_client_id && client_id + && g_bytes_equal(priv->effective_client_id, client_id))) { if (take && client_id) g_bytes_unref(client_id); return; } - if (priv->client_id) - g_bytes_unref(priv->client_id); - priv->client_id = client_id; + if (priv->effective_client_id) + g_bytes_unref(priv->effective_client_id); + priv->effective_client_id = client_id; if (!take && client_id) g_bytes_ref(client_id); @@ -277,94 +103,20 @@ _set_client_id(NMDhcpClient *self, GBytes *client_id, gboolean take) gs_free char *s = NULL; _LOGT("%s: set %s", - nm_dhcp_client_get_addr_family(self) == AF_INET6 ? "duid" : "client-id", - priv->client_id ? (s = nm_dhcp_utils_duid_to_string(priv->client_id)) : "default"); + priv->config.addr_family == AF_INET6 ? "duid" : "client-id", + priv->effective_client_id + ? (s = nm_dhcp_utils_duid_to_string(priv->effective_client_id)) + : "default"); } } void -nm_dhcp_client_set_client_id(NMDhcpClient *self, GBytes *client_id) +nm_dhcp_client_set_effective_client_id(NMDhcpClient *self, GBytes *client_id) { g_return_if_fail(NM_IS_DHCP_CLIENT(self)); g_return_if_fail(!client_id || g_bytes_get_size(client_id) >= 2); - _set_client_id(self, client_id, FALSE); -} - -void -nm_dhcp_client_set_client_id_bin(NMDhcpClient *self, - guint8 type, - const guint8 *client_id, - gsize len) -{ - guint8 *buf; - GBytes *b; - - g_return_if_fail(NM_IS_DHCP_CLIENT(self)); - g_return_if_fail(client_id); - g_return_if_fail(len > 0); - - buf = g_malloc(len + 1); - buf[0] = type; - memcpy(buf + 1, client_id, len); - b = g_bytes_new_take(buf, len + 1); - _set_client_id(self, b, TRUE); -} - -const char * -nm_dhcp_client_get_anycast_address(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), NULL); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->anycast_address; -} - -const char * -nm_dhcp_client_get_hostname(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), NULL); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->hostname; -} - -NMDhcpHostnameFlags -nm_dhcp_client_get_hostname_flags(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), NM_DHCP_HOSTNAME_FLAG_NONE); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->hostname_flags; -} - -NMDhcpClientFlags -nm_dhcp_client_get_client_flags(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), NM_DHCP_CLIENT_FLAGS_NONE); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->client_flags; -} - -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; -} - -GBytes * -nm_dhcp_client_get_vendor_class_identifier(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), NULL); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->vendor_class_identifier; -} - -const char *const * -nm_dhcp_client_get_reject_servers(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), NULL); - - return (const char *const *) NM_DHCP_CLIENT_GET_PRIVATE(self)->reject_servers; + _set_effective_client_id(self, client_id, FALSE); } /*****************************************************************************/ @@ -457,78 +209,159 @@ stop(NMDhcpClient *self, gboolean release) if (priv->pid > 0) { /* Clean up the watch handler since we're explicitly killing the daemon */ watch_cleanup(self); - nm_dhcp_client_stop_pid(priv->pid, priv->iface); + nm_dhcp_client_stop_pid(priv->pid, priv->config.iface); } priv->pid = -1; } -void -nm_dhcp_client_set_state(NMDhcpClient *self, - NMDhcpState new_state, - NMIPConfig * ip_config, - GHashTable * options) +static gboolean +_no_lease_timeout(gpointer user_data) { + NMDhcpClient * self = user_data; NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + nm_clear_g_source_inst(&priv->no_lease_timeout_source); + + _emit_notify(self, + &((NMDhcpClientNotifyData){ + .notify_type = NM_DHCP_CLIENT_NOTIFY_TYPE_NO_LEASE_TIMEOUT, + })); + return G_SOURCE_CONTINUE; +} + +const NMDhcpClientConfig * +nm_dhcp_client_get_config(NMDhcpClient *self) +{ + NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + + return &priv->config; +} + +void +nm_dhcp_client_set_state(NMDhcpClient *self, NMDhcpState new_state, const NML3ConfigData *l3cd) +{ + NMDhcpClientPrivate * priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + GHashTable * options; + const int IS_IPv4 = NM_IS_IPv4(priv->config.addr_family); + nm_auto_unref_l3cd const NML3ConfigData *l3cd_merged = NULL; + + g_return_if_fail(NM_IS_DHCP_CLIENT(self)); + if (NM_IN_SET(new_state, NM_DHCP_STATE_BOUND, NM_DHCP_STATE_EXTENDED)) { - g_return_if_fail(NM_IS_IP_CONFIG_ADDR_FAMILY(ip_config, priv->addr_family)); - g_return_if_fail(options); - } else { - g_return_if_fail(!ip_config); - g_return_if_fail(!options); - } + g_return_if_fail(NM_IS_L3_CONFIG_DATA(l3cd)); + g_return_if_fail(nm_l3_config_data_get_dhcp_lease(l3cd, priv->config.addr_family)); + } else + g_return_if_fail(!l3cd); + + if (l3cd) + nm_l3_config_data_seal(l3cd); if (new_state >= NM_DHCP_STATE_BOUND) timeout_cleanup(self); if (new_state >= NM_DHCP_STATE_TIMEOUT) watch_cleanup(self); - /* The client may send same-state transitions for RENEW/REBIND events and - * the lease may have changed, so handle same-state transitions for the - * EXTENDED and BOUND states. Ignore same-state transitions for other - * events since the lease won't have changed and the state was already handled. - */ - if ((priv->state == new_state) - && !NM_IN_SET(new_state, NM_DHCP_STATE_BOUND, NM_DHCP_STATE_EXTENDED)) - return; + if (!IS_IPv4 && l3cd) { + if (nm_dhcp_utils_merge_new_dhcp6_lease(priv->l3cd, l3cd, &l3cd_merged)) { + l3cd = nm_l3_config_data_seal(l3cd_merged); + } + } - if (_LOGD_ENABLED()) { - gs_free const char **keys = NULL; - guint i, nkeys; + if (priv->l3cd == l3cd) + return; - keys = nm_strdict_get_keys(options, TRUE, &nkeys); - for (i = 0; i < nkeys; i++) { - _LOGD("option %-20s => '%s'", keys[i], (char *) g_hash_table_lookup(options, keys[i])); + if (l3cd) + nm_clear_g_source_inst(&priv->no_lease_timeout_source); + else { + /* FIXME(l3cfg:dhcp): we also need to start no_lease_timeout initially, if the + * instance starts without a previous_lease. */ + if (!priv->no_lease_timeout_source && priv->l3cd) { + if (priv->config.timeout == NM_DHCP_TIMEOUT_INFINITY) + priv->no_lease_timeout_source = g_source_ref(nm_g_source_sentinel_get(0)); + else { + priv->no_lease_timeout_source = + nm_g_timeout_add_source_seconds(priv->config.timeout, _no_lease_timeout, self); + } } } - if (_LOGT_ENABLED() && priv->addr_family == AF_INET6) { - gs_free char *event_id = NULL; + /* FIXME(l3cfg:dhcp): the API of NMDhcpClient is changing to expose a simpler API. + * The internals like NMDhcpState should not be exposed (or possibly dropped in large + * parts). */ + + nm_l3_config_data_reset(&priv->l3cd, l3cd); + + options = l3cd ? nm_dhcp_lease_get_options( + nm_l3_config_data_get_dhcp_lease(l3cd, priv->config.addr_family)) + : NULL; + + if (_LOGD_ENABLED()) { + if (options) { + gs_free const char **keys = NULL; + guint nkeys; + guint i; + + keys = nm_strdict_get_keys(options, TRUE, &nkeys); + for (i = 0; i < nkeys; i++) { + _LOGD("option %-20s => '%s'", + keys[i], + (char *) g_hash_table_lookup(options, keys[i])); + } + + if (priv->config.addr_family == AF_INET6) { + gs_free char *event_id = NULL; - event_id = nm_dhcp_utils_get_dhcp6_event_id(options); - if (event_id) - _LOGT("event-id: \"%s\"", event_id); + event_id = nm_dhcp_utils_get_dhcp6_event_id(options); + if (event_id) + _LOGT("event-id: \"%s\"", event_id); + } + } } if (_LOGI_ENABLED()) { const char *req_str = - NM_IS_IPv4(priv->addr_family) - ? nm_dhcp_option_request_string(AF_INET, NM_DHCP_OPTION_DHCP4_NM_IP_ADDRESS) - : nm_dhcp_option_request_string(AF_INET6, NM_DHCP_OPTION_DHCP6_NM_IP_ADDRESS); + IS_IPv4 ? nm_dhcp_option_request_string(AF_INET, NM_DHCP_OPTION_DHCP4_NM_IP_ADDRESS) + : nm_dhcp_option_request_string(AF_INET6, NM_DHCP_OPTION_DHCP6_NM_IP_ADDRESS); const char *addr = nm_g_hash_table_lookup(options, req_str); - _LOGI("state changed %s -> %s%s%s%s", - nm_dhcp_state_to_string(priv->state), - nm_dhcp_state_to_string(new_state), + _LOGI("state changed %s%s%s%s", + priv->l3cd ? "new lease" : "no lease", NM_PRINT_FMT_QUOTED(addr, ", address=", addr, "", "")); } - priv->state = new_state; + /* FIXME(l3cfg:dhcp:acd): NMDhcpClient must also do ACD. It needs acd_timeout_msec + * as a configuration parameter (in NMDhcpClientConfig). When ACD is enabled, + * when a new lease gets announced, it must first use NML3Cfg to run ACD on the + * interface (the previous lease -- if any -- will still be used at that point). + * If ACD fails, we call nm_dhcp_client_decline() and try to get a different + * lease. + * If ACD passes, we need to notify the new lease, and the user (NMDevice) may + * then configure the address. We need to watch the configured addresses (in NML3Cfg), + * and if the address appears there, we need to accept the lease. That is complicated + * but necessary, because we can only accept the lease after we configured the + * address. + * + * As a whole, ACD is transparent for the user (NMDevice). It's entirely managed + * by NMDhcpClient. Note that we do ACD through NML3Cfg, which centralizes IP handling + * for one interface, so for example if the same address happens to be configured + * as a static address (bypassing ACD), then NML3Cfg is aware of that and signals + * immediate success. */ - _emit_notify_state_changed(self, new_state, ip_config, options); + { + const NMDhcpClientNotifyData notify_data = { + .notify_type = NM_DHCP_CLIENT_NOTIFY_TYPE_LEASE_UPDATE, + .lease_update = + { + .l3cd = priv->l3cd, + }, + }; + + _emit_notify(self, ¬ify_data); + } } -static gboolean +/* FIXME(l3cfg:dhcp) */ +_nm_unused static gboolean transaction_timeout(gpointer user_data) { NMDhcpClient * self = NM_DHCP_CLIENT(user_data); @@ -536,7 +369,7 @@ transaction_timeout(gpointer user_data) priv->timeout_id = 0; _LOGW("request timed out"); - nm_dhcp_client_set_state(self, NM_DHCP_STATE_TIMEOUT, NULL, NULL); + nm_dhcp_client_set_state(self, NM_DHCP_STATE_TIMEOUT, NULL); return G_SOURCE_REMOVE; } @@ -554,7 +387,7 @@ daemon_watch_cb(GPid pid, int status, gpointer user_data) priv->pid = -1; - nm_dhcp_client_set_state(self, NM_DHCP_STATE_TERMINATED, NULL, NULL); + nm_dhcp_client_set_state(self, NM_DHCP_STATE_TERMINATED, NULL); } void @@ -566,10 +399,10 @@ nm_dhcp_client_start_timeout(NMDhcpClient *self) /* Set up a timeout on the transaction to kill it after the timeout */ - if (priv->timeout == NM_DHCP_TIMEOUT_INFINITY) - return; - - priv->timeout_id = g_timeout_add_seconds(priv->timeout, transaction_timeout, self); + /* FIXME(l3cfg:dhcp): no-lease-timeout is only for convenience for the user (NMDevice). + * Whatever the purpose of nm_dhcp_client_start_timeout() is, it is not the same timer. */ + return; + //priv->timeout_id = g_timeout_add_seconds(priv->no_lease_timeout, transaction_timeout, self); } void @@ -599,10 +432,7 @@ nm_dhcp_client_stop_watch_child(NMDhcpClient *self, pid_t pid) } gboolean -nm_dhcp_client_start_ip4(NMDhcpClient *self, - GBytes * client_id, - const char * last_ip4_address, - GError ** error) +nm_dhcp_client_start_ip4(NMDhcpClient *self, GError **error) { NMDhcpClientPrivate *priv; @@ -610,24 +440,37 @@ nm_dhcp_client_start_ip4(NMDhcpClient *self, priv = NM_DHCP_CLIENT_GET_PRIVATE(self); g_return_val_if_fail(priv->pid == -1, FALSE); - g_return_val_if_fail(priv->addr_family == AF_INET, FALSE); - g_return_val_if_fail(priv->uuid != NULL, FALSE); - - if (priv->timeout == NM_DHCP_TIMEOUT_INFINITY) + g_return_val_if_fail(priv->config.addr_family == AF_INET, FALSE); + g_return_val_if_fail(priv->config.uuid, FALSE); + + /* FIXME(l3cfg:dhcp:ipv6ll): for IPv6, NMDhcpClient needs to wait that + * a IPv6 LL address appears. The user (NMDevice) will start the generation + * of a LL address, but NMDhcpClient is already running and is just waiting. + * + * All the while, NM_DHCP_CLIENT_NO_LEASE_TIMEOUT is ticking. If the LL address + * does not appear in (e.g. 5 seconds), a NM_DHCP_CLIENT_NOTIFY_TYPE_IT_LOOKS_BAD signal + * can be emitted. */ + + if (priv->config.timeout == NM_DHCP_TIMEOUT_INFINITY) _LOGI("activation: beginning transaction (no timeout)"); else - _LOGI("activation: beginning transaction (timeout in %u seconds)", (guint) priv->timeout); + _LOGI("activation: beginning transaction (timeout in %u seconds)", + (guint) priv->config.timeout); - nm_dhcp_client_set_client_id(self, client_id); - - return NM_DHCP_CLIENT_GET_CLASS(self)->ip4_start(self, last_ip4_address, error); + return NM_DHCP_CLIENT_GET_CLASS(self)->ip4_start(self, error); } gboolean nm_dhcp_client_accept(NMDhcpClient *self, GError **error) { + NMDhcpClientPrivate *priv; + g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), FALSE); + priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + + g_return_val_if_fail(priv->l3cd, FALSE); + if (NM_DHCP_CLIENT_GET_CLASS(self)->accept) { return NM_DHCP_CLIENT_GET_CLASS(self)->accept(self, error); } @@ -652,8 +495,14 @@ nm_dhcp_client_can_accept(NMDhcpClient *self) gboolean nm_dhcp_client_decline(NMDhcpClient *self, const char *error_message, GError **error) { + NMDhcpClientPrivate *priv; + g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), FALSE); + priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + + g_return_val_if_fail(priv->l3cd, FALSE); + if (NM_DHCP_CLIENT_GET_CLASS(self)->decline) { return NM_DHCP_CLIENT_GET_CLASS(self)->decline(self, error_message, error); } @@ -668,42 +517,31 @@ get_duid(NMDhcpClient *self) } gboolean -nm_dhcp_client_start_ip6(NMDhcpClient * self, - GBytes * client_id, - gboolean enforce_duid, - const struct in6_addr * ll_addr, - NMSettingIP6ConfigPrivacy privacy, - guint needed_prefixes, - GError ** error) +nm_dhcp_client_start_ip6(NMDhcpClient *self, GError **error) { NMDhcpClientPrivate *priv; gs_unref_bytes GBytes *own_client_id = NULL; g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), FALSE); - g_return_val_if_fail(client_id, FALSE); - priv = NM_DHCP_CLIENT_GET_PRIVATE(self); g_return_val_if_fail(priv->pid == -1, FALSE); - g_return_val_if_fail(priv->addr_family == AF_INET6, FALSE); - g_return_val_if_fail(priv->uuid != NULL, FALSE); - g_return_val_if_fail(!priv->client_id, FALSE); + g_return_val_if_fail(priv->config.addr_family == AF_INET6, FALSE); + g_return_val_if_fail(priv->config.uuid, FALSE); + g_return_val_if_fail(!priv->effective_client_id, FALSE); - if (!enforce_duid) + if (!priv->config.v6.enforce_duid) own_client_id = NM_DHCP_CLIENT_GET_CLASS(self)->get_duid(self); - _set_client_id(self, own_client_id ?: client_id, FALSE); + _set_effective_client_id(self, own_client_id ?: priv->config.client_id, FALSE); - if (priv->timeout == NM_DHCP_TIMEOUT_INFINITY) + if (priv->config.timeout == NM_DHCP_TIMEOUT_INFINITY) _LOGI("activation: beginning transaction (no timeout)"); else - _LOGI("activation: beginning transaction (timeout in %u seconds)", (guint) priv->timeout); + _LOGI("activation: beginning transaction (timeout in %u seconds)", + (guint) priv->config.timeout); - return NM_DHCP_CLIENT_GET_CLASS(self)->ip6_start(self, - ll_addr, - privacy, - needed_prefixes, - error); + return NM_DHCP_CLIENT_GET_CLASS(self)->ip6_start(self, error); } void @@ -789,7 +627,7 @@ nm_dhcp_client_stop(NMDhcpClient *self, gboolean release) _LOGI("canceled DHCP transaction"); nm_assert(priv->pid == -1); - nm_dhcp_client_set_state(self, NM_DHCP_STATE_TERMINATED, NULL, NULL); + nm_dhcp_client_set_state(self, NM_DHCP_STATE_TERMINATED, NULL); } /*****************************************************************************/ @@ -921,12 +759,10 @@ nm_dhcp_client_handle_event(gpointer unused, const char * reason, NMDhcpClient *self) { - NMDhcpClientPrivate *priv; - guint32 old_state; - guint32 new_state; - gs_unref_hashtable GHashTable *str_options = NULL; - gs_unref_object NMIPConfig *ip_config = NULL; - NMPlatformIP6Address prefix = { + NMDhcpClientPrivate * priv; + guint32 new_state; + nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; + NMPlatformIP6Address prefix = { 0, }; @@ -938,25 +774,26 @@ nm_dhcp_client_handle_event(gpointer unused, priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - if (g_strcmp0(priv->iface, iface) != 0) + if (!nm_streq0(priv->config.iface, iface)) return FALSE; if (priv->pid != pid) return FALSE; - old_state = priv->state; - new_state = reason_to_state(self, priv->iface, reason); + new_state = reason_to_state(self, priv->config.iface, reason); + if (new_state == NM_DHCP_STATE_NOOP) + return TRUE; + _LOGD("DHCP state '%s' -> '%s' (reason: '%s')", - nm_dhcp_state_to_string(old_state), + nm_dhcp_state_to_string(priv->state), nm_dhcp_state_to_string(new_state), reason); - - if (new_state == NM_DHCP_STATE_NOOP) - return TRUE; + priv->state = new_state; if (NM_IN_SET(new_state, NM_DHCP_STATE_BOUND, NM_DHCP_STATE_EXTENDED)) { - GVariantIter iter; - const char * name; - GVariant * value; + gs_unref_hashtable GHashTable *str_options = NULL; + GVariantIter iter; + const char * name; + GVariant * value; /* Copy options */ str_options = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, g_free); @@ -968,25 +805,29 @@ nm_dhcp_client_handle_event(gpointer unused, /* Create the IP config */ if (g_hash_table_size(str_options) > 0) { - if (priv->addr_family == AF_INET) { - ip_config = NM_IP_CONFIG_CAST( - nm_dhcp_utils_ip4_config_from_options(nm_dhcp_client_get_multi_idx(self), - priv->ifindex, - priv->iface, - str_options, - priv->route_table, - priv->route_metric)); + if (priv->config.addr_family == AF_INET) { + l3cd = nm_dhcp_utils_ip4_config_from_options( + nm_l3cfg_get_multi_idx(priv->config.l3cfg), + nm_l3cfg_get_ifindex(priv->config.l3cfg), + priv->config.iface, + str_options); } else { - prefix = nm_dhcp_utils_ip6_prefix_from_options(str_options); - ip_config = NM_IP_CONFIG_CAST(nm_dhcp_utils_ip6_config_from_options( - nm_dhcp_client_get_multi_idx(self), - priv->ifindex, - priv->iface, + prefix = nm_dhcp_utils_ip6_prefix_from_options(str_options); + l3cd = nm_dhcp_utils_ip6_config_from_options( + nm_l3cfg_get_multi_idx(priv->config.l3cfg), + nm_l3cfg_get_ifindex(priv->config.l3cfg), + priv->config.iface, str_options, - NM_FLAGS_HAS(priv->client_flags, NM_DHCP_CLIENT_FLAGS_INFO_ONLY))); + priv->config.v6.info_only); } } else g_warn_if_reached(); + + if (l3cd) { + nm_l3_config_data_set_dhcp_lease_from_options(l3cd, + priv->config.addr_family, + g_steal_pointer(&str_options)); + } } if (!IN6_IS_ADDR_UNSPECIFIED(&prefix.address)) { @@ -994,17 +835,16 @@ nm_dhcp_client_handle_event(gpointer unused, * of the DHCP client instance. Instead, we just signal the prefix * to the device. */ nm_dhcp_client_emit_ipv6_prefix_delegated(self, &prefix); - } else { - /* Fail if no valid IP config was received */ - if (NM_IN_SET(new_state, NM_DHCP_STATE_BOUND, NM_DHCP_STATE_EXTENDED) && !ip_config) { - _LOGW("client bound but IP config not received"); - new_state = NM_DHCP_STATE_FAIL; - nm_clear_pointer(&str_options, g_hash_table_unref); - } + return TRUE; + } - nm_dhcp_client_set_state(self, new_state, ip_config, str_options); + /* Fail if no valid IP config was received */ + if (NM_IN_SET(new_state, NM_DHCP_STATE_BOUND, NM_DHCP_STATE_EXTENDED) && !l3cd) { + _LOGW("client bound but IP config not received"); + new_state = NM_DHCP_STATE_FAIL; } + nm_dhcp_client_set_state(self, new_state, l3cd); return TRUE; } @@ -1016,18 +856,18 @@ nm_dhcp_client_server_id_is_rejected(NMDhcpClient *self, gconstpointer addr) guint i; /* IPv6 not implemented yet */ - nm_assert(priv->addr_family == AF_INET); + nm_assert(priv->config.addr_family == AF_INET); - if (!priv->reject_servers || !priv->reject_servers[0]) + if (!priv->config.reject_servers || !priv->config.reject_servers[0]) return FALSE; - for (i = 0; priv->reject_servers[i]; i++) { + for (i = 0; priv->config.reject_servers[i]; i++) { in_addr_t r_addr; in_addr_t mask; int r_prefix; if (!nm_utils_parse_inaddr_prefix_bin(AF_INET, - priv->reject_servers[i], + priv->config.reject_servers[i], NULL, &r_addr, &r_prefix)) @@ -1040,146 +880,151 @@ nm_dhcp_client_server_id_is_rejected(NMDhcpClient *self, gconstpointer addr) return FALSE; } -/*****************************************************************************/ +static void +config_init(NMDhcpClientConfig *config, const NMDhcpClientConfig *src) +{ + *config = *src; + + g_object_ref(config->l3cfg); + + if (config->hwaddr) + g_bytes_ref(config->hwaddr); + if (config->bcast_hwaddr) + g_bytes_ref(config->bcast_hwaddr); + if (config->vendor_class_identifier) + g_bytes_ref(config->vendor_class_identifier); + if (config->client_id) + g_bytes_ref(config->client_id); + + config->iface = g_strdup(config->iface); + config->uuid = g_strdup(config->uuid); + config->anycast_address = g_strdup(config->anycast_address); + config->hostname = g_strdup(config->hostname); + config->mud_url = g_strdup(config->mud_url); + + config->reject_servers = (const char *const *) nm_strv_dup(config->reject_servers, -1, TRUE); + + if (config->addr_family == AF_INET) { + config->v4.last_address = g_strdup(config->v4.last_address); + } else if (config->addr_family == AF_INET6) { + config->v6.ll_addr = g_memdup(config->v6.ll_addr, sizeof(struct in6_addr)); + config->hwaddr = NULL; + config->bcast_hwaddr = NULL; + config->use_fqdn = TRUE; + } else { + nm_assert_not_reached(); + } + + if (!config->hostname && config->send_hostname) { + const char * hostname; + gs_free char *hostname_tmp = NULL; + + hostname = nm_hostname_manager_get_hostname(nm_hostname_manager_get()); + + if (nm_utils_is_specific_hostname(hostname)) { + if (config->addr_family == AF_INET) { + char *dot; + + hostname_tmp = g_strdup(hostname); + dot = strchr(hostname_tmp, '.'); + if (dot) + *dot = '\0'; + } + config->hostname = hostname_tmp ? g_steal_pointer(&hostname_tmp) : g_strdup(hostname); + } + } + + if (config->hostname) { + if ((config->use_fqdn && !nm_sd_dns_name_is_valid(config->hostname)) + || (!config->use_fqdn && !nm_sd_hostname_is_valid(config->hostname, FALSE))) { + nm_log_warn(LOGD_DHCP, + "dhcp%c: %s '%s' is invalid, will be ignored", + nm_utils_addr_family_to_char(config->addr_family), + config->use_fqdn ? "FQDN" : "hostname", + config->hostname); + nm_clear_g_free((gpointer *) &config->hostname); + } + } +} static void -get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +config_clear(NMDhcpClientConfig *config) { - NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(object); + g_object_unref(config->l3cfg); - switch (prop_id) { - case PROP_IFACE: - g_value_set_string(value, priv->iface); - break; - case PROP_IFINDEX: - g_value_set_int(value, priv->ifindex); - break; - case PROP_HWADDR: - g_value_set_boxed(value, priv->hwaddr); - break; - case PROP_BROADCAST_HWADDR: - g_value_set_boxed(value, priv->bcast_hwaddr); - break; - case PROP_ADDR_FAMILY: - g_value_set_int(value, priv->addr_family); - break; - case PROP_UUID: - g_value_set_string(value, priv->uuid); - break; - case PROP_IAID: - g_value_set_uint(value, priv->iaid); - break; - case PROP_IAID_EXPLICIT: - g_value_set_boolean(value, priv->iaid_explicit); - break; - case PROP_HOSTNAME: - g_value_set_string(value, priv->hostname); - break; - case PROP_ROUTE_METRIC: - g_value_set_uint(value, priv->route_metric); - break; - case PROP_ROUTE_TABLE: - g_value_set_uint(value, priv->route_table); - break; - case PROP_TIMEOUT: - g_value_set_uint(value, priv->timeout); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; + nm_clear_pointer(&config->hwaddr, g_bytes_unref); + nm_clear_pointer(&config->bcast_hwaddr, g_bytes_unref); + nm_clear_pointer(&config->vendor_class_identifier, g_bytes_unref); + nm_clear_pointer(&config->client_id, g_bytes_unref); + + nm_clear_g_free((gpointer *) &config->iface); + nm_clear_g_free((gpointer *) &config->uuid); + nm_clear_g_free((gpointer *) &config->anycast_address); + nm_clear_g_free((gpointer *) &config->hostname); + nm_clear_g_free((gpointer *) &config->mud_url); + + nm_clear_pointer((gpointer *) &config->reject_servers, g_strfreev); + + if (config->addr_family == AF_INET) { + nm_clear_g_free((gpointer *) &config->v4.last_address); + } else if (config->addr_family == AF_INET6) { + nm_clear_g_free((gpointer *) &config->v6.ll_addr); + } else { + nm_assert_not_reached(); } } +int +nm_dhcp_client_get_addr_family(NMDhcpClient *self) +{ + NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + + return priv->config.addr_family; +} + +const char * +nm_dhcp_client_get_iface(NMDhcpClient *self) +{ + NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + + return priv->config.iface; +} + +NMDedupMultiIndex * +nm_dhcp_client_get_multi_idx(NMDhcpClient *self) +{ + NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + + return nm_l3cfg_get_multi_idx(priv->config.l3cfg); +} + +int +nm_dhcp_client_get_ifindex(NMDhcpClient *self) +{ + NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + + return nm_l3cfg_get_ifindex(priv->config.l3cfg); +} + +GBytes * +nm_dhcp_client_get_effective_client_id(NMDhcpClient *self) +{ + NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + + return priv->effective_client_id; +} + +/*****************************************************************************/ + static void set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(object); - guint flags; switch (prop_id) { - case PROP_FLAGS: - /* construct-only */ - flags = g_value_get_uint(value); - nm_assert(!NM_FLAGS_ANY(flags, ~((guint) NM_DHCP_CLIENT_FLAGS_ALL))); - priv->client_flags = flags; - break; - case PROP_MULTI_IDX: - /* construct-only */ - priv->multi_idx = g_value_get_pointer(value); - if (!priv->multi_idx) - g_return_if_reached(); - nm_dedup_multi_index_ref(priv->multi_idx); - break; - case PROP_IFACE: - /* construct-only */ - priv->iface = g_value_dup_string(value); - g_return_if_fail(priv->iface); - nm_assert(nm_utils_ifname_valid_kernel(priv->iface, NULL)); - break; - case PROP_IFINDEX: - /* construct-only */ - priv->ifindex = g_value_get_int(value); - g_return_if_fail(priv->ifindex > 0); - break; - case PROP_HWADDR: - /* construct-only */ - priv->hwaddr = g_value_dup_boxed(value); - break; - case PROP_ANYCAST_ADDRESS: - /* construct-only */ - priv->anycast_address = g_value_dup_string(value); - break; - case PROP_BROADCAST_HWADDR: - /* construct-only */ - priv->bcast_hwaddr = g_value_dup_boxed(value); - break; - case PROP_ADDR_FAMILY: - /* construct-only */ - priv->addr_family = g_value_get_int(value); - if (!NM_IN_SET(priv->addr_family, AF_INET, AF_INET6)) - g_return_if_reached(); - break; - case PROP_UUID: - /* construct-only */ - priv->uuid = g_value_dup_string(value); - break; - case PROP_IAID: - /* construct-only */ - priv->iaid = g_value_get_uint(value); - break; - case PROP_IAID_EXPLICIT: - /* construct-only */ - priv->iaid_explicit = g_value_get_boolean(value); - break; - case PROP_HOSTNAME: - /* construct-only */ - priv->hostname = g_value_dup_string(value); - break; - case PROP_HOSTNAME_FLAGS: - /* 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; - case PROP_ROUTE_METRIC: - priv->route_metric = g_value_get_uint(value); - break; - case PROP_TIMEOUT: - /* construct-only */ - priv->timeout = g_value_get_uint(value); - break; - case PROP_VENDOR_CLASS_IDENTIFIER: - /* construct-only */ - priv->vendor_class_identifier = g_value_dup_boxed(value); - break; - case PROP_REJECT_SERVERS: + case PROP_CONFIG: /* construct-only */ - priv->reject_servers = nm_strv_dup_packed(g_value_get_boxed(value), -1); + config_init(&priv->config, g_value_get_pointer(value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); @@ -1200,53 +1045,31 @@ nm_dhcp_client_init(NMDhcpClient *self) priv->pid = -1; } -#if NM_MORE_ASSERTS static void -constructed(GObject *object) +dispose(GObject *object) { NMDhcpClient * self = NM_DHCP_CLIENT(object); NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - /* certain flags only make sense with certain address family. Assert - * for that. */ - if (NM_IS_IPv4(priv->addr_family)) - nm_assert(!NM_FLAGS_ANY(priv->client_flags, NM_DHCP_CLIENT_FLAGS_INFO_ONLY)); - else { - nm_assert(NM_FLAGS_HAS(priv->client_flags, NM_DHCP_CLIENT_FLAGS_USE_FQDN)); - nm_assert(!NM_FLAGS_ANY(priv->client_flags, NM_DHCP_CLIENT_FLAGS_REQUEST_BROADCAST)); - } + nm_dhcp_client_stop(self, FALSE); - nm_assert(!priv->anycast_address || nm_utils_hwaddr_valid(priv->anycast_address, ETH_ALEN)); + watch_cleanup(self); + timeout_cleanup(self); + + nm_clear_g_source_inst(&priv->no_lease_timeout_source); - G_OBJECT_CLASS(nm_dhcp_client_parent_class)->constructed(object); + G_OBJECT_CLASS(nm_dhcp_client_parent_class)->dispose(object); } -#endif static void -dispose(GObject *object) +finalize(GObject *object) { NMDhcpClient * self = NM_DHCP_CLIENT(object); NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - nm_dhcp_client_stop(self, FALSE); - - watch_cleanup(self); - timeout_cleanup(self); - - nm_clear_g_free(&priv->iface); - nm_clear_g_free(&priv->hostname); - nm_clear_g_free(&priv->uuid); - nm_clear_g_free(&priv->anycast_address); - nm_clear_g_free(&priv->mud_url); - nm_clear_g_free(&priv->reject_servers); - 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); - nm_clear_pointer(&priv->vendor_class_identifier, g_bytes_unref); + config_clear(&priv->config); - G_OBJECT_CLASS(nm_dhcp_client_parent_class)->dispose(object); - - priv->multi_idx = nm_dedup_multi_index_unref(priv->multi_idx); + G_OBJECT_CLASS(nm_dhcp_client_parent_class)->finalize(object); } static void @@ -1256,165 +1079,19 @@ nm_dhcp_client_class_init(NMDhcpClientClass *client_class) g_type_class_add_private(client_class, sizeof(NMDhcpClientPrivate)); -#if NM_MORE_ASSERTS - object_class->constructed = constructed; -#endif object_class->dispose = dispose; - object_class->get_property = get_property; + object_class->finalize = finalize; object_class->set_property = set_property; client_class->stop = stop; client_class->get_duid = get_duid; - obj_properties[PROP_MULTI_IDX] = - g_param_spec_pointer(NM_DHCP_CLIENT_MULTI_IDX, + obj_properties[PROP_CONFIG] = + g_param_spec_pointer(NM_DHCP_CLIENT_CONFIG, "", "", G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_IFACE] = - g_param_spec_string(NM_DHCP_CLIENT_INTERFACE, - "", - "", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_IFINDEX] = - g_param_spec_int(NM_DHCP_CLIENT_IFINDEX, - "", - "", - -1, - G_MAXINT, - -1, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_HWADDR] = - g_param_spec_boxed(NM_DHCP_CLIENT_HWADDR, - "", - "", - G_TYPE_BYTES, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_BROADCAST_HWADDR] = - g_param_spec_boxed(NM_DHCP_CLIENT_BROADCAST_HWADDR, - "", - "", - G_TYPE_BYTES, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_ADDR_FAMILY] = - g_param_spec_int(NM_DHCP_CLIENT_ADDR_FAMILY, - "", - "", - 0, - G_MAXINT, - AF_UNSPEC, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_ANYCAST_ADDRESS] = - g_param_spec_string(NM_DHCP_CLIENT_ANYCAST_ADDRESS, - "", - "", - NULL, - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_UUID] = - g_param_spec_string(NM_DHCP_CLIENT_UUID, - "", - "", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_IAID] = - g_param_spec_uint(NM_DHCP_CLIENT_IAID, - "", - "", - 0, - G_MAXUINT32, - 0, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_IAID_EXPLICIT] = - g_param_spec_boolean(NM_DHCP_CLIENT_IAID_EXPLICIT, - "", - "", - FALSE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_HOSTNAME] = - g_param_spec_string(NM_DHCP_CLIENT_HOSTNAME, - "", - "", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_HOSTNAME_FLAGS] = - g_param_spec_uint(NM_DHCP_CLIENT_HOSTNAME_FLAGS, - "", - "", - 0, - G_MAXUINT32, - NM_DHCP_HOSTNAME_FLAG_NONE, - 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, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_ROUTE_METRIC] = - g_param_spec_uint(NM_DHCP_CLIENT_ROUTE_METRIC, - "", - "", - 0, - G_MAXUINT32, - 0, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - - G_STATIC_ASSERT_EXPR(G_MAXINT32 == NM_DHCP_TIMEOUT_INFINITY); - obj_properties[PROP_TIMEOUT] = - g_param_spec_uint(NM_DHCP_CLIENT_TIMEOUT, - "", - "", - 1, - G_MAXINT32, - NM_DHCP_TIMEOUT_DEFAULT, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_FLAGS] = - g_param_spec_uint(NM_DHCP_CLIENT_FLAGS, - "", - "", - 0, - G_MAXUINT32, - 0, - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_VENDOR_CLASS_IDENTIFIER] = - g_param_spec_boxed(NM_DHCP_CLIENT_VENDOR_CLASS_IDENTIFIER, - "", - "", - G_TYPE_BYTES, - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_REJECT_SERVERS] = - g_param_spec_boxed(NM_DHCP_CLIENT_REJECT_SERVERS, - "", - "", - G_TYPE_STRV, - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); signals[SIGNAL_NOTIFY] = diff --git a/src/core/dhcp/nm-dhcp-client.h b/src/core/dhcp/nm-dhcp-client.h index 2e7e021650..372acc752c 100644 --- a/src/core/dhcp/nm-dhcp-client.h +++ b/src/core/dhcp/nm-dhcp-client.h @@ -8,8 +8,6 @@ #include "nm-setting-ip4-config.h" #include "nm-setting-ip6-config.h" -#include "nm-ip4-config.h" -#include "nm-ip6-config.h" #include "nm-dhcp-utils.h" #define NM_DHCP_TIMEOUT_DEFAULT ((guint32) 45) /* default DHCP timeout, in seconds */ @@ -24,25 +22,7 @@ #define NM_DHCP_CLIENT_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DHCP_CLIENT, NMDhcpClientClass)) -#define NM_DHCP_CLIENT_ADDR_FAMILY "addr-family" -#define NM_DHCP_CLIENT_ANYCAST_ADDRESS "anycast-address" -#define NM_DHCP_CLIENT_FLAGS "flags" -#define NM_DHCP_CLIENT_HWADDR "hwaddr" -#define NM_DHCP_CLIENT_BROADCAST_HWADDR "broadcast-hwaddr" -#define NM_DHCP_CLIENT_IFINDEX "ifindex" -#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" -#define NM_DHCP_CLIENT_UUID "uuid" -#define NM_DHCP_CLIENT_IAID "iaid" -#define NM_DHCP_CLIENT_IAID_EXPLICIT "iaid-explicit" -#define NM_DHCP_CLIENT_HOSTNAME_FLAGS "hostname-flags" -#define NM_DHCP_CLIENT_VENDOR_CLASS_IDENTIFIER "vendor-class-identifier" -#define NM_DHCP_CLIENT_REJECT_SERVERS "reject-servers" +#define NM_DHCP_CLIENT_CONFIG "config" #define NM_DHCP_CLIENT_NOTIFY "dhcp-notify" @@ -59,7 +39,27 @@ typedef enum { } NMDhcpState; typedef enum _nm_packed { - NM_DHCP_CLIENT_NOTIFY_TYPE_STATE_CHANGED, + NM_DHCP_CLIENT_NOTIFY_TYPE_LEASE_UPDATE, + + /* When NM_DHCP_CLIENT_NO_LEASE_TIMEOUT expired and the state + * switched from NM_DHCP_CLIENT_STATE_NO_LEASE to + * NM_DHCP_CLIENT_STATE_NO_LEASE_WITH_TIMEOUT. */ + NM_DHCP_CLIENT_NOTIFY_TYPE_NO_LEASE_TIMEOUT, + + /* NMDhcpClient will indefinitely try to get/renew the lease. + * As such, it's never officially in a non-recoverable state. + * However, there are cases when it really looks like we won't + * be able to get a lease. For example, if the underlying interface + * is layer 3 only, if we have no IPv6 link local address for a prolonged + * time, or if dhclient is not installed. + * But even these cases are potentially recoverable. This is only + * a hint to the user (which they might ignore). + * + * In particular, NM_DHCP_CLIENT_NOTIFY_TYPE_NO_LEASE_TIMEOUT might mean + * that the DHCP is currently not running, but that could change + * at any moment and from client's side, it does not look bad. */ + NM_DHCP_CLIENT_NOTIFY_TYPE_IT_LOOKS_BAD, + NM_DHCP_CLIENT_NOTIFY_TYPE_PREFIX_DELEGATED, } NMDhcpClientNotifyType; @@ -67,18 +67,126 @@ typedef struct { NMDhcpClientNotifyType notify_type; union { struct { - NMIPConfig *ip_config; - GHashTable *options; - NMDhcpState dhcp_state; - } state_changed; + /* This is either the new lease information we just received, + * or NULL (if a previous lease timed out). It can also be the + * previous lease, that was injected. */ + const NML3ConfigData *l3cd; + } lease_update; struct { const NMPlatformIP6Address *prefix; } prefix_delegated; + struct { + const char *reason; + } it_looks_bad; }; } NMDhcpClientNotifyData; const char *nm_dhcp_state_to_string(NMDhcpState state); +/* FIXME(l3cfg:dhcp:config): nm_dhcp_manager_start_ip[46]() has a gazillion of parameters, + * those get passed on as CONSTRUCT_ONLY properties to the NMDhcpClient. Drop + * all these parameters, and let the caller provide one NMDhcpClientConfig + * instance. There will be only one GObject property (NM_DHCP_CLIENT_CONFIG), + * which is CONSTRUCT_ONLY and takes a (mandatory) G_TYPE_POINTER for the + * configuration. + * + * Since NMDhcpClientConfig has an addr_family, we also don't need separate + * nm_dhcp_manager_start_ip[46]() methods. */ +typedef struct { + int addr_family; + + /* The NML3Cfg instance is the manager object for the ifindex on which + * NMDhcpClient is supposed to run. */ + NML3Cfg *l3cfg; + + /* FIXME(l3cfg:dhcp:previous-lease): most parameters of NMDhcpClient are immutable, + * so to change them (during reapply), we need to create and start + * a new NMDhcpClient instance. + * + * However, while the restart happens, we want to stick to the previous + * lease (if any). Allow the caller to provide such a previous lease, + * and if present, the instance starts by pretending that it just received + * this lease, before really starting. */ + const NML3ConfigData *previous_lease; + + const char *iface; + + /* The hardware address */ + GBytes *hwaddr; + + /* The broadcast hardware address */ + GBytes *bcast_hwaddr; + + /* Timeout in seconds before reporting failure */ + guint32 timeout; + + /* Flags for the hostname and FQDN DHCP options */ + NMDhcpHostnameFlags hostname_flags; + + /* The UUID of the connection. Used mainly to build + * lease file names. */ + const char *uuid; + + /* Set to reduce the number of broadcast packets when the + * anycast hardware address of the DHCP service is known. */ + const char *anycast_address; + + /* The hostname or FQDN to send. */ + const char *hostname; + + /* The Manufacturer Usage Description (RFC 8520) URL to send */ + const char *mud_url; + + /* The value for the Vendor Class Identifier option */ + GBytes *vendor_class_identifier; + + /* A list of servers from which offers should be rejected */ + const char *const *reject_servers; + + /* The client identifier (DHCPv4) or DUID (DHCPv6) to send */ + GBytes *client_id; + + /* Whether to send the hostname or FQDN option */ + bool send_hostname : 1; + + /* Whether to send the hostname as HOSTNAME option or FQDN. + * For DHCPv6 this is always TRUE. */ + bool use_fqdn : 1; + + union { + struct { + /* Set BOOTP broadcast flag in request packets, so that servers + * will always broadcast replies. */ + bool request_broadcast : 1; + + /* The address from the previous lease */ + const char *last_address; + } v4; + struct { + /* The link-local IPv6 address for UDP socket bind() */ + const struct in6_addr *ll_addr; + + /* If set, the DUID from the connection is used; otherwise + * the one from an existing lease is used. */ + gboolean enforce_duid; + + /* The IAID to use */ + guint32 iaid; + + /* Whether the IAID was explicitly set in the connection or + * as global default */ + gboolean iaid_explicit; + + /* Number to prefixes (IA_PD) to request */ + guint needed_prefixes; + + /* Use Information-request to get stateless configuration + * parameters (don't request a IA_NA) */ + bool info_only : 1; + } v6; + }; +} NMDhcpClientConfig; + struct _NMDhcpClientPrivate; typedef struct { @@ -100,17 +208,13 @@ typedef enum _nm_packed { typedef struct { GObjectClass parent; - gboolean (*ip4_start)(NMDhcpClient *self, const char *last_ip4_address, GError **error); + gboolean (*ip4_start)(NMDhcpClient *self, GError **error); gboolean (*accept)(NMDhcpClient *self, GError **error); gboolean (*decline)(NMDhcpClient *self, const char *error_message, GError **error); - gboolean (*ip6_start)(NMDhcpClient * self, - const struct in6_addr * ll_addr, - NMSettingIP6ConfigPrivacy privacy, - guint needed_prefixes, - GError ** error); + gboolean (*ip6_start)(NMDhcpClient *self, GError **error); void (*stop)(NMDhcpClient *self, gboolean release); @@ -128,64 +232,25 @@ typedef struct { GType nm_dhcp_client_get_type(void); -struct _NMDedupMultiIndex *nm_dhcp_client_get_multi_idx(NMDhcpClient *self); - -pid_t nm_dhcp_client_get_pid(NMDhcpClient *self); - -int nm_dhcp_client_get_addr_family(NMDhcpClient *self); - -const char *nm_dhcp_client_get_iface(NMDhcpClient *self); - -int nm_dhcp_client_get_ifindex(NMDhcpClient *self); - -const char *nm_dhcp_client_get_uuid(NMDhcpClient *self); - -GBytes *nm_dhcp_client_get_duid(NMDhcpClient *self); - -GBytes *nm_dhcp_client_get_hw_addr(NMDhcpClient *self); - -GBytes *nm_dhcp_client_get_broadcast_hw_addr(NMDhcpClient *self); - -const char *nm_dhcp_client_get_anycast_address(NMDhcpClient *self); - -guint32 nm_dhcp_client_get_route_table(NMDhcpClient *self); - -void nm_dhcp_client_set_route_table(NMDhcpClient *self, guint32 route_table); +gboolean nm_dhcp_client_start_ip4(NMDhcpClient *self, GError **error); +gboolean nm_dhcp_client_start_ip6(NMDhcpClient *self, GError **error); -guint32 nm_dhcp_client_get_route_metric(NMDhcpClient *self); +const NMDhcpClientConfig *nm_dhcp_client_get_config(NMDhcpClient *self); -void nm_dhcp_client_set_route_metric(NMDhcpClient *self, guint32 route_metric); - -guint32 nm_dhcp_client_get_timeout(NMDhcpClient *self); - -guint32 nm_dhcp_client_get_iaid(NMDhcpClient *self); - -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); -const char *const *nm_dhcp_client_get_reject_servers(NMDhcpClient *self); - -NMDhcpHostnameFlags nm_dhcp_client_get_hostname_flags(NMDhcpClient *self); - -NMDhcpClientFlags nm_dhcp_client_get_client_flags(NMDhcpClient *self); - -GBytes *nm_dhcp_client_get_vendor_class_identifier(NMDhcpClient *self); - -gboolean nm_dhcp_client_start_ip4(NMDhcpClient *self, - GBytes * client_id, - const char * last_ip4_address, - GError ** error); +pid_t nm_dhcp_client_get_pid(NMDhcpClient *self); -gboolean nm_dhcp_client_start_ip6(NMDhcpClient * self, - GBytes * client_id, - gboolean enforce_duid, - const struct in6_addr * ll_addr, - NMSettingIP6ConfigPrivacy privacy, - guint needed_prefixes, - GError ** error); +static inline const NML3ConfigData * +nm_dhcp_client_get_lease(NMDhcpClient *self) +{ + /* FIXME(l3cfg:dhcp:previous-lease): this function returns the currently + * valid, exposed lease. + * + * Note that NMDhcpClient should accept as construct argument a *previous* lease, + * and (if that lease is still valid), pretend that it's good to use. The point is + * so that during reapply we keep using the current address, until a new lease + * was received. */ + return NULL; +} gboolean nm_dhcp_client_accept(NMDhcpClient *self, GError **error); gboolean nm_dhcp_client_can_accept(NMDhcpClient *self); @@ -205,10 +270,8 @@ void nm_dhcp_client_watch_child(NMDhcpClient *self, pid_t pid); void nm_dhcp_client_stop_watch_child(NMDhcpClient *self, pid_t pid); -void nm_dhcp_client_set_state(NMDhcpClient *self, - NMDhcpState new_state, - NMIPConfig * ip_config, - GHashTable * options); /* str:str hash */ +void +nm_dhcp_client_set_state(NMDhcpClient *self, NMDhcpState new_state, const NML3ConfigData *l3cd); gboolean nm_dhcp_client_handle_event(gpointer unused, const char * iface, @@ -217,17 +280,19 @@ gboolean nm_dhcp_client_handle_event(gpointer unused, const char * reason, NMDhcpClient *self); -void nm_dhcp_client_set_client_id(NMDhcpClient *self, GBytes *client_id); -void nm_dhcp_client_set_client_id_bin(NMDhcpClient *self, - guint8 type, - const guint8 *client_id, - gsize len); - void nm_dhcp_client_emit_ipv6_prefix_delegated(NMDhcpClient * self, const NMPlatformIP6Address *prefix); gboolean nm_dhcp_client_server_id_is_rejected(NMDhcpClient *self, gconstpointer addr); +int nm_dhcp_client_get_addr_family(NMDhcpClient *self); +const char * nm_dhcp_client_get_iface(NMDhcpClient *self); +NMDedupMultiIndex *nm_dhcp_client_get_multi_idx(NMDhcpClient *self); +int nm_dhcp_client_get_ifindex(NMDhcpClient *self); + +void nm_dhcp_client_set_effective_client_id(NMDhcpClient *self, GBytes *client_id); +GBytes *nm_dhcp_client_get_effective_client_id(NMDhcpClient *self); + /***************************************************************************** * Client data *****************************************************************************/ diff --git a/src/core/dhcp/nm-dhcp-dhclient-utils.c b/src/core/dhcp/nm-dhcp-dhclient-utils.c index 341ac7b2fa..60cb46e507 100644 --- a/src/core/dhcp/nm-dhcp-dhclient-utils.c +++ b/src/core/dhcp/nm-dhcp-dhclient-utils.c @@ -15,7 +15,6 @@ #include "libnm-glib-aux/nm-dedup-multi.h" #include "nm-dhcp-utils.h" -#include "nm-ip4-config.h" #include "nm-utils.h" #include "libnm-platform/nm-platform.h" #include "NetworkManagerUtils.h" diff --git a/src/core/dhcp/nm-dhcp-dhclient.c b/src/core/dhcp/nm-dhcp-dhclient.c index 970a51f5dd..9406ae7005 100644 --- a/src/core/dhcp/nm-dhcp-dhclient.c +++ b/src/core/dhcp/nm-dhcp-dhclient.c @@ -333,26 +333,28 @@ dhclient_start(NMDhcpClient *client, const char * mode_opt, gboolean release, pid_t * out_pid, - int prefixes, GError ** error) { NMDhcpDhclient * self = NM_DHCP_DHCLIENT(client); NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE(self); gs_unref_ptrarray GPtrArray *argv = NULL; pid_t pid; - gs_free_error GError *local = NULL; - const char * iface; - const char * uuid; - const char * system_bus_address; - const char * dhclient_path; - char * binary_name; - gs_free char * cmd_str = NULL; - gs_free char * pid_file = NULL; - gs_free char * system_bus_address_env = NULL; - gs_free char * preferred_leasefile_path = NULL; - const int addr_family = nm_dhcp_client_get_addr_family(client); + gs_free_error GError * local = NULL; + const char * iface; + const char * uuid; + const char * system_bus_address; + const char * dhclient_path; + char * binary_name; + gs_free char * cmd_str = NULL; + gs_free char * pid_file = NULL; + gs_free char * system_bus_address_env = NULL; + gs_free char * preferred_leasefile_path = NULL; + int addr_family; + const NMDhcpClientConfig *client_config; g_return_val_if_fail(!priv->pid_file, FALSE); + client_config = nm_dhcp_client_get_config(client); + addr_family = client_config->addr_family; NM_SET_OUT(out_pid, 0); @@ -362,8 +364,8 @@ dhclient_start(NMDhcpClient *client, return FALSE; } - iface = nm_dhcp_client_get_iface(client); - uuid = nm_dhcp_client_get_uuid(client); + iface = client_config->iface; + uuid = client_config->uuid; pid_file = g_strdup_printf(NMRUNDIR "/dhclient%s-%s.pid", _addr_family_to_path_part(addr_family), @@ -409,9 +411,7 @@ dhclient_start(NMDhcpClient *client, /* Save the DUID to the leasefile dhclient will actually use */ if (addr_family == AF_INET6) { - if (!nm_dhcp_dhclient_save_duid(priv->lease_file, - nm_dhcp_client_get_client_id(client), - &local)) { + if (!nm_dhcp_dhclient_save_duid(priv->lease_file, client_config->client_id, &local)) { nm_utils_error_set(error, NM_UTILS_ERROR_UNKNOWN, "failed to save DUID to '%s': %s", @@ -434,13 +434,13 @@ dhclient_start(NMDhcpClient *client, if (release) g_ptr_array_add(argv, (gpointer) "-r"); - if (!release - && NM_FLAGS_HAS(nm_dhcp_client_get_client_flags(NM_DHCP_CLIENT(self)), - NM_DHCP_CLIENT_FLAGS_REQUEST_BROADCAST)) { + if (!release && client_config->addr_family == AF_INET && client_config->v4.request_broadcast) { g_ptr_array_add(argv, (gpointer) "-B"); } if (addr_family == AF_INET6) { + guint prefixes = client_config->v6.needed_prefixes; + g_ptr_array_add(argv, (gpointer) "-6"); if (prefixes > 0 && nm_streq0(mode_opt, "-S")) { @@ -513,29 +513,28 @@ dhclient_start(NMDhcpClient *client, } static gboolean -ip4_start(NMDhcpClient *client, const char *last_ip4_address, GError **error) +ip4_start(NMDhcpClient *client, GError **error) { - NMDhcpDhclient * self = NM_DHCP_DHCLIENT(client); - NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE(self); - GBytes * client_id; - gs_unref_bytes GBytes *new_client_id = NULL; - - client_id = nm_dhcp_client_get_client_id(client); - - priv->conf_file = create_dhclient_config( - self, - AF_INET, - nm_dhcp_client_get_iface(client), - nm_dhcp_client_get_uuid(client), - client_id, - nm_dhcp_client_get_anycast_address(client), - nm_dhcp_client_get_hostname(client), - nm_dhcp_client_get_timeout(client), - NM_FLAGS_HAS(nm_dhcp_client_get_client_flags(client), NM_DHCP_CLIENT_FLAGS_USE_FQDN), - nm_dhcp_client_get_hostname_flags(client), - nm_dhcp_client_get_mud_url(client), - nm_dhcp_client_get_reject_servers(client), - &new_client_id); + NMDhcpDhclient * self = NM_DHCP_DHCLIENT(client); + NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE(self); + gs_unref_bytes GBytes * new_client_id = NULL; + const NMDhcpClientConfig *client_config; + + client_config = nm_dhcp_client_get_config(client); + + priv->conf_file = create_dhclient_config(self, + AF_INET, + client_config->iface, + client_config->uuid, + client_config->client_id, + client_config->anycast_address, + client_config->hostname, + client_config->timeout, + client_config->use_fqdn, + client_config->hostname_flags, + client_config->mud_url, + client_config->reject_servers, + &new_client_id); if (!priv->conf_file) { nm_utils_error_set_literal(error, NM_UTILS_ERROR_UNKNOWN, @@ -544,36 +543,35 @@ ip4_start(NMDhcpClient *client, const char *last_ip4_address, GError **error) } if (new_client_id) { - nm_assert(!client_id); - nm_dhcp_client_set_client_id(client, new_client_id); + nm_assert(!client_config->client_id); + nm_dhcp_client_set_effective_client_id(client, new_client_id); } - return dhclient_start(client, NULL, FALSE, NULL, 0, error); + return dhclient_start(client, NULL, FALSE, NULL, error); } static gboolean -ip6_start(NMDhcpClient * client, - const struct in6_addr * ll_addr, - NMSettingIP6ConfigPrivacy privacy, - guint needed_prefixes, - GError ** error) +ip6_start(NMDhcpClient *client, GError **error) { - NMDhcpDhclient * self = NM_DHCP_DHCLIENT(client); - NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE(self); + NMDhcpDhclient * self = NM_DHCP_DHCLIENT(client); + NMDhcpDhclientPrivate * priv = NM_DHCP_DHCLIENT_GET_PRIVATE(self); + const NMDhcpClientConfig *config; - if (nm_dhcp_client_get_iaid_explicit(client)) + config = nm_dhcp_client_get_config(client); + + if (config->v6.iaid_explicit) _LOGW("dhclient does not support specifying an IAID for DHCPv6, it will be ignored"); priv->conf_file = create_dhclient_config(self, AF_INET6, - nm_dhcp_client_get_iface(client), - nm_dhcp_client_get_uuid(client), + config->iface, + config->uuid, NULL, - nm_dhcp_client_get_anycast_address(client), - nm_dhcp_client_get_hostname(client), - nm_dhcp_client_get_timeout(client), + config->anycast_address, + config->hostname, + config->timeout, TRUE, - nm_dhcp_client_get_hostname_flags(client), - nm_dhcp_client_get_mud_url(client), + config->hostname_flags, + config->mud_url, NULL, NULL); if (!priv->conf_file) { @@ -583,15 +581,7 @@ ip6_start(NMDhcpClient * client, return FALSE; } - return dhclient_start(client, - NM_FLAGS_HAS(nm_dhcp_client_get_client_flags(NM_DHCP_CLIENT(self)), - NM_DHCP_CLIENT_FLAGS_INFO_ONLY) - ? "-S" - : "-N", - FALSE, - NULL, - needed_prefixes, - error); + return dhclient_start(client, config->v6.needed_prefixes ? "-S" : "-N", FALSE, NULL, error); } static void @@ -625,7 +615,7 @@ stop(NMDhcpClient *client, gboolean release) if (release) { pid_t rpid = -1; - if (dhclient_start(client, NULL, TRUE, &rpid, 0, NULL)) { + if (dhclient_start(client, NULL, TRUE, &rpid, NULL)) { /* Wait a few seconds for the release to happen */ nm_dhcp_client_stop_pid(rpid, nm_dhcp_client_get_iface(client)); } @@ -635,16 +625,19 @@ stop(NMDhcpClient *client, gboolean release) static GBytes * get_duid(NMDhcpClient *client) { - NMDhcpDhclient * self = NM_DHCP_DHCLIENT(client); - NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE(self); - GBytes * duid = NULL; - gs_free char * leasefile = NULL; - GError * error = NULL; + NMDhcpDhclient * self = NM_DHCP_DHCLIENT(client); + NMDhcpDhclientPrivate * priv = NM_DHCP_DHCLIENT_GET_PRIVATE(self); + const NMDhcpClientConfig *client_config; + GBytes * duid = NULL; + gs_free char * leasefile = NULL; + GError * error = NULL; + + client_config = nm_dhcp_client_get_config(client); /* Look in interface-specific leasefile first for backwards compat */ leasefile = get_dhclient_leasefile(AF_INET6, nm_dhcp_client_get_iface(client), - nm_dhcp_client_get_uuid(client), + client_config->uuid, NULL); if (leasefile) { _LOGD("looking for DUID in '%s'", leasefile); diff --git a/src/core/dhcp/nm-dhcp-dhcpcanon.c b/src/core/dhcp/nm-dhcp-dhcpcanon.c index f993ffb940..ed29b85cd0 100644 --- a/src/core/dhcp/nm-dhcp-dhcpcanon.c +++ b/src/core/dhcp/nm-dhcp-dhcpcanon.c @@ -160,7 +160,7 @@ dhcpcanon_start(NMDhcpClient *client, } static gboolean -ip4_start(NMDhcpClient *client, const char *last_ip4_address, GError **error) +ip4_start(NMDhcpClient *client, GError **error) { return dhcpcanon_start(client, NULL, NULL, FALSE, NULL, 0, error); } diff --git a/src/core/dhcp/nm-dhcp-dhcpcd.c b/src/core/dhcp/nm-dhcp-dhcpcd.c index 7522156bef..0a6a91b743 100644 --- a/src/core/dhcp/nm-dhcp-dhcpcd.c +++ b/src/core/dhcp/nm-dhcp-dhcpcd.c @@ -64,21 +64,19 @@ nm_dhcp_dhcpcd_get_path(void) } static gboolean -ip4_start(NMDhcpClient *client, const char *last_ip4_address, GError **error) +ip4_start(NMDhcpClient *client, GError **error) { - NMDhcpDhcpcd * self = NM_DHCP_DHCPCD(client); + NMDhcpDhcpcd * self = NM_DHCP_DHCPCD(client); + const NMDhcpClientConfig *client_config; gs_unref_ptrarray GPtrArray *argv = NULL; pid_t pid; GError * local; gs_free char * cmd_str = NULL; - const char * iface; const char * dhcpcd_path; - const char * hostname; pid = nm_dhcp_client_get_pid(client); g_return_val_if_fail(pid == -1, FALSE); - - iface = nm_dhcp_client_get_iface(client); + client_config = nm_dhcp_client_get_config(client); dhcpcd_path = nm_dhcp_dhcpcd_get_path(); if (!dhcpcd_path) { @@ -115,21 +113,19 @@ ip4_start(NMDhcpClient *client, const char *last_ip4_address, GError **error) */ g_ptr_array_add(argv, (gpointer) "-4"); - hostname = nm_dhcp_client_get_hostname(client); - - if (hostname) { - if (NM_FLAGS_HAS(nm_dhcp_client_get_client_flags(client), NM_DHCP_CLIENT_FLAGS_USE_FQDN)) { + if (client_config->hostname) { + if (client_config->use_fqdn) { g_ptr_array_add(argv, (gpointer) "-h"); - g_ptr_array_add(argv, (gpointer) hostname); + g_ptr_array_add(argv, (gpointer) client_config->hostname); g_ptr_array_add(argv, (gpointer) "-F"); g_ptr_array_add(argv, (gpointer) "both"); } else { g_ptr_array_add(argv, (gpointer) "-h"); - g_ptr_array_add(argv, (gpointer) hostname); + g_ptr_array_add(argv, (gpointer) client_config->hostname); } } - g_ptr_array_add(argv, (gpointer) iface); + g_ptr_array_add(argv, (gpointer) client_config->iface); g_ptr_array_add(argv, NULL); _LOGD("running: %s", (cmd_str = g_strjoinv(" ", (char **) argv->pdata))); diff --git a/src/core/dhcp/nm-dhcp-manager.c b/src/core/dhcp/nm-dhcp-manager.c index 3cb893932d..7c7ac13f33 100644 --- a/src/core/dhcp/nm-dhcp-manager.c +++ b/src/core/dhcp/nm-dhcp-manager.c @@ -17,7 +17,6 @@ #include <stdio.h> #include "libnm-glib-aux/nm-dedup-multi.h" -#include "libnm-systemd-shared/nm-sd-utils-shared.h" #include "nm-config.h" #include "NetworkManagerUtils.h" @@ -26,7 +25,6 @@ typedef struct { const NMDhcpClientFactory *client_factory; - char * default_hostname; } NMDhcpManagerPrivate; struct _NMDhcpManager { @@ -129,34 +127,8 @@ _client_factory_get_gtype(const NMDhcpClientFactory *client_factory, int addr_fa /*****************************************************************************/ -static NMDhcpClient * -client_start(NMDhcpManager * self, - int addr_family, - NMDedupMultiIndex * multi_idx, - const char * iface, - int ifindex, - GBytes * hwaddr, - GBytes * bcast_hwaddr, - const char * uuid, - guint32 route_table, - guint32 route_metric, - const struct in6_addr * ipv6_ll_addr, - GBytes * dhcp_client_id, - gboolean enforce_duid, - guint32 iaid, - gboolean iaid_explicit, - guint32 timeout, - NMDhcpClientFlags client_flags, - const char * anycast_address, - const char * hostname, - NMDhcpHostnameFlags hostname_flags, - const char * mud_url, - NMSettingIP6ConfigPrivacy privacy, - const char * last_ip4_address, - guint needed_prefixes, - GBytes * vendor_class_identifier, - const char *const * reject_servers, - GError ** error) +NMDhcpClient * +nm_dhcp_manager_start_client(NMDhcpManager *self, NMDhcpClientConfig *config, GError **error) { NMDhcpManagerPrivate *priv; gs_unref_object NMDhcpClient *client = NULL; @@ -165,100 +137,44 @@ client_start(NMDhcpManager * self, GType gtype; g_return_val_if_fail(NM_IS_DHCP_MANAGER(self), NULL); - g_return_val_if_fail(iface, NULL); - g_return_val_if_fail(ifindex > 0, NULL); - g_return_val_if_fail(uuid != NULL, NULL); - g_return_val_if_fail(!dhcp_client_id || g_bytes_get_size(dhcp_client_id) >= 2, NULL); - g_return_val_if_fail(!vendor_class_identifier - || g_bytes_get_size(vendor_class_identifier) <= 255, + g_return_val_if_fail(config, NULL); + g_return_val_if_fail(config->iface, NULL); + g_return_val_if_fail(config->l3cfg, NULL); + g_return_val_if_fail(config->uuid != NULL, NULL); + g_return_val_if_fail(!config->client_id || g_bytes_get_size(config->client_id) >= 2, NULL); + g_return_val_if_fail(!config->vendor_class_identifier + || g_bytes_get_size(config->vendor_class_identifier) <= 255, NULL); g_return_val_if_fail(!error || !*error, NULL); - nm_assert(!NM_FLAGS_ANY(client_flags, ~NM_DHCP_CLIENT_FLAGS_ALL)); - if (addr_family == AF_INET) { - if (!hwaddr || !bcast_hwaddr) { + if (config->addr_family == AF_INET) { + if (!config->hwaddr || !config->bcast_hwaddr) { nm_utils_error_set(error, NM_UTILS_ERROR_UNKNOWN, "missing %s address", - hwaddr ? "broadcast" : "MAC"); + config->hwaddr ? "broadcast" : "MAC"); return NULL; } - hwaddr_len = g_bytes_get_size(hwaddr); + hwaddr_len = g_bytes_get_size(config->hwaddr); if (hwaddr_len == 0 || hwaddr_len > _NM_UTILS_HWADDR_LEN_MAX) { nm_utils_error_set(error, NM_UTILS_ERROR_UNKNOWN, "invalid MAC address"); g_return_val_if_reached(NULL); } - nm_assert(g_bytes_get_size(hwaddr) == g_bytes_get_size(bcast_hwaddr)); - } else { - hwaddr = NULL; - bcast_hwaddr = NULL; - } - - if (hostname) { - gboolean use_fqdn = NM_FLAGS_HAS(client_flags, NM_DHCP_CLIENT_FLAGS_USE_FQDN); - - if ((use_fqdn && !nm_sd_dns_name_is_valid(hostname)) - || (!use_fqdn && !nm_sd_hostname_is_valid(hostname, FALSE))) { - nm_log_warn(LOGD_DHCP, - "dhcp%c: %s '%s' is invalid, will be ignored", - nm_utils_addr_family_to_char(addr_family), - use_fqdn ? "FQDN" : "hostname", - hostname); - hostname = NULL; - } + nm_assert(g_bytes_get_size(config->hwaddr) == g_bytes_get_size(config->bcast_hwaddr)); } priv = NM_DHCP_MANAGER_GET_PRIVATE(self); - gtype = _client_factory_get_gtype(priv->client_factory, addr_family); + gtype = _client_factory_get_gtype(priv->client_factory, config->addr_family); nm_log_trace(LOGD_DHCP, "dhcp%c: creating IPv%c DHCP client of type %s", - nm_utils_addr_family_to_char(addr_family), - nm_utils_addr_family_to_char(addr_family), + nm_utils_addr_family_to_char(config->addr_family), + nm_utils_addr_family_to_char(config->addr_family), g_type_name(gtype)); - client = g_object_new(gtype, - NM_DHCP_CLIENT_MULTI_IDX, - multi_idx, - NM_DHCP_CLIENT_ADDR_FAMILY, - addr_family, - NM_DHCP_CLIENT_INTERFACE, - iface, - NM_DHCP_CLIENT_IFINDEX, - ifindex, - NM_DHCP_CLIENT_HWADDR, - hwaddr, - NM_DHCP_CLIENT_BROADCAST_HWADDR, - bcast_hwaddr, - NM_DHCP_CLIENT_UUID, - uuid, - 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, - NM_DHCP_CLIENT_HOSTNAME_FLAGS, - (guint) hostname_flags, - NM_DHCP_CLIENT_VENDOR_CLASS_IDENTIFIER, - vendor_class_identifier, - NM_DHCP_CLIENT_REJECT_SERVERS, - reject_servers, - NM_DHCP_CLIENT_FLAGS, - (guint) client_flags, - NM_DHCP_CLIENT_ANYCAST_ADDRESS, - anycast_address, - NULL); + client = g_object_new(gtype, NM_DHCP_CLIENT_CONFIG, config, NULL); /* unfortunately, our implementations work differently per address-family regarding client-id/DUID. * @@ -286,16 +202,10 @@ client_start(NMDhcpManager * self, * default outside of NetworkManager API. */ - if (addr_family == AF_INET) { - success = nm_dhcp_client_start_ip4(client, dhcp_client_id, last_ip4_address, error); + if (config->addr_family == AF_INET) { + success = nm_dhcp_client_start_ip4(client, error); } else { - success = nm_dhcp_client_start_ip6(client, - dhcp_client_id, - enforce_duid, - ipv6_ll_addr, - privacy, - needed_prefixes, - error); + success = nm_dhcp_client_start_ip6(client, error); } if (!success) @@ -304,178 +214,6 @@ client_start(NMDhcpManager * self, return g_steal_pointer(&client); } -/* Caller owns a reference to the NMDhcpClient on return */ -NMDhcpClient * -nm_dhcp_manager_start_ip4(NMDhcpManager * self, - NMDedupMultiIndex * multi_idx, - const char * iface, - int ifindex, - GBytes * hwaddr, - GBytes * bcast_hwaddr, - const char * uuid, - guint32 route_table, - guint32 route_metric, - NMDhcpClientFlags client_flags, - gboolean send_hostname, - const char * dhcp_hostname, - const char * dhcp_fqdn, - NMDhcpHostnameFlags hostname_flags, - const char * mud_url, - GBytes * dhcp_client_id, - guint32 timeout, - const char * anycast_address, - const char * last_ip_address, - GBytes * vendor_class_identifier, - const char *const * reject_servers, - GError ** error) -{ - NMDhcpManagerPrivate *priv; - const char * hostname = NULL; - gs_free char * hostname_tmp = NULL; - gboolean use_fqdn = FALSE; - char * dot; - - /* these flags are set automatically/prohibited, and not free to set to the caller. */ - nm_assert(!NM_FLAGS_ANY(client_flags, - NM_DHCP_CLIENT_FLAGS_USE_FQDN | NM_DHCP_CLIENT_FLAGS_INFO_ONLY)); - - g_return_val_if_fail(NM_IS_DHCP_MANAGER(self), NULL); - priv = NM_DHCP_MANAGER_GET_PRIVATE(self); - - if (send_hostname) { - /* Use, in order of preference: - * 1. FQDN from configuration - * 2. hostname from configuration - * 3. system hostname (only host part) - */ - if (dhcp_fqdn) { - hostname = dhcp_fqdn; - use_fqdn = TRUE; - } else if (dhcp_hostname) - hostname = dhcp_hostname; - else { - hostname = priv->default_hostname; - if (hostname) { - hostname_tmp = g_strdup(hostname); - dot = strchr(hostname_tmp, '.'); - if (dot) - *dot = '\0'; - hostname = hostname_tmp; - } - } - } - - return client_start( - self, - AF_INET, - multi_idx, - iface, - ifindex, - hwaddr, - bcast_hwaddr, - uuid, - route_table, - route_metric, - NULL, - dhcp_client_id, - FALSE, - 0, - FALSE, - timeout, - client_flags | (use_fqdn ? NM_DHCP_CLIENT_FLAGS_USE_FQDN : NM_DHCP_CLIENT_FLAGS_NONE), - anycast_address, - hostname, - hostname_flags, - mud_url, - 0, - last_ip_address, - 0, - vendor_class_identifier, - reject_servers, - error); -} - -/* Caller owns a reference to the NMDhcpClient on return */ -NMDhcpClient * -nm_dhcp_manager_start_ip6(NMDhcpManager * self, - NMDedupMultiIndex * multi_idx, - const char * iface, - int ifindex, - const struct in6_addr * ll_addr, - const char * uuid, - guint32 route_table, - guint32 route_metric, - NMDhcpClientFlags client_flags, - gboolean send_hostname, - const char * dhcp_hostname, - NMDhcpHostnameFlags hostname_flags, - const char * mud_url, - GBytes * duid, - gboolean enforce_duid, - guint32 iaid, - gboolean iaid_explicit, - guint32 timeout, - const char * anycast_address, - NMSettingIP6ConfigPrivacy privacy, - guint needed_prefixes, - GError ** error) -{ - NMDhcpManagerPrivate *priv; - const char * hostname = NULL; - - /* this flag is set automatically, and not free to set to the caller. */ - nm_assert(!NM_FLAGS_ANY(client_flags, NM_DHCP_CLIENT_FLAGS_USE_FQDN)); - - g_return_val_if_fail(NM_IS_DHCP_MANAGER(self), NULL); - priv = NM_DHCP_MANAGER_GET_PRIVATE(self); - - if (send_hostname) { - /* Always prefer the explicit dhcp-hostname if given */ - hostname = dhcp_hostname ?: priv->default_hostname; - } - return client_start(self, - AF_INET6, - multi_idx, - iface, - ifindex, - NULL, - NULL, - uuid, - route_table, - route_metric, - ll_addr, - duid, - enforce_duid, - iaid, - iaid_explicit, - timeout, - client_flags | NM_DHCP_CLIENT_FLAGS_USE_FQDN, - anycast_address, - hostname, - hostname_flags, - mud_url, - privacy, - NULL, - needed_prefixes, - NULL, - NULL, - error); -} - -void -nm_dhcp_manager_set_default_hostname(NMDhcpManager *manager, const char *hostname) -{ - NMDhcpManagerPrivate *priv = NM_DHCP_MANAGER_GET_PRIVATE(manager); - - nm_clear_g_free(&priv->default_hostname); - - /* Never send 'localhost'-type names to the DHCP server */ - if (!nm_utils_is_specific_hostname(hostname)) - return; - - priv->default_hostname = g_strdup(hostname); -} - const char * nm_dhcp_manager_get_config(NMDhcpManager *self) { @@ -573,20 +311,5 @@ nm_dhcp_manager_init(NMDhcpManager *self) } static void -dispose(GObject *object) -{ - NMDhcpManager * self = NM_DHCP_MANAGER(object); - NMDhcpManagerPrivate *priv = NM_DHCP_MANAGER_GET_PRIVATE(self); - - G_OBJECT_CLASS(nm_dhcp_manager_parent_class)->dispose(object); - - nm_clear_g_free(&priv->default_hostname); -} - -static void nm_dhcp_manager_class_init(NMDhcpManagerClass *manager_class) -{ - GObjectClass *object_class = G_OBJECT_CLASS(manager_class); - - object_class->dispose = dispose; -} +{} diff --git a/src/core/dhcp/nm-dhcp-manager.h b/src/core/dhcp/nm-dhcp-manager.h index ce160437a5..bbd68236a3 100644 --- a/src/core/dhcp/nm-dhcp-manager.h +++ b/src/core/dhcp/nm-dhcp-manager.h @@ -8,7 +8,6 @@ #define __NETWORKMANAGER_DHCP_MANAGER_H__ #include "nm-dhcp-client.h" -#include "nm-ip4-config.h" #include "nm-dhcp-config.h" #define NM_TYPE_DHCP_MANAGER (nm_dhcp_manager_get_type()) @@ -32,51 +31,8 @@ const char *nm_dhcp_manager_get_config(NMDhcpManager *self); void nm_dhcp_manager_set_default_hostname(NMDhcpManager *manager, const char *hostname); -NMDhcpClient *nm_dhcp_manager_start_ip4(NMDhcpManager * manager, - struct _NMDedupMultiIndex *multi_idx, - const char * iface, - int ifindex, - GBytes * hwaddr, - GBytes * bcast_hwaddr, - const char * uuid, - guint32 route_table, - guint32 route_metric, - NMDhcpClientFlags client_flags, - gboolean send_hostname, - const char * dhcp_hostname, - const char * dhcp_fqdn, - NMDhcpHostnameFlags hostname_flags, - const char * mud_url, - GBytes * dhcp_client_id, - guint32 timeout, - const char * anycast_address, - const char * last_ip_address, - GBytes * vendor_class_identifier, - const char *const * reject_servers, - GError ** error); - -NMDhcpClient *nm_dhcp_manager_start_ip6(NMDhcpManager * manager, - struct _NMDedupMultiIndex *multi_idx, - const char * iface, - int ifindex, - const struct in6_addr * ll_addr, - const char * uuid, - guint32 route_table, - guint32 route_metric, - NMDhcpClientFlags client_flags, - gboolean send_hostname, - const char * dhcp_hostname, - NMDhcpHostnameFlags hostname_flags, - const char * mud_url, - GBytes * duid, - gboolean enforce_duid, - guint32 iaid, - gboolean iaid_explicit, - guint32 timeout, - const char * anycast_address, - NMSettingIP6ConfigPrivacy privacy, - guint needed_prefixes, - GError ** error); +NMDhcpClient * +nm_dhcp_manager_start_client(NMDhcpManager *manager, NMDhcpClientConfig *config, GError **error); /* For testing only */ extern const char *nm_dhcp_helper_path; diff --git a/src/core/dhcp/nm-dhcp-nettools.c b/src/core/dhcp/nm-dhcp-nettools.c index 56b485dd25..6ab7f8c18d 100644 --- a/src/core/dhcp/nm-dhcp-nettools.c +++ b/src/core/dhcp/nm-dhcp-nettools.c @@ -17,6 +17,7 @@ #include "libnm-std-aux/unaligned.h" #include "libnm-glib-aux/nm-str-buf.h" +#include "nm-l3-config-data.h" #include "nm-utils.h" #include "nm-config.h" #include "nm-dhcp-utils.h" @@ -151,7 +152,7 @@ lease_option_consume_route(const uint8_t **datap, static gboolean lease_parse_address(NDhcp4ClientLease *lease, - NMIP4Config * ip4_config, + NML3ConfigData * l3cd, GHashTable * options, GError ** error) { @@ -256,23 +257,23 @@ lease_parse_address(NDhcp4ClientLease *lease, a_next_server.s_addr); } - nm_ip4_config_add_address(ip4_config, - &((const NMPlatformIP4Address){ - .address = a_address.s_addr, - .peer_address = a_address.s_addr, - .plen = a_plen, - .addr_source = NM_IP_CONFIG_SOURCE_DHCP, - .timestamp = a_timestamp, - .lifetime = a_lifetime, - .preferred = a_lifetime, - })); + nm_l3_config_data_add_address_4(l3cd, + &((const NMPlatformIP4Address){ + .address = a_address.s_addr, + .peer_address = a_address.s_addr, + .plen = a_plen, + .addr_source = NM_IP_CONFIG_SOURCE_DHCP, + .timestamp = a_timestamp, + .lifetime = a_lifetime, + .preferred = a_lifetime, + })); return TRUE; } static void lease_parse_address_list(NDhcp4ClientLease * lease, - NMIP4Config * ip4_config, + NML3ConfigData * l3cd, NMDhcpOptionDhcp4Options option, GHashTable * options, NMStrBuf * sbuf) @@ -304,13 +305,13 @@ lease_parse_address_list(NDhcp4ClientLease * lease, * See https://github.com/systemd/systemd/issues/4524. */ continue; } - nm_ip4_config_add_nameserver(ip4_config, addr); + nm_l3_config_data_add_nameserver(l3cd, AF_INET, &addr); break; case NM_DHCP_OPTION_DHCP4_NIS_SERVERS: - nm_ip4_config_add_nis_server(ip4_config, addr); + nm_l3_config_data_add_nis_server(l3cd, addr); break; case NM_DHCP_OPTION_DHCP4_NETBIOS_NAMESERVER: - nm_ip4_config_add_wins(ip4_config, addr); + nm_l3_config_data_add_wins(l3cd, addr); break; case NM_DHCP_OPTION_DHCP4_NTP_SERVER: break; @@ -324,10 +325,8 @@ lease_parse_address_list(NDhcp4ClientLease * lease, static void lease_parse_routes(NDhcp4ClientLease *lease, - NMIP4Config * ip4_config, + NML3ConfigData * l3cd, GHashTable * options, - guint32 route_table, - guint32 route_metric, NMStrBuf * sbuf) { char dest_str[NM_UTILS_INET_ADDRSTRLEN]; @@ -336,9 +335,9 @@ lease_parse_routes(NDhcp4ClientLease *lease, in_addr_t gateway; uint8_t plen; guint32 m; - gboolean has_router_from_classless = FALSE; - gboolean has_classless = FALSE; - guint32 default_route_metric = route_metric; + gboolean has_router_from_classless = FALSE; + gboolean has_classless = FALSE; + guint32 default_route_metric_offset = 0; const guint8 *l_data; gsize l_data_len; int r; @@ -367,26 +366,22 @@ lease_parse_routes(NDhcp4ClientLease *lease, if (plen == 0) { /* if there are multiple default routes, we add them with differing * metrics. */ - m = default_route_metric; - if (default_route_metric < G_MAXUINT32) - default_route_metric++; - + m = default_route_metric_offset++; has_router_from_classless = TRUE; - } else { - m = route_metric; - } - - nm_ip4_config_add_route( - ip4_config, - &((const NMPlatformIP4Route){ - .network = dest, - .plen = plen, - .gateway = gateway, - .rt_source = NM_IP_CONFIG_SOURCE_DHCP, - .metric = m, - .table_coerced = nm_platform_route_table_coerce(route_table), - }), - NULL); + } else + m = 0; + + nm_l3_config_data_add_route_4(l3cd, + &((const NMPlatformIP4Route){ + .network = dest, + .plen = plen, + .gateway = gateway, + .rt_source = NM_IP_CONFIG_SOURCE_DHCP, + .table_any = TRUE, + .table_coerced = 0, + .metric_any = TRUE, + .metric = m, + })); } has_classless = TRUE; @@ -419,17 +414,17 @@ lease_parse_routes(NDhcp4ClientLease *lease, continue; } - nm_ip4_config_add_route( - ip4_config, - &((const NMPlatformIP4Route){ - .network = dest, - .plen = plen, - .gateway = gateway, - .rt_source = NM_IP_CONFIG_SOURCE_DHCP, - .metric = route_metric, - .table_coerced = nm_platform_route_table_coerce(route_table), - }), - NULL); + nm_l3_config_data_add_route_4(l3cd, + &((const NMPlatformIP4Route){ + .network = dest, + .plen = plen, + .gateway = gateway, + .rt_source = NM_IP_CONFIG_SOURCE_DHCP, + .table_any = TRUE, + .table_coerced = 0, + .metric_any = TRUE, + .metric = 0, + })); } nm_dhcp_option_add_option(options, @@ -463,19 +458,17 @@ lease_parse_routes(NDhcp4ClientLease *lease, /* if there are multiple default routes, we add them with differing * metrics. */ - m = default_route_metric; - if (default_route_metric < G_MAXUINT32) - default_route_metric++; - - nm_ip4_config_add_route( - ip4_config, - &((const NMPlatformIP4Route){ - .rt_source = NM_IP_CONFIG_SOURCE_DHCP, - .gateway = gateway, - .table_coerced = nm_platform_route_table_coerce(route_table), - .metric = m, - }), - NULL); + m = default_route_metric_offset++; + + nm_l3_config_data_add_route_4(l3cd, + &((const NMPlatformIP4Route){ + .rt_source = NM_IP_CONFIG_SOURCE_DHCP, + .gateway = gateway, + .table_any = TRUE, + .table_coerced = 0, + .metric_any = TRUE, + .metric = m, + })); } nm_dhcp_option_add_option(options, @@ -486,7 +479,7 @@ lease_parse_routes(NDhcp4ClientLease *lease, } static void -lease_parse_search_domains(NDhcp4ClientLease *lease, NMIP4Config *ip4_config, GHashTable *options) +lease_parse_search_domains(NDhcp4ClientLease *lease, NML3ConfigData *l3cd, GHashTable *options) { gs_strfreev char **domains = NULL; const guint8 * l_data; @@ -504,7 +497,7 @@ lease_parse_search_domains(NDhcp4ClientLease *lease, NMIP4Config *ip4_config, GH return; for (i = 0; domains[i]; i++) - nm_ip4_config_add_search(ip4_config, domains[i]); + nm_l3_config_data_add_search(l3cd, AF_INET, domains[i]); nm_dhcp_option_take_option(options, AF_INET, @@ -539,34 +532,31 @@ lease_parse_private_options(NDhcp4ClientLease *lease, GHashTable *options) } } -static NMIP4Config * +static NML3ConfigData * lease_to_ip4_config(NMDedupMultiIndex *multi_idx, const char * iface, int ifindex, NDhcp4ClientLease *lease, - guint32 route_table, - guint32 route_metric, - GHashTable ** out_options, GError ** error) { - nm_auto_str_buf NMStrBuf sbuf = NM_STR_BUF_INIT(0, FALSE); - gs_unref_object NMIP4Config *ip4_config = NULL; - gs_unref_hashtable GHashTable *options = NULL; + nm_auto_str_buf NMStrBuf sbuf = NM_STR_BUF_INIT(0, FALSE); + nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; + gs_unref_hashtable GHashTable *options = NULL; const guint8 * l_data; gsize l_data_len; const char * v_str; guint16 v_u16; - gboolean v_bool; in_addr_t v_inaddr; struct in_addr v_inaddr_s; int r; g_return_val_if_fail(lease != NULL, NULL); - ip4_config = nm_ip4_config_new(multi_idx, ifindex); - options = nm_dhcp_option_create_options_dict(); + l3cd = nm_l3_config_data_new(multi_idx, ifindex, NM_IP_CONFIG_SOURCE_DHCP); + + options = nm_dhcp_option_create_options_dict(); - if (!lease_parse_address(lease, ip4_config, options, error)) + if (!lease_parse_address(lease, l3cd, options, error)) return NULL; r = n_dhcp4_client_lease_get_server_identifier(lease, &v_inaddr_s); @@ -585,13 +575,9 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, v_inaddr); } - lease_parse_routes(lease, ip4_config, options, route_table, route_metric, &sbuf); + lease_parse_routes(lease, l3cd, options, &sbuf); - lease_parse_address_list(lease, - ip4_config, - NM_DHCP_OPTION_DHCP4_DOMAIN_NAME_SERVER, - options, - &sbuf); + lease_parse_address_list(lease, l3cd, NM_DHCP_OPTION_DHCP4_DOMAIN_NAME_SERVER, options, &sbuf); r = _client_lease_query(lease, NM_DHCP_OPTION_DHCP4_DOMAIN_NAME, &l_data, &l_data_len); if (r == 0 && nm_dhcp_lease_data_parse_cstr(l_data, l_data_len, &l_data_len)) { @@ -616,7 +602,7 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, nm_str_buf_append_required_delimiter(&sbuf, ' '); nm_str_buf_append(&sbuf, s); - nm_ip4_config_add_domain(ip4_config, s); + nm_l3_config_data_add_domain(l3cd, AF_INET, s); } } @@ -628,18 +614,17 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, } } - lease_parse_search_domains(lease, ip4_config, options); + lease_parse_search_domains(lease, l3cd, options); r = _client_lease_query(lease, NM_DHCP_OPTION_DHCP4_INTERFACE_MTU, &l_data, &l_data_len); if (r == 0 && nm_dhcp_lease_data_parse_mtu(l_data, l_data_len, &v_u16)) { nm_dhcp_option_add_option_u64(options, AF_INET, NM_DHCP_OPTION_DHCP4_INTERFACE_MTU, v_u16); - nm_ip4_config_set_mtu(ip4_config, v_u16, NM_IP_CONFIG_SOURCE_DHCP); + nm_l3_config_data_set_mtu(l3cd, v_u16); } r = _client_lease_query(lease, NM_DHCP_OPTION_DHCP4_VENDOR_SPECIFIC, &l_data, &l_data_len); - v_bool = - (r == 0) && memmem(l_data, l_data_len, "ANDROID_METERED", NM_STRLEN("ANDROID_METERED")); - nm_ip4_config_set_metered(ip4_config, v_bool); + if ((r == 0) && memmem(l_data, l_data_len, "ANDROID_METERED", NM_STRLEN("ANDROID_METERED"))) + nm_l3_config_data_set_metered(l3cd, TRUE); r = _client_lease_query(lease, NM_DHCP_OPTION_DHCP4_HOST_NAME, &l_data, &l_data_len); if (r == 0) { @@ -650,7 +635,7 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, } } - lease_parse_address_list(lease, ip4_config, NM_DHCP_OPTION_DHCP4_NTP_SERVER, options, &sbuf); + lease_parse_address_list(lease, l3cd, NM_DHCP_OPTION_DHCP4_NTP_SERVER, options, &sbuf); r = _client_lease_query(lease, NM_DHCP_OPTION_DHCP4_ROOT_PATH, &l_data, &l_data_len); if (r == 0 && nm_dhcp_lease_data_parse_cstr(l_data, l_data_len, &l_data_len)) { @@ -681,11 +666,17 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, * We reject NUL characters inside the string (except trailing NULs). * Otherwise, we allow any encoding and backslash-escape the result to * UTF-8. */ - nm_dhcp_option_add_option_utf8safe_escape(options, - AF_INET, - NM_DHCP_OPTION_DHCP4_PRIVATE_PROXY_AUTODISCOVERY, - l_data, - l_data_len); + gs_free char *to_free = NULL; + const char * escaped; + + escaped = nm_utils_buf_utf8safe_escape((char *) l_data, l_data_len, 0, &to_free); + nm_dhcp_option_add_option(options, + AF_INET, + NM_DHCP_OPTION_DHCP4_PRIVATE_PROXY_AUTODISCOVERY, + escaped ?: ""); + + nm_l3_config_data_set_proxy_method(l3cd, NM_PROXY_CONFIG_METHOD_AUTO); + nm_l3_config_data_set_proxy_pac_url(l3cd, escaped ?: ""); } r = _client_lease_query(lease, NM_DHCP_OPTION_DHCP4_NIS_DOMAIN, &l_data, &l_data_len); @@ -700,7 +691,7 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, &to_free); nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_NIS_DOMAIN, v_str ?: ""); - nm_ip4_config_set_nis_domain(ip4_config, v_str ?: ""); + nm_l3_config_data_set_nis_domain(l3cd, v_str ?: ""); } r = n_dhcp4_client_lease_get_file(lease, &v_str); @@ -728,18 +719,17 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, v_str ?: ""); } - lease_parse_address_list(lease, ip4_config, NM_DHCP_OPTION_DHCP4_NIS_SERVERS, options, &sbuf); + lease_parse_address_list(lease, l3cd, NM_DHCP_OPTION_DHCP4_NIS_SERVERS, options, &sbuf); - lease_parse_address_list(lease, - ip4_config, - NM_DHCP_OPTION_DHCP4_NETBIOS_NAMESERVER, - options, - &sbuf); + lease_parse_address_list(lease, l3cd, NM_DHCP_OPTION_DHCP4_NETBIOS_NAMESERVER, options, &sbuf); lease_parse_private_options(lease, options); - NM_SET_OUT(out_options, g_steal_pointer(&options)); - return g_steal_pointer(&ip4_config); + nm_dhcp_option_add_requests_to_options(options, AF_INET); + + nm_l3_config_data_set_dhcp_lease_from_options(l3cd, AF_INET, g_steal_pointer(&options)); + + return g_steal_pointer(&l3cd); } /*****************************************************************************/ @@ -771,47 +761,44 @@ lease_save(NMDhcpNettools *self, NDhcp4ClientLease *lease, const char *lease_fil static void bound4_handle(NMDhcpNettools *self, NDhcp4ClientLease *lease, gboolean extended) { - NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self); - const char * iface = nm_dhcp_client_get_iface(NM_DHCP_CLIENT(self)); - gs_unref_object NMIP4Config *ip4_config = NULL; - gs_unref_hashtable GHashTable *options = NULL; - GError * error = NULL; + NMDhcpNettoolsPrivate * priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self); + NMDhcpClient * client = NM_DHCP_CLIENT(self); + const NMDhcpClientConfig *client_config; + nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; + GError * error = NULL; _LOGT("lease available (%s)", extended ? "extended" : "new"); - - ip4_config = lease_to_ip4_config(nm_dhcp_client_get_multi_idx(NM_DHCP_CLIENT(self)), - iface, - nm_dhcp_client_get_ifindex(NM_DHCP_CLIENT(self)), - lease, - nm_dhcp_client_get_route_table(NM_DHCP_CLIENT(self)), - nm_dhcp_client_get_route_metric(NM_DHCP_CLIENT(self)), - &options, - &error); - if (!ip4_config) { - _LOGW("%s", error->message); + client_config = nm_dhcp_client_get_config(client); + l3cd = lease_to_ip4_config(nm_dhcp_client_get_multi_idx(client), + client_config->iface, + nm_dhcp_client_get_ifindex(client), + lease, + &error); + if (!l3cd) { + _LOGW("failure to parse lease: %s", error->message); g_clear_error(&error); - nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL, NULL); + nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL); return; } - nm_dhcp_option_add_requests_to_options(options, AF_INET); lease_save(self, lease, priv->lease_file); nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), extended ? NM_DHCP_STATE_EXTENDED : NM_DHCP_STATE_BOUND, - NM_IP_CONFIG_CAST(ip4_config), - options); + l3cd); } static void dhcp4_event_handle(NMDhcpNettools *self, NDhcp4ClientEvent *event) { - NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self); - struct in_addr server_id; - char addr_str[INET_ADDRSTRLEN]; - int r; + NMDhcpNettoolsPrivate * priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self); + const NMDhcpClientConfig *client_config; + struct in_addr server_id; + char addr_str[INET_ADDRSTRLEN]; + int r; _LOGT("client event %d", event->event); + client_config = nm_dhcp_client_get_config(NM_DHCP_CLIENT(self)); switch (event->event) { case N_DHCP4_CLIENT_EVENT_OFFER: @@ -835,10 +822,10 @@ dhcp4_event_handle(NMDhcpNettools *self, NDhcp4ClientEvent *event) break; case N_DHCP4_CLIENT_EVENT_RETRACTED: case N_DHCP4_CLIENT_EVENT_EXPIRED: - nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_EXPIRE, NULL, NULL); + nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_EXPIRE, NULL); break; case N_DHCP4_CLIENT_EVENT_CANCELLED: - nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL, NULL); + nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL); break; case N_DHCP4_CLIENT_EVENT_GRANTED: priv->lease = n_dhcp4_client_lease_ref(event->granted.lease); @@ -861,7 +848,7 @@ dhcp4_event_handle(NMDhcpNettools *self, NDhcp4ClientEvent *event) NULL, NULL, "dhcp4 (%s): %s", - nm_dhcp_client_get_iface(NM_DHCP_CLIENT(self)), + client_config->iface, event->log.message); } } break; @@ -890,13 +877,12 @@ dhcp4_event_cb(int fd, GIOCondition condition, gpointer user_data) */ _LOGE("error %d dispatching events", r); nm_clear_g_source_inst(&priv->event_source); - nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL, NULL); + nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL); return G_SOURCE_REMOVE; } - while (!n_dhcp4_client_pop_event(priv->client, &event) && event) { + while (!n_dhcp4_client_pop_event(priv->client, &event) && event) dhcp4_event_handle(self, event); - } return G_SOURCE_CONTINUE; } @@ -914,23 +900,26 @@ nettools_create(NMDhcpNettools *self, GError **error) gsize hwaddr_len; gsize bcast_hwaddr_len; GBytes * client_id; - gs_unref_bytes GBytes *client_id_new = NULL; - const uint8_t * client_id_arr; - size_t client_id_len; - int r, fd, arp_type, transport; + gs_unref_bytes GBytes * client_id_new = NULL; + const uint8_t * client_id_arr; + size_t client_id_len; + int r, fd, arp_type, transport; + const NMDhcpClientConfig *client_config; + + client_config = nm_dhcp_client_get_config(NM_DHCP_CLIENT(self)); g_return_val_if_fail(!priv->client, FALSE); /* TODO: honor nm_dhcp_client_get_anycast_address() */ - hwaddr = nm_dhcp_client_get_hw_addr(NM_DHCP_CLIENT(self)); + hwaddr = client_config->hwaddr; if (!hwaddr || !(hwaddr_arr = g_bytes_get_data(hwaddr, &hwaddr_len)) || (arp_type = nm_utils_arp_type_detect_from_hwaddrlen(hwaddr_len)) < 0) { nm_utils_error_set_literal(error, NM_UTILS_ERROR_UNKNOWN, "invalid MAC address"); return FALSE; } - bcast_hwaddr = nm_dhcp_client_get_broadcast_hw_addr(NM_DHCP_CLIENT(self)); + bcast_hwaddr = client_config->bcast_hwaddr; bcast_hwaddr_arr = g_bytes_get_data(bcast_hwaddr, &bcast_hwaddr_len); switch (arp_type) { @@ -947,7 +936,7 @@ nettools_create(NMDhcpNettools *self, GError **error) /* Note that we always set a client-id. In particular for infiniband that is necessary, * see https://tools.ietf.org/html/rfc4390#section-2.1 . */ - client_id = nm_dhcp_client_get_client_id(NM_DHCP_CLIENT(self)); + client_id = client_config->client_id; if (!client_id) { client_id_new = nm_utils_dhcp_client_id_mac(arp_type, hwaddr_arr, hwaddr_len); client_id = client_id_new; @@ -971,10 +960,7 @@ nettools_create(NMDhcpNettools *self, GError **error) n_dhcp4_client_config_set_transport(config, transport); n_dhcp4_client_config_set_mac(config, hwaddr_arr, hwaddr_len); n_dhcp4_client_config_set_broadcast_mac(config, bcast_hwaddr_arr, bcast_hwaddr_len); - n_dhcp4_client_config_set_request_broadcast( - config, - NM_FLAGS_HAS(nm_dhcp_client_get_client_flags(NM_DHCP_CLIENT(self)), - NM_DHCP_CLIENT_FLAGS_REQUEST_BROADCAST)); + n_dhcp4_client_config_set_request_broadcast(config, client_config->v4.request_broadcast); r = n_dhcp4_client_config_set_client_id(config, client_id_arr, NM_MIN(client_id_len, 1 + _NM_MAX_CLIENT_ID_LEN)); @@ -1033,7 +1019,7 @@ decline(NMDhcpClient *client, const char *error_message, GError **error) g_return_val_if_fail(priv->lease, FALSE); - _LOGT("dhcp4-client: decline"); + _LOGT("dhcp4-client: decline (%s)", error_message); r = n_dhcp4_client_lease_decline(priv->lease, error_message); if (r) { @@ -1063,19 +1049,20 @@ fqdn_flags_to_wire(NMDhcpHostnameFlags flags) } static gboolean -ip4_start(NMDhcpClient *client, const char *last_ip4_address, GError **error) +ip4_start(NMDhcpClient *client, GError **error) { nm_auto(n_dhcp4_client_probe_config_freep) NDhcp4ClientProbeConfig *config = NULL; - NMDhcpNettools * self = NM_DHCP_NETTOOLS(client); - NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self); - gs_free char * lease_file = NULL; - struct in_addr last_addr = {0}; - const char * hostname; - const char * mud_url; - GBytes * vendor_class_identifier; - int r, i; + NMDhcpNettools * self = NM_DHCP_NETTOOLS(client); + NMDhcpNettoolsPrivate * priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self); + const NMDhcpClientConfig *client_config; + gs_free char * lease_file = NULL; + struct in_addr last_addr = {0}; + int r, i; + + client_config = nm_dhcp_client_get_config(client); g_return_val_if_fail(!priv->probe, FALSE); + g_return_val_if_fail(client_config, FALSE); if (!nettools_create(self, error)) return FALSE; @@ -1094,12 +1081,12 @@ ip4_start(NMDhcpClient *client, const char *last_ip4_address, GError **error) nm_dhcp_utils_get_leasefile_path(AF_INET, "internal", - nm_dhcp_client_get_iface(client), - nm_dhcp_client_get_uuid(client), + client_config->iface, + client_config->uuid, &lease_file); - if (last_ip4_address) - inet_pton(AF_INET, last_ip4_address, &last_addr); + if (client_config->v4.last_address) + inet_pton(AF_INET, client_config->v4.last_address, &last_addr); else { /* * TODO: we stick to the systemd-networkd lease file format. Quite easy for now to @@ -1129,31 +1116,33 @@ ip4_start(NMDhcpClient *client, const char *last_ip4_address, GError **error) } } - mud_url = nm_dhcp_client_get_mud_url(client); - if (mud_url) { + if (client_config->mud_url) { r = n_dhcp4_client_probe_config_append_option(config, NM_DHCP_OPTION_DHCP4_MUD_URL, - mud_url, - strlen(mud_url)); + client_config->mud_url, + strlen(client_config->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_FLAGS_HAS(nm_dhcp_client_get_client_flags(client), NM_DHCP_CLIENT_FLAGS_USE_FQDN)) { + + if (client_config->hostname) { + if (client_config->use_fqdn) { uint8_t buffer[255]; NMDhcpHostnameFlags flags; size_t fqdn_len; - flags = nm_dhcp_client_get_hostname_flags(client); + flags = client_config->hostname_flags; buffer[0] = fqdn_flags_to_wire(flags); buffer[1] = 0; /* RCODE1 (deprecated) */ buffer[2] = 0; /* RCODE2 (deprecated) */ if (flags & NM_DHCP_HOSTNAME_FLAG_FQDN_ENCODED) { - r = nm_sd_dns_name_to_wire_format(hostname, buffer + 3, sizeof(buffer) - 3, FALSE); + r = nm_sd_dns_name_to_wire_format(client_config->hostname, + buffer + 3, + sizeof(buffer) - 3, + FALSE); if (r <= 0) { if (r < 0) nm_utils_error_set_errno(error, r, "failed to convert DHCP FQDN: %s"); @@ -1163,12 +1152,12 @@ ip4_start(NMDhcpClient *client, const char *last_ip4_address, GError **error) } fqdn_len = r; } else { - fqdn_len = strlen(hostname); + fqdn_len = strlen(client_config->hostname); if (fqdn_len > sizeof(buffer) - 3) { nm_utils_error_set(error, r, "failed to set DHCP FQDN: name too long"); return FALSE; } - memcpy(buffer + 3, hostname, fqdn_len); + memcpy(buffer + 3, client_config->hostname, fqdn_len); } r = n_dhcp4_client_probe_config_append_option(config, @@ -1182,8 +1171,8 @@ ip4_start(NMDhcpClient *client, const char *last_ip4_address, GError **error) } else { r = n_dhcp4_client_probe_config_append_option(config, NM_DHCP_OPTION_DHCP4_HOST_NAME, - hostname, - strlen(hostname)); + client_config->hostname, + strlen(client_config->hostname)); if (r) { set_error_nettools(error, r, "failed to set DHCP hostname"); return FALSE; @@ -1191,12 +1180,11 @@ ip4_start(NMDhcpClient *client, const char *last_ip4_address, GError **error) } } - vendor_class_identifier = nm_dhcp_client_get_vendor_class_identifier(client); - if (vendor_class_identifier) { + if (client_config->vendor_class_identifier) { const void *option_data; gsize option_size; - option_data = g_bytes_get_data(vendor_class_identifier, &option_size); + option_data = g_bytes_get_data(client_config->vendor_class_identifier, &option_size); nm_assert(option_data); nm_assert(option_size <= 255); diff --git a/src/core/dhcp/nm-dhcp-systemd.c b/src/core/dhcp/nm-dhcp-systemd.c index af1d2238b4..a6adc0ccdc 100644 --- a/src/core/dhcp/nm-dhcp-systemd.c +++ b/src/core/dhcp/nm-dhcp-systemd.c @@ -17,6 +17,7 @@ #include "libnm-std-aux/unaligned.h" #include "nm-utils.h" +#include "nm-l3-config-data.h" #include "nm-dhcp-utils.h" #include "nm-dhcp-options.h" #include "nm-core-utils.h" @@ -51,8 +52,6 @@ typedef struct { char * lease_file; guint request_count; - - bool privacy : 1; } NMDhcpSystemdPrivate; struct _NMDhcpSystemd { @@ -70,18 +69,15 @@ G_DEFINE_TYPE(NMDhcpSystemd, nm_dhcp_systemd, NM_TYPE_DHCP_CLIENT) /*****************************************************************************/ -static NMIP4Config * +static NML3ConfigData * lease_to_ip4_config(NMDedupMultiIndex *multi_idx, const char * iface, int ifindex, sd_dhcp_lease * lease, - guint32 route_table, - guint32 route_metric, - GHashTable ** out_options, GError ** error) { - gs_unref_object NMIP4Config *ip4_config = NULL; - gs_unref_hashtable GHashTable *options = NULL; + nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; + gs_unref_hashtable GHashTable *options = NULL; const struct in_addr * addr_list; char addr_str[NM_UTILS_INET_ADDRSTRLEN]; const char * s; @@ -92,7 +88,6 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, int i, num; const void * data; gsize data_len; - gboolean metered = FALSE; gboolean has_router_from_classless = FALSE; gboolean has_classless_route = FALSE; gboolean has_static_route = FALSE; @@ -133,9 +128,9 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, return NULL; } - ip4_config = nm_ip4_config_new(multi_idx, ifindex); + l3cd = nm_l3_config_data_new(multi_idx, ifindex, NM_IP_CONFIG_SOURCE_DHCP); - options = out_options ? nm_dhcp_option_create_options_dict() : NULL; + options = nm_dhcp_option_create_options_dict(); _nm_utils_inet4_ntop(a_address.s_addr, addr_str); nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_NM_IP_ADDRESS, addr_str); @@ -160,16 +155,16 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_NM_NEXT_SERVER, addr_str); } - nm_ip4_config_add_address(ip4_config, - &((const NMPlatformIP4Address){ - .address = a_address.s_addr, - .peer_address = a_address.s_addr, - .plen = a_plen, - .addr_source = NM_IP_CONFIG_SOURCE_DHCP, - .timestamp = ts, - .lifetime = a_lifetime, - .preferred = a_lifetime, - })); + nm_l3_config_data_add_address_4(l3cd, + &((const NMPlatformIP4Address){ + .address = a_address.s_addr, + .peer_address = a_address.s_addr, + .plen = a_plen, + .addr_source = NM_IP_CONFIG_SOURCE_DHCP, + .timestamp = ts, + .lifetime = a_lifetime, + .preferred = a_lifetime, + })); if (sd_dhcp_lease_get_server_identifier(lease, &server_id) >= 0) { _nm_utils_inet4_ntop(server_id.s_addr, addr_str); @@ -193,7 +188,7 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, * See https://github.com/systemd/systemd/issues/4524. */ continue; } - nm_ip4_config_add_nameserver(ip4_config, addr_list[i].s_addr); + nm_l3_config_data_add_nameserver(l3cd, AF_INET, &addr_list[i].s_addr); } nm_dhcp_option_add_option(options, AF_INET, @@ -206,7 +201,7 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, nm_gstring_prepare(&str); for (i = 0; i < num; i++) { g_string_append(nm_gstring_add_space_delimiter(str), search_domains[i]); - nm_ip4_config_add_search(ip4_config, search_domains[i]); + nm_l3_config_data_add_search(l3cd, AF_INET, search_domains[i]); } nm_dhcp_option_add_option(options, AF_INET, @@ -224,7 +219,7 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, * As systemd escapes such characters, split them at \\032. */ domains = g_strsplit(s, "\\032", 0); for (d = domains; *d; d++) - nm_ip4_config_add_domain(ip4_config, *d); + nm_l3_config_data_add_domain(l3cd, AF_INET, *d); } if (sd_dhcp_lease_get_hostname(lease, &s) >= 0) { @@ -233,9 +228,9 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, num = sd_dhcp_lease_get_routes(lease, &routes); if (num > 0) { - nm_auto_free_gstring GString *str_classless = NULL; - nm_auto_free_gstring GString *str_static = NULL; - guint32 default_route_metric = route_metric; + nm_auto_free_gstring GString *str_classless = NULL; + nm_auto_free_gstring GString *str_static = NULL; + guint32 default_route_metric_offset = 0; for (i = 0; i < num; i++) { switch (sd_dhcp_route_get_option(routes[i])) { @@ -307,25 +302,22 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, if (r_plen == 0) { /* if there are multiple default routes, we add them with differing * metrics. */ - m = default_route_metric; - if (default_route_metric < G_MAXUINT32) - default_route_metric++; - + m = default_route_metric_offset++; has_router_from_classless = TRUE; } else - m = route_metric; - - nm_ip4_config_add_route( - ip4_config, - &((const NMPlatformIP4Route){ - .network = network_net, - .plen = r_plen, - .gateway = r_gateway.s_addr, - .rt_source = NM_IP_CONFIG_SOURCE_DHCP, - .metric = m, - .table_coerced = nm_platform_route_table_coerce(route_table), - }), - NULL); + m = 0; + + nm_l3_config_data_add_route_4(l3cd, + &((const NMPlatformIP4Route){ + .network = network_net, + .plen = r_plen, + .gateway = r_gateway.s_addr, + .rt_source = NM_IP_CONFIG_SOURCE_DHCP, + .metric_any = TRUE, + .metric = m, + .table_any = TRUE, + .table_coerced = 0, + })); } if (str_classless && str_classless->len > 0) @@ -342,7 +334,7 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, num = sd_dhcp_lease_get_router(lease, &a_router); if (num > 0) { - guint32 default_route_metric = route_metric; + guint32 default_route_metric_offset = 0; nm_gstring_prepare(&str); for (i = 0; i < num; i++) { @@ -368,26 +360,24 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, /* if there are multiple default routes, we add them with differing * metrics. */ - m = default_route_metric; - if (default_route_metric < G_MAXUINT32) - default_route_metric++; - - nm_ip4_config_add_route( - ip4_config, - &((const NMPlatformIP4Route){ - .rt_source = NM_IP_CONFIG_SOURCE_DHCP, - .gateway = a_router[i].s_addr, - .table_coerced = nm_platform_route_table_coerce(route_table), - .metric = m, - }), - NULL); + m = default_route_metric_offset++; + + nm_l3_config_data_add_route_4(l3cd, + &((const NMPlatformIP4Route){ + .rt_source = NM_IP_CONFIG_SOURCE_DHCP, + .gateway = a_router[i].s_addr, + .table_any = TRUE, + .table_coerced = 0, + .metric_any = TRUE, + .metric = m, + })); } nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_ROUTER, str->str); } if (sd_dhcp_lease_get_mtu(lease, &mtu) >= 0 && mtu) { nm_dhcp_option_add_option_u64(options, AF_INET, NM_DHCP_OPTION_DHCP4_INTERFACE_MTU, mtu); - nm_ip4_config_set_mtu(ip4_config, mtu, NM_IP_CONFIG_SOURCE_DHCP); + nm_l3_config_data_set_mtu(l3cd, mtu); } num = sd_dhcp_lease_get_ntp(lease, &addr_list); @@ -422,9 +412,10 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_NEW_TZDB_TIMEZONE, s); } - if (sd_dhcp_lease_get_vendor_specific(lease, &data, &data_len) >= 0) - metered = !!memmem(data, data_len, "ANDROID_METERED", NM_STRLEN("ANDROID_METERED")); - nm_ip4_config_set_metered(ip4_config, metered); + if (sd_dhcp_lease_get_vendor_specific(lease, &data, &data_len) >= 0) { + if (!!memmem(data, data_len, "ANDROID_METERED", NM_STRLEN("ANDROID_METERED"))) + nm_l3_config_data_set_metered(l3cd, TRUE); + } num = nm_sd_dhcp_lease_get_private_options(lease, &private_options); if (num > 0) { @@ -436,12 +427,18 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, if (code == NM_DHCP_OPTION_DHCP4_PRIVATE_PROXY_AUTODISCOVERY) { if (nm_dhcp_lease_data_parse_cstr(l_data, l_data_len, &l_data_len)) { - nm_dhcp_option_add_option_utf8safe_escape( - options, - AF_INET, - NM_DHCP_OPTION_DHCP4_PRIVATE_PROXY_AUTODISCOVERY, - l_data, - l_data_len); + gs_free char *to_free = NULL; + const char * escaped; + + escaped = + nm_utils_buf_utf8safe_escape((char *) l_data, l_data_len, 0, &to_free); + nm_dhcp_option_add_option(options, + AF_INET, + NM_DHCP_OPTION_DHCP4_PRIVATE_PROXY_AUTODISCOVERY, + escaped ?: ""); + + nm_l3_config_data_set_proxy_method(l3cd, NM_PROXY_CONFIG_METHOD_AUTO); + nm_l3_config_data_set_proxy_pac_url(l3cd, escaped ?: ""); } continue; } @@ -458,8 +455,12 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, nm_dhcp_option_take_option(options, AF_INET, code, option_string); } } - NM_SET_OUT(out_options, g_steal_pointer(&options)); - return g_steal_pointer(&ip4_config); + + nm_dhcp_option_add_requests_to_options(options, AF_INET); + + nm_l3_config_data_set_dhcp_lease_from_options(l3cd, AF_INET, g_steal_pointer(&options)); + + return g_steal_pointer(&l3cd); } /*****************************************************************************/ @@ -467,43 +468,38 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, static void bound4_handle(NMDhcpSystemd *self, gboolean extended) { - NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE(self); - const char * iface = nm_dhcp_client_get_iface(NM_DHCP_CLIENT(self)); - gs_unref_object NMIP4Config *ip4_config = NULL; - gs_unref_hashtable GHashTable *options = NULL; - sd_dhcp_lease * lease = NULL; - GError * error = NULL; + NMDhcpSystemdPrivate * priv = NM_DHCP_SYSTEMD_GET_PRIVATE(self); + const char * iface = nm_dhcp_client_get_iface(NM_DHCP_CLIENT(self)); + nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; + gs_unref_hashtable GHashTable *options = NULL; + sd_dhcp_lease * lease = NULL; + GError * error = NULL; if (sd_dhcp_client_get_lease(priv->client4, &lease) < 0 || !lease) { _LOGW("no lease!"); - nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL, NULL); + nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL); return; } _LOGD("lease available"); - ip4_config = lease_to_ip4_config(nm_dhcp_client_get_multi_idx(NM_DHCP_CLIENT(self)), - iface, - nm_dhcp_client_get_ifindex(NM_DHCP_CLIENT(self)), - lease, - nm_dhcp_client_get_route_table(NM_DHCP_CLIENT(self)), - nm_dhcp_client_get_route_metric(NM_DHCP_CLIENT(self)), - &options, - &error); - if (!ip4_config) { + l3cd = lease_to_ip4_config(nm_dhcp_client_get_multi_idx(NM_DHCP_CLIENT(self)), + iface, + nm_dhcp_client_get_ifindex(NM_DHCP_CLIENT(self)), + lease, + &error); + if (!l3cd) { _LOGW("%s", error->message); g_clear_error(&error); - nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL, NULL); + nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL); return; } - nm_dhcp_option_add_requests_to_options(options, AF_INET); dhcp_lease_save(lease, priv->lease_file); nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), extended ? NM_DHCP_STATE_EXTENDED : NM_DHCP_STATE_BOUND, - NM_IP_CONFIG_CAST(ip4_config), - options); + l3cd); } static int @@ -522,10 +518,10 @@ dhcp_event_cb(sd_dhcp_client *client, int event, gpointer user_data) switch (event) { case SD_DHCP_CLIENT_EVENT_EXPIRED: - nm_dhcp_client_set_state(NM_DHCP_CLIENT(user_data), NM_DHCP_STATE_EXPIRE, NULL, NULL); + nm_dhcp_client_set_state(NM_DHCP_CLIENT(user_data), NM_DHCP_STATE_EXPIRE, NULL); break; case SD_DHCP_CLIENT_EVENT_STOP: - nm_dhcp_client_set_state(NM_DHCP_CLIENT(user_data), NM_DHCP_STATE_FAIL, NULL, NULL); + nm_dhcp_client_set_state(NM_DHCP_CLIENT(user_data), NM_DHCP_STATE_FAIL, NULL); break; case SD_DHCP_CLIENT_EVENT_RENEW: case SD_DHCP_CLIENT_EVENT_IP_CHANGE: @@ -558,11 +554,12 @@ dhcp_event_cb(sd_dhcp_client *client, int event, gpointer user_data) } static gboolean -ip4_start(NMDhcpClient *client, const char *last_ip4_address, GError **error) +ip4_start(NMDhcpClient *client, GError **error) { - nm_auto(sd_dhcp_client_unrefp) sd_dhcp_client *sd_client = NULL; - NMDhcpSystemd * self = NM_DHCP_SYSTEMD(client); - NMDhcpSystemdPrivate * priv = NM_DHCP_SYSTEMD_GET_PRIVATE(self); + nm_auto(sd_dhcp_client_unrefp) sd_dhcp_client *sd_client = NULL; + NMDhcpSystemd * self = NM_DHCP_SYSTEMD(client); + NMDhcpSystemdPrivate * priv = NM_DHCP_SYSTEMD_GET_PRIVATE(self); + const NMDhcpClientConfig * client_config; gs_free char * lease_file = NULL; GBytes * hwaddr; const uint8_t * hwaddr_arr; @@ -584,6 +581,8 @@ ip4_start(NMDhcpClient *client, const char *last_ip4_address, GError **error) g_return_val_if_fail(!priv->client4, FALSE); g_return_val_if_fail(!priv->client6, FALSE); + client_config = nm_dhcp_client_get_config(client); + /* TODO: honor nm_dhcp_client_get_anycast_address() */ r = sd_dhcp_client_new(&sd_client, FALSE); @@ -600,7 +599,7 @@ ip4_start(NMDhcpClient *client, const char *last_ip4_address, GError **error) return FALSE; } - hwaddr = nm_dhcp_client_get_hw_addr(client); + hwaddr = client_config->hwaddr; if (!hwaddr || !(hwaddr_arr = g_bytes_get_data(hwaddr, &hwaddr_len)) || (arp_type = nm_utils_arp_type_detect_from_hwaddrlen(hwaddr_len)) < 0) { nm_utils_error_set_literal(error, NM_UTILS_ERROR_UNKNOWN, "invalid MAC address"); @@ -608,7 +607,8 @@ ip4_start(NMDhcpClient *client, const char *last_ip4_address, GError **error) } bcast_hwaddr_arr = NULL; - if ((bcast_hwaddr = nm_dhcp_client_get_broadcast_hw_addr(NM_DHCP_CLIENT(self)))) { + bcast_hwaddr = client_config->bcast_hwaddr; + if (bcast_hwaddr) { bcast_hwaddr_arr = g_bytes_get_data(bcast_hwaddr, &bcast_hwaddr_len); if (bcast_hwaddr_len != hwaddr_len) bcast_hwaddr_arr = NULL; @@ -632,12 +632,12 @@ ip4_start(NMDhcpClient *client, const char *last_ip4_address, GError **error) nm_dhcp_utils_get_leasefile_path(AF_INET, "internal", - nm_dhcp_client_get_iface(client), - nm_dhcp_client_get_uuid(client), + client_config->iface, + client_config->uuid, &lease_file); - if (last_ip4_address) - inet_pton(AF_INET, last_ip4_address, &last_addr); + if (client_config->v4.last_address) + inet_pton(AF_INET, client_config->v4.last_address, &last_addr); else { nm_auto(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL; @@ -646,9 +646,7 @@ ip4_start(NMDhcpClient *client, const char *last_ip4_address, GError **error) sd_dhcp_lease_get_address(lease, &last_addr); } - r = sd_dhcp_client_set_request_broadcast(sd_client, - NM_FLAGS_HAS(nm_dhcp_client_get_client_flags(client), - NM_DHCP_CLIENT_FLAGS_REQUEST_BROADCAST)); + r = sd_dhcp_client_set_request_broadcast(sd_client, client_config->v4.request_broadcast); nm_assert(r >= 0); if (last_addr.s_addr) { @@ -659,7 +657,7 @@ ip4_start(NMDhcpClient *client, const char *last_ip4_address, GError **error) } } - client_id = nm_dhcp_client_get_client_id(client); + client_id = client_config->client_id; if (!client_id) { client_id_new = nm_utils_dhcp_client_id_mac(arp_type, hwaddr_arr, hwaddr_len); client_id = client_id_new; @@ -694,7 +692,7 @@ ip4_start(NMDhcpClient *client, const char *last_ip4_address, GError **error) } } - hostname = nm_dhcp_client_get_hostname(client); + hostname = client_config->hostname; if (hostname) { /* FIXME: sd-dhcp decides which hostname/FQDN option to send (12 or 81) * only based on whether the hostname has a domain part or not. At the @@ -707,7 +705,7 @@ ip4_start(NMDhcpClient *client, const char *last_ip4_address, GError **error) } } - mud_url = nm_dhcp_client_get_mud_url(client); + mud_url = client_config->mud_url; if (mud_url) { r = sd_dhcp_client_set_mud_url(sd_client, mud_url); if (r < 0) { @@ -716,7 +714,7 @@ ip4_start(NMDhcpClient *client, const char *last_ip4_address, GError **error) } } - vendor_class_identifier = nm_dhcp_client_get_vendor_class_identifier(client); + vendor_class_identifier = client_config->vendor_class_identifier; if (vendor_class_identifier) { const char *option_data; gsize len; @@ -745,7 +743,7 @@ ip4_start(NMDhcpClient *client, const char *last_ip4_address, GError **error) g_free(priv->lease_file); priv->lease_file = g_steal_pointer(&lease_file); - nm_dhcp_client_set_client_id(client, client_id); + nm_dhcp_client_set_effective_client_id(client, client_id); r = sd_dhcp_client_start(priv->client4); if (r < 0) { @@ -759,32 +757,32 @@ ip4_start(NMDhcpClient *client, const char *last_ip4_address, GError **error) return TRUE; } -static NMIP6Config * +static NML3ConfigData * lease_to_ip6_config(NMDedupMultiIndex *multi_idx, const char * iface, int ifindex, sd_dhcp6_lease * lease, gboolean info_only, - GHashTable ** out_options, gint32 ts, GError ** error) { - gs_unref_object NMIP6Config *ip6_config = NULL; - gs_unref_hashtable GHashTable *options = NULL; + nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; + gs_unref_hashtable GHashTable *options = NULL; struct in6_addr tmp_addr; const struct in6_addr * dns; uint32_t lft_pref, lft_valid; char addr_str[NM_UTILS_INET_ADDRSTRLEN]; char ** domains; const char * s; - nm_auto_free_gstring GString *str = NULL; + nm_auto_free_gstring GString *str = NULL; + gboolean has_any_addresses = FALSE; int num, i; nm_assert(lease); - ip6_config = nm_ip6_config_new(multi_idx, ifindex); + l3cd = nm_l3_config_data_new(multi_idx, ifindex, NM_IP_CONFIG_SOURCE_DHCP); - options = out_options ? nm_dhcp_option_create_options_dict() : NULL; + options = nm_dhcp_option_create_options_dict(); sd_dhcp6_lease_reset_address_iter(lease); nm_gstring_prepare(&str); @@ -798,15 +796,19 @@ lease_to_ip6_config(NMDedupMultiIndex *multi_idx, .addr_source = NM_IP_CONFIG_SOURCE_DHCP, }; - nm_ip6_config_add_address(ip6_config, &address); + nm_l3_config_data_add_address_6(l3cd, &address); _nm_utils_inet6_ntop(&tmp_addr, addr_str); g_string_append(nm_gstring_add_space_delimiter(str), addr_str); - }; - if (str->len) + + has_any_addresses = TRUE; + } + + if (str->len) { nm_dhcp_option_add_option(options, AF_INET6, NM_DHCP_OPTION_DHCP6_NM_IP_ADDRESS, str->str); + } - if (!info_only && nm_ip6_config_get_num_addresses(ip6_config) == 0) { + if (!info_only && !has_any_addresses) { g_set_error_literal(error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, @@ -820,7 +822,7 @@ lease_to_ip6_config(NMDedupMultiIndex *multi_idx, for (i = 0; i < num; i++) { _nm_utils_inet6_ntop(&dns[i], addr_str); g_string_append(nm_gstring_add_space_delimiter(str), addr_str); - nm_ip6_config_add_nameserver(ip6_config, &dns[i]); + nm_l3_config_data_add_nameserver(l3cd, AF_INET6, &dns[i]); } nm_dhcp_option_add_option(options, AF_INET6, NM_DHCP_OPTION_DHCP6_DNS_SERVERS, str->str); } @@ -830,7 +832,7 @@ lease_to_ip6_config(NMDedupMultiIndex *multi_idx, nm_gstring_prepare(&str); for (i = 0; i < num; i++) { g_string_append(nm_gstring_add_space_delimiter(str), domains[i]); - nm_ip6_config_add_search(ip6_config, domains[i]); + nm_l3_config_data_add_search(l3cd, AF_INET6, domains[i]); } nm_dhcp_option_add_option(options, AF_INET6, NM_DHCP_OPTION_DHCP6_DOMAIN_LIST, str->str); } @@ -839,51 +841,48 @@ lease_to_ip6_config(NMDedupMultiIndex *multi_idx, nm_dhcp_option_add_option(options, AF_INET6, NM_DHCP_OPTION_DHCP6_FQDN, s); } - NM_SET_OUT(out_options, g_steal_pointer(&options)); - return g_steal_pointer(&ip6_config); + nm_l3_config_data_set_dhcp_lease_from_options(l3cd, AF_INET6, g_steal_pointer(&options)); + + return g_steal_pointer(&l3cd); } static void bound6_handle(NMDhcpSystemd *self) { - NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE(self); - const gint32 ts = nm_utils_get_monotonic_timestamp_sec(); - const char * iface = nm_dhcp_client_get_iface(NM_DHCP_CLIENT(self)); - gs_unref_object NMIP6Config *ip6_config = NULL; - gs_unref_hashtable GHashTable *options = NULL; - gs_free_error GError *error = NULL; - NMPlatformIP6Address prefix = {0}; - sd_dhcp6_lease * lease = NULL; + NMDhcpSystemdPrivate * priv = NM_DHCP_SYSTEMD_GET_PRIVATE(self); + const gint32 ts = nm_utils_get_monotonic_timestamp_sec(); + const char * iface = nm_dhcp_client_get_iface(NM_DHCP_CLIENT(self)); + const NMDhcpClientConfig *client_config; + nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; + gs_free_error GError *error = NULL; + NMPlatformIP6Address prefix = {0}; + sd_dhcp6_lease * lease = NULL; + + client_config = nm_dhcp_client_get_config(NM_DHCP_CLIENT(self)); if (sd_dhcp6_client_get_lease(priv->client6, &lease) < 0 || !lease) { _LOGW(" no lease!"); - nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL, NULL); + nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL); return; } _LOGD("lease available"); - ip6_config = - lease_to_ip6_config(nm_dhcp_client_get_multi_idx(NM_DHCP_CLIENT(self)), - iface, - nm_dhcp_client_get_ifindex(NM_DHCP_CLIENT(self)), - lease, - NM_FLAGS_HAS(nm_dhcp_client_get_client_flags(NM_DHCP_CLIENT(self)), - NM_DHCP_CLIENT_FLAGS_INFO_ONLY), - &options, - ts, - &error); - - if (!ip6_config) { + l3cd = lease_to_ip6_config(nm_dhcp_client_get_multi_idx(NM_DHCP_CLIENT(self)), + iface, + nm_dhcp_client_get_ifindex(NM_DHCP_CLIENT(self)), + lease, + client_config->v6.info_only, + ts, + &error); + + if (!l3cd) { _LOGW("%s", error->message); - nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL, NULL); + nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL); return; } - nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), - NM_DHCP_STATE_BOUND, - NM_IP_CONFIG_CAST(ip6_config), - options); + nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_BOUND, l3cd); sd_dhcp6_lease_reset_pd_prefix_iter(lease); while (!sd_dhcp6_lease_get_pd(lease, @@ -908,11 +907,11 @@ dhcp6_event_cb(sd_dhcp6_client *client, int event, gpointer user_data) switch (event) { case SD_DHCP6_CLIENT_EVENT_RETRANS_MAX: - nm_dhcp_client_set_state(NM_DHCP_CLIENT(user_data), NM_DHCP_STATE_TIMEOUT, NULL, NULL); + nm_dhcp_client_set_state(NM_DHCP_CLIENT(user_data), NM_DHCP_STATE_TIMEOUT, NULL); break; case SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE: case SD_DHCP6_CLIENT_EVENT_STOP: - nm_dhcp_client_set_state(NM_DHCP_CLIENT(user_data), NM_DHCP_STATE_FAIL, NULL, NULL); + nm_dhcp_client_set_state(NM_DHCP_CLIENT(user_data), NM_DHCP_STATE_FAIL, NULL); break; case SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE: case SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST: @@ -925,15 +924,12 @@ dhcp6_event_cb(sd_dhcp6_client *client, int event, gpointer user_data) } static gboolean -ip6_start(NMDhcpClient * client, - const struct in6_addr * ll_addr, - NMSettingIP6ConfigPrivacy privacy, - guint needed_prefixes, - GError ** error) +ip6_start(NMDhcpClient *client, GError **error) { NMDhcpSystemd * self = NM_DHCP_SYSTEMD(client); NMDhcpSystemdPrivate * priv = NM_DHCP_SYSTEMD_GET_PRIVATE(self); nm_auto(sd_dhcp6_client_unrefp) sd_dhcp6_client *sd_client = NULL; + const NMDhcpClientConfig * client_config; const char * hostname; const char * mud_url; int r, i; @@ -944,10 +940,12 @@ ip6_start(NMDhcpClient * client, g_return_val_if_fail(!priv->client4, FALSE); g_return_val_if_fail(!priv->client6, FALSE); + client_config = nm_dhcp_client_get_config(client); + /* TODO: honor nm_dhcp_client_get_anycast_address() */ - if (!(duid = nm_dhcp_client_get_client_id(client)) - || !(duid_arr = g_bytes_get_data(duid, &duid_len)) || duid_len < 2) { + duid = nm_dhcp_client_get_effective_client_id(client); + if (!duid || !(duid_arr = g_bytes_get_data(duid, &duid_len)) || duid_len < 2) { nm_utils_error_set_literal(error, NM_UTILS_ERROR_UNKNOWN, "missing DUID"); g_return_val_if_reached(FALSE); } @@ -960,13 +958,13 @@ ip6_start(NMDhcpClient * client, _LOGT("dhcp-client6: set %p", sd_client); - if (NM_FLAGS_HAS(nm_dhcp_client_get_client_flags(client), NM_DHCP_CLIENT_FLAGS_INFO_ONLY)) { + if (client_config->v6.info_only) { sd_dhcp6_client_set_address_request(sd_client, 0); - if (needed_prefixes == 0) + if (client_config->v6.needed_prefixes == 0) sd_dhcp6_client_set_information_request(sd_client, 1); } - r = sd_dhcp6_client_set_iaid(sd_client, nm_dhcp_client_get_iaid(client)); + r = sd_dhcp6_client_set_iaid(sd_client, client_config->v6.iaid); if (r < 0) { nm_utils_error_set_errno(error, r, "failed to set IAID: %s"); return FALSE; @@ -1002,7 +1000,7 @@ ip6_start(NMDhcpClient * client, } } - mud_url = nm_dhcp_client_get_mud_url(client); + mud_url = client_config->mud_url; if (mud_url) { r = sd_dhcp6_client_set_request_mud_url(sd_client, mud_url); if (r < 0) { @@ -1011,8 +1009,8 @@ ip6_start(NMDhcpClient * client, } } - if (needed_prefixes > 0) { - if (needed_prefixes > 1) + if (client_config->v6.needed_prefixes > 0) { + if (client_config->v6.needed_prefixes > 1) _LOGW("dhcp-client6: only one prefix request is supported"); /* FIXME: systemd-networkd API only allows to request a * single prefix */ @@ -1023,13 +1021,13 @@ ip6_start(NMDhcpClient * client, } } - r = sd_dhcp6_client_set_local_address(sd_client, ll_addr); + r = sd_dhcp6_client_set_local_address(sd_client, client_config->v6.ll_addr); if (r < 0) { nm_utils_error_set_errno(error, r, "failed to set local address: %s"); return FALSE; } - hostname = nm_dhcp_client_get_hostname(client); + hostname = client_config->hostname; r = sd_dhcp6_client_set_fqdn(sd_client, hostname); if (r < 0) { nm_utils_error_set_errno(error, r, "failed to set DHCP hostname: %s"); diff --git a/src/core/dhcp/nm-dhcp-utils.c b/src/core/dhcp/nm-dhcp-utils.c index 3cc6987ada..b1ff1b97a9 100644 --- a/src/core/dhcp/nm-dhcp-utils.c +++ b/src/core/dhcp/nm-dhcp-utils.c @@ -14,6 +14,7 @@ #include "libnm-systemd-shared/nm-sd-utils-shared.h" #include "nm-dhcp-utils.h" +#include "nm-l3-config-data.h" #include "nm-utils.h" #include "nm-config.h" #include "NetworkManagerUtils.h" @@ -24,12 +25,10 @@ /*****************************************************************************/ static gboolean -ip4_process_dhcpcd_rfc3442_routes(const char * iface, - const char * str, - guint32 route_table, - guint32 route_metric, - NMIP4Config *ip4_config, - guint32 * gwaddr) +ip4_process_dhcpcd_rfc3442_routes(const char * iface, + const char * str, + NML3ConfigData *l3cd, + guint32 * gwaddr) { gs_free const char **routes = NULL; const char ** r; @@ -45,10 +44,9 @@ ip4_process_dhcpcd_rfc3442_routes(const char * iface, } for (r = routes; *r; r += 2) { - char * slash; - NMPlatformIP4Route route; - int rt_cidr = 32; - guint32 rt_addr, rt_route; + char * slash; + int rt_cidr = 32; + guint32 rt_addr, rt_route; slash = strchr(*r, '/'); if (slash) { @@ -89,14 +87,18 @@ ip4_process_dhcpcd_rfc3442_routes(const char * iface, *r, rt_cidr, *(r + 1)); - memset(&route, 0, sizeof(route)); - route.network = nm_utils_ip4_address_clear_host_address(rt_addr, rt_cidr); - route.plen = rt_cidr; - route.gateway = rt_route; - route.rt_source = NM_IP_CONFIG_SOURCE_DHCP; - route.metric = route_metric; - route.table_coerced = nm_platform_route_table_coerce(route_table); - nm_ip4_config_add_route(ip4_config, &route, NULL); + + nm_l3_config_data_add_route_4( + l3cd, + &((const NMPlatformIP4Route){ + .network = nm_utils_ip4_address_clear_host_address(rt_addr, rt_cidr), + .plen = rt_cidr, + .gateway = rt_route, + .rt_source = NM_IP_CONFIG_SOURCE_DHCP, + .metric_any = TRUE, + .table_any = TRUE, + + })); } } @@ -153,12 +155,10 @@ process_dhclient_rfc3442_route(const char *const **p_octets, NMPlatformIP4Route } static gboolean -ip4_process_dhclient_rfc3442_routes(const char * iface, - const char * str, - guint32 route_table, - guint32 route_metric, - NMIP4Config *ip4_config, - guint32 * gwaddr) +ip4_process_dhclient_rfc3442_routes(const char * iface, + const char * str, + NML3ConfigData *l3cd, + guint32 * gwaddr) { gs_free const char **octets = NULL; const char *const * o; @@ -189,9 +189,12 @@ ip4_process_dhclient_rfc3442_routes(const char * iface, /* normal route */ route.rt_source = NM_IP_CONFIG_SOURCE_DHCP; - route.metric = route_metric; - route.table_coerced = nm_platform_route_table_coerce(route_table); - nm_ip4_config_add_route(ip4_config, &route, NULL); + route.table_any = TRUE; + route.table_coerced = 0; + route.metric_any = TRUE; + route.metric = 0; + + nm_l3_config_data_add_route_4(l3cd, &route); _LOG2I(LOGD_DHCP4, iface, @@ -206,17 +209,15 @@ ip4_process_dhclient_rfc3442_routes(const char * iface, } static gboolean -ip4_process_classless_routes(const char * iface, - GHashTable * options, - guint32 route_table, - guint32 route_metric, - NMIP4Config *ip4_config, - guint32 * gwaddr) +ip4_process_classless_routes(const char * iface, + GHashTable * options, + NML3ConfigData *l3cd, + guint32 * gwaddr) { const char *str, *p; g_return_val_if_fail(options != NULL, FALSE); - g_return_val_if_fail(ip4_config != NULL, FALSE); + g_return_val_if_fail(l3cd != NULL, FALSE); *gwaddr = 0; @@ -265,28 +266,14 @@ ip4_process_classless_routes(const char * iface, if (strchr(str, '/')) { /* dhcpcd format */ - return ip4_process_dhcpcd_rfc3442_routes(iface, - str, - route_table, - route_metric, - ip4_config, - gwaddr); + return ip4_process_dhcpcd_rfc3442_routes(iface, str, l3cd, gwaddr); } - return ip4_process_dhclient_rfc3442_routes(iface, - str, - route_table, - route_metric, - ip4_config, - gwaddr); + return ip4_process_dhclient_rfc3442_routes(iface, str, l3cd, gwaddr); } static void -process_classful_routes(const char * iface, - GHashTable * options, - guint32 route_table, - guint32 route_metric, - NMIP4Config *ip4_config) +process_classful_routes(const char *iface, GHashTable *options, NML3ConfigData *l3cd) { gs_free const char **searches = NULL; const char ** s; @@ -320,8 +307,10 @@ process_classful_routes(const char * iface, // FIXME: ensure the IP address and route are sane - memset(&route, 0, sizeof(route)); - route.network = rt_addr; + route = (NMPlatformIP4Route){ + .network = rt_addr, + }; + /* RFC 2132, updated by RFC 3442: * The Static Routes option (option 33) does not provide a subnet mask * for each route - it is assumed that the subnet mask is implicit in @@ -333,12 +322,15 @@ process_classful_routes(const char * iface, } route.gateway = rt_route; route.rt_source = NM_IP_CONFIG_SOURCE_DHCP; - route.metric = route_metric; - route.table_coerced = nm_platform_route_table_coerce(route_table); + route.table_any = TRUE; + route.table_coerced = 0; + route.metric_any = TRUE; + route.metric = 0; route.network = nm_utils_ip4_address_clear_host_address(route.network, route.plen); - nm_ip4_config_add_route(ip4_config, &route, NULL); + nm_l3_config_data_add_route_4(l3cd, &route); + _LOG2I(LOGD_DHCP, iface, " static route %s", @@ -347,7 +339,7 @@ process_classful_routes(const char * iface, } static void -process_domain_search(const char *iface, const char *str, GFunc add_func, gpointer user_data) +process_domain_search(int addr_family, const char *iface, const char *str, NML3ConfigData *l3cd) { gs_free const char **searches = NULL; gs_free char * unescaped = NULL; @@ -356,7 +348,7 @@ process_domain_search(const char *iface, const char *str, GFunc add_func, gpoint int i; g_return_if_fail(str != NULL); - g_return_if_fail(add_func != NULL); + nm_assert(l3cd); unescaped = g_strdup(str); @@ -379,46 +371,43 @@ process_domain_search(const char *iface, const char *str, GFunc add_func, gpoint searches = nm_strsplit_set(unescaped, " "); for (s = searches; searches && *s; s++) { _LOG2I(LOGD_DHCP, iface, " domain search '%s'", *s); - add_func((gpointer) *s, user_data); + nm_l3_config_data_add_search(l3cd, addr_family, *s); } } -static void -ip4_add_domain_search(gpointer data, gpointer user_data) -{ - nm_ip4_config_add_search(NM_IP4_CONFIG(user_data), (const char *) data); -} - -NMIP4Config * +NML3ConfigData * nm_dhcp_utils_ip4_config_from_options(NMDedupMultiIndex *multi_idx, int ifindex, const char * iface, - GHashTable * options, - guint32 route_table, - guint32 route_metric) + GHashTable * options) { - gs_unref_object NMIP4Config *ip4_config = NULL; - guint32 tmp_addr; - in_addr_t addr; - NMPlatformIP4Address address; - char * str = NULL; - gboolean gateway_has = FALSE; - guint32 gateway = 0; - guint8 plen = 0; - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; + nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; + guint32 tmp_addr; + in_addr_t addr; + NMPlatformIP4Address address; + char * str = NULL; + gboolean gateway_has = FALSE; + guint32 gateway = 0; + guint8 plen = 0; + char sbuf[NM_UTILS_INET_ADDRSTRLEN]; + guint32 now; g_return_val_if_fail(options != NULL, NULL); - ip4_config = nm_ip4_config_new(multi_idx, ifindex); - memset(&address, 0, sizeof(address)); - address.timestamp = nm_utils_get_monotonic_timestamp_sec(); + l3cd = nm_l3_config_data_new(multi_idx, ifindex, NM_IP_CONFIG_SOURCE_DHCP); + + now = nm_utils_get_monotonic_timestamp_sec(); + + address = (NMPlatformIP4Address){ + .timestamp = now, + }; str = g_hash_table_lookup(options, "ip_address"); - if (str && (inet_pton(AF_INET, str, &addr) > 0)) - _LOG2I(LOGD_DHCP4, iface, " address %s", str); - else + if (!str || !nm_utils_parse_inaddr_bin(AF_INET, str, NULL, &addr)) return NULL; + _LOG2I(LOGD_DHCP4, iface, " address %s", str); + str = g_hash_table_lookup(options, "subnet_mask"); if (str && (inet_pton(AF_INET, str, &tmp_addr) > 0)) { plen = nm_utils_ip4_netmask_to_prefix(tmp_addr); @@ -433,13 +422,8 @@ nm_dhcp_utils_ip4_config_from_options(NMDedupMultiIndex *multi_idx, /* Routes: if the server returns classless static routes, we MUST ignore * the 'static_routes' option. */ - if (!ip4_process_classless_routes(iface, - options, - route_table, - route_metric, - ip4_config, - &gateway)) - process_classful_routes(iface, options, route_table, route_metric, ip4_config); + if (!ip4_process_classless_routes(iface, options, l3cd, &gateway)) + process_classful_routes(iface, options, l3cd); if (gateway) { _LOG2I(LOGD_DHCP4, iface, " gateway %s", _nm_utils_inet4_ntop(gateway, sbuf)); @@ -453,7 +437,7 @@ nm_dhcp_utils_ip4_config_from_options(NMDedupMultiIndex *multi_idx, gs_free const char **routers = nm_strsplit_set(str, " "); const char ** s; - for (s = routers; routers && *s; s++) { + for (s = routers; *s; s++) { /* FIXME: how to handle multiple routers? */ if (inet_pton(AF_INET, *s, &gateway) > 0) { _LOG2I(LOGD_DHCP4, iface, " gateway %s", *s); @@ -469,11 +453,13 @@ nm_dhcp_utils_ip4_config_from_options(NMDedupMultiIndex *multi_idx, const NMPlatformIP4Route r = { .rt_source = NM_IP_CONFIG_SOURCE_DHCP, .gateway = gateway, - .table_coerced = nm_platform_route_table_coerce(route_table), - .metric = route_metric, + .table_any = TRUE, + .table_coerced = 0, + .metric_any = TRUE, + .metric = 0, }; - nm_ip4_config_add_route(ip4_config, &r, NULL); + nm_l3_config_data_add_route_4(l3cd, &r); } str = g_hash_table_lookup(options, "dhcp_lease_time"); @@ -483,7 +469,8 @@ nm_dhcp_utils_ip4_config_from_options(NMDedupMultiIndex *multi_idx, } address.addr_source = NM_IP_CONFIG_SOURCE_DHCP; - nm_ip4_config_add_address(ip4_config, &address); + + nm_l3_config_data_add_address_4(l3cd, &address); str = g_hash_table_lookup(options, "host_name"); if (str) @@ -497,7 +484,7 @@ nm_dhcp_utils_ip4_config_from_options(NMDedupMultiIndex *multi_idx, for (s = dns; dns && *s; s++) { if (inet_pton(AF_INET, *s, &tmp_addr) > 0) { if (tmp_addr) { - nm_ip4_config_add_nameserver(ip4_config, tmp_addr); + nm_l3_config_data_add_nameserver(l3cd, AF_INET, &tmp_addr); _LOG2I(LOGD_DHCP4, iface, " nameserver '%s'", *s); } } else @@ -512,13 +499,13 @@ nm_dhcp_utils_ip4_config_from_options(NMDedupMultiIndex *multi_idx, for (s = domains; domains && *s; s++) { _LOG2I(LOGD_DHCP4, iface, " domain name '%s'", *s); - nm_ip4_config_add_domain(ip4_config, *s); + nm_l3_config_data_add_domain(l3cd, AF_INET, *s); } } str = g_hash_table_lookup(options, "domain_search"); if (str) - process_domain_search(iface, str, ip4_add_domain_search, ip4_config); + process_domain_search(AF_INET, iface, str, l3cd); str = g_hash_table_lookup(options, "netbios_name_servers"); if (str) { @@ -528,7 +515,7 @@ nm_dhcp_utils_ip4_config_from_options(NMDedupMultiIndex *multi_idx, for (s = nbns; nbns && *s; s++) { if (inet_pton(AF_INET, *s, &tmp_addr) > 0) { if (tmp_addr) { - nm_ip4_config_add_wins(ip4_config, tmp_addr); + nm_l3_config_data_add_wins(l3cd, tmp_addr); _LOG2I(LOGD_DHCP4, iface, " wins '%s'", *s); } } else @@ -546,13 +533,13 @@ nm_dhcp_utils_ip4_config_from_options(NMDedupMultiIndex *multi_idx, return NULL; if (int_mtu > 576) - nm_ip4_config_set_mtu(ip4_config, int_mtu, NM_IP_CONFIG_SOURCE_DHCP); + nm_l3_config_data_set_mtu(l3cd, int_mtu); } str = g_hash_table_lookup(options, "nis_domain"); if (str) { _LOG2I(LOGD_DHCP4, iface, " NIS domain '%s'", str); - nm_ip4_config_set_nis_domain(ip4_config, str); + nm_l3_config_data_add_domain(l3cd, AF_INET, str); } str = g_hash_table_lookup(options, "nis_servers"); @@ -563,7 +550,7 @@ nm_dhcp_utils_ip4_config_from_options(NMDedupMultiIndex *multi_idx, for (s = nis; nis && *s; s++) { if (inet_pton(AF_INET, *s, &tmp_addr) > 0) { if (tmp_addr) { - nm_ip4_config_add_nis_server(ip4_config, tmp_addr); + nm_l3_config_data_add_nis_server(l3cd, tmp_addr); _LOG2I(LOGD_DHCP4, iface, " nis '%s'", *s); } } else @@ -572,19 +559,20 @@ nm_dhcp_utils_ip4_config_from_options(NMDedupMultiIndex *multi_idx, } str = g_hash_table_lookup(options, "vendor_encapsulated_options"); - nm_ip4_config_set_metered(ip4_config, str && strstr(str, "ANDROID_METERED")); + if (str && strstr(str, "ANDROID_METERED")) + nm_l3_config_data_set_metered(l3cd, TRUE); - return g_steal_pointer(&ip4_config); + str = g_hash_table_lookup(options, "wpad"); + if (str) { + nm_l3_config_data_set_proxy_method(l3cd, NM_PROXY_CONFIG_METHOD_AUTO); + nm_l3_config_data_set_proxy_pac_url(l3cd, str); + } + + return g_steal_pointer(&l3cd); } /*****************************************************************************/ -static void -ip6_add_domain_search(gpointer data, gpointer user_data) -{ - nm_ip6_config_add_search(NM_IP6_CONFIG(user_data), (const char *) data); -} - NMPlatformIP6Address nm_dhcp_utils_ip6_prefix_from_options(GHashTable *options) { @@ -635,25 +623,29 @@ nm_dhcp_utils_ip6_prefix_from_options(GHashTable *options) return address; } -NMIP6Config * +NML3ConfigData * nm_dhcp_utils_ip6_config_from_options(NMDedupMultiIndex *multi_idx, int ifindex, const char * iface, GHashTable * options, gboolean info_only) { - gs_unref_object NMIP6Config *ip6_config = NULL; - struct in6_addr tmp_addr; - NMPlatformIP6Address address; - char * str = NULL; + nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; + struct in6_addr tmp_addr; + NMPlatformIP6Address address; + char * str = NULL; + guint32 now; g_return_val_if_fail(options != NULL, NULL); - memset(&address, 0, sizeof(address)); - address.plen = 128; - address.timestamp = nm_utils_get_monotonic_timestamp_sec(); + now = nm_utils_get_monotonic_timestamp_sec(); - ip6_config = nm_ip6_config_new(multi_idx, ifindex); + address = (NMPlatformIP6Address){ + .plen = 128, + .timestamp = now, + }; + + l3cd = nm_l3_config_data_new(multi_idx, ifindex, NM_IP_CONFIG_SOURCE_DHCP); str = g_hash_table_lookup(options, "max_life"); if (str) { @@ -676,7 +668,7 @@ nm_dhcp_utils_ip6_config_from_options(NMDedupMultiIndex *multi_idx, address.address = tmp_addr; address.addr_source = NM_IP_CONFIG_SOURCE_DHCP; - nm_ip6_config_add_address(ip6_config, &address); + nm_l3_config_data_add_address_6(l3cd, &address); _LOG2I(LOGD_DHCP6, iface, " address %s", str); } else if (info_only == FALSE) { /* No address in Managed mode is a hard error */ @@ -695,7 +687,7 @@ nm_dhcp_utils_ip6_config_from_options(NMDedupMultiIndex *multi_idx, for (s = dns; dns && *s; s++) { if (inet_pton(AF_INET6, *s, &tmp_addr) > 0) { if (!IN6_IS_ADDR_UNSPECIFIED(&tmp_addr)) { - nm_ip6_config_add_nameserver(ip6_config, &tmp_addr); + nm_l3_config_data_add_nameserver(l3cd, AF_INET6, &tmp_addr); _LOG2I(LOGD_DHCP6, iface, " nameserver '%s'", *s); } } else @@ -705,9 +697,9 @@ nm_dhcp_utils_ip6_config_from_options(NMDedupMultiIndex *multi_idx, str = g_hash_table_lookup(options, "dhcp6_domain_search"); if (str) - process_domain_search(iface, str, ip6_add_domain_search, ip6_config); + process_domain_search(AF_INET6, iface, str, l3cd); - return g_steal_pointer(&ip6_config); + return g_steal_pointer(&l3cd); } char * @@ -838,6 +830,65 @@ nm_dhcp_utils_get_dhcp6_event_id(GHashTable *lease) return g_strdup_printf("%s|%s", iaid, start); } +gboolean +nm_dhcp_utils_merge_new_dhcp6_lease(const NML3ConfigData * l3cd_old, + const NML3ConfigData * l3cd_new, + const NML3ConfigData **out_l3cd_merged) +{ + nm_auto_unref_l3cd_init NML3ConfigData *l3cd_merged = NULL; + const NMPlatformIP6Address * addr; + NMDhcpLease * lease_old; + NMDhcpLease * lease_new; + NMDedupMultiIter iter; + const char * start; + const char * iaid; + + nm_assert(out_l3cd_merged); + nm_assert(!*out_l3cd_merged); + + if (!l3cd_old) + return FALSE; + if (!l3cd_new) + return FALSE; + + lease_new = nm_l3_config_data_get_dhcp_lease(l3cd_new, AF_INET6); + if (!lease_new) + return FALSE; + + lease_old = nm_l3_config_data_get_dhcp_lease(l3cd_old, AF_INET6); + if (!lease_old) + return FALSE; + + start = nm_dhcp_lease_lookup_option(lease_new, "life_starts"); + if (!start) + return FALSE; + iaid = nm_dhcp_lease_lookup_option(lease_new, "iaid"); + if (!iaid) + return FALSE; + + if (!nm_streq0(start, nm_dhcp_lease_lookup_option(lease_old, "life_starts"))) + return FALSE; + if (!nm_streq0(iaid, nm_dhcp_lease_lookup_option(lease_old, "iaid"))) + return FALSE; + + /* If the server sends multiple IPv6 addresses, we receive a state + * changed event for each of them. Use the event ID to merge IPv6 + * addresses from the same transaction into a single configuration. + **/ + + l3cd_merged = nm_l3_config_data_new_clone(l3cd_old, -1); + + nm_l3_config_data_iter_ip6_address_for_each (&iter, l3cd_new, &addr) + nm_l3_config_data_add_address_6(l3cd_merged, addr); + + /* FIXME(l3cfg): Note that we keep the original NMDhcpLease. All we take from the new lease are the + * addresses. Maybe this is not right and we should merge the leases too?? */ + nm_l3_config_data_set_dhcp_lease(l3cd_merged, AF_INET6, lease_old); + + *out_l3cd_merged = nm_l3_config_data_ref_and_seal(g_steal_pointer(&l3cd_merged)); + return TRUE; +} + /*****************************************************************************/ gboolean diff --git a/src/core/dhcp/nm-dhcp-utils.h b/src/core/dhcp/nm-dhcp-utils.h index 69715f90fe..bee10de3f6 100644 --- a/src/core/dhcp/nm-dhcp-utils.h +++ b/src/core/dhcp/nm-dhcp-utils.h @@ -8,21 +8,18 @@ #include <stdlib.h> -#include "nm-ip4-config.h" -#include "nm-ip6-config.h" - -NMIP4Config *nm_dhcp_utils_ip4_config_from_options(struct _NMDedupMultiIndex *multi_idx, - int ifindex, - const char * iface, - GHashTable * options, - guint32 route_table, - guint32 route_metric); - -NMIP6Config *nm_dhcp_utils_ip6_config_from_options(struct _NMDedupMultiIndex *multi_idx, - int ifindex, - const char * iface, - GHashTable * options, - gboolean info_only); +#include "nm-l3-config-data.h" + +NML3ConfigData *nm_dhcp_utils_ip4_config_from_options(struct _NMDedupMultiIndex *multi_idx, + int ifindex, + const char * iface, + GHashTable * options); + +NML3ConfigData *nm_dhcp_utils_ip6_config_from_options(struct _NMDedupMultiIndex *multi_idx, + int ifindex, + const char * iface, + GHashTable * options, + gboolean info_only); NMPlatformIP6Address nm_dhcp_utils_ip6_prefix_from_options(GHashTable *options); @@ -38,6 +35,10 @@ gboolean nm_dhcp_utils_get_leasefile_path(int addr_family, char *nm_dhcp_utils_get_dhcp6_event_id(GHashTable *lease); +gboolean nm_dhcp_utils_merge_new_dhcp6_lease(const NML3ConfigData * l3cd_old, + const NML3ConfigData * l3cd_new, + const NML3ConfigData **out_l3cd_merged); + /*****************************************************************************/ static inline gboolean diff --git a/src/core/dhcp/tests/test-dhcp-dhclient.c b/src/core/dhcp/tests/test-dhcp-dhclient.c index e9a6209644..803933ff04 100644 --- a/src/core/dhcp/tests/test-dhcp-dhclient.c +++ b/src/core/dhcp/tests/test-dhcp-dhclient.c @@ -15,7 +15,6 @@ #include "dhcp/nm-dhcp-dhclient-utils.h" #include "dhcp/nm-dhcp-utils.h" #include "nm-utils.h" -#include "nm-ip4-config.h" #include "libnm-platform/nm-platform.h" #include "nm-test-utils-core.h" diff --git a/src/core/dhcp/tests/test-dhcp-utils.c b/src/core/dhcp/tests/test-dhcp-utils.c index 4d47e7e283..0fab5c15ad 100644 --- a/src/core/dhcp/tests/test-dhcp-utils.c +++ b/src/core/dhcp/tests/test-dhcp-utils.c @@ -20,20 +20,18 @@ /*****************************************************************************/ -static NMIP4Config * -_ip4_config_from_options(int ifindex, const char *iface, GHashTable *options, guint32 route_metric) +static const NML3ConfigData * +_ip4_config_from_options(int ifindex, const char *iface, GHashTable *options) { nm_auto_unref_dedup_multi_index NMDedupMultiIndex *multi_idx = nm_dedup_multi_index_new(); - NMIP4Config * config; - - config = nm_dhcp_utils_ip4_config_from_options(multi_idx, - ifindex, - iface, - options, - RT_TABLE_MAIN, - route_metric); - g_assert(config); - return config; + NML3ConfigData * l3cd; + + l3cd = nm_dhcp_utils_ip4_config_from_options(multi_idx, ifindex, iface, options); + g_assert(NM_IS_L3_CONFIG_DATA(l3cd)); + g_assert(!nm_l3_config_data_is_sealed(l3cd)); + if (nmtst_get_rand_bool()) + nm_l3_config_data_seal(l3cd); + return l3cd; } typedef struct { @@ -74,58 +72,57 @@ static const Option generic_options[] = { static void test_generic_options(void) { - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const NMPlatformIP4Address * address; - const NMPlatformIP4Route * route; - guint32 tmp; - const char * expected_addr = "192.168.1.106"; - const char * expected_gw = "192.168.1.1"; - const char * expected_dns1 = "216.254.95.2"; - const char * expected_dns2 = "216.231.41.2"; - const char * expected_search1 = "foobar.com"; - const char * expected_search2 = "blah.foobar.com"; - const char * expected_route1_dest = "10.1.1.5"; - const char * expected_route1_gw = "10.1.1.1"; - const char * expected_route2_dest = "100.99.88.56"; - const char * expected_route2_gw = "10.1.1.1"; - - options = fill_table(generic_options, NULL); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); - - /* IP4 address */ - g_assert_cmpint(nm_ip4_config_get_num_addresses(ip4_config), ==, 1); - address = _nmtst_ip4_config_get_address(ip4_config, 0); + gs_unref_hashtable GHashTable *options = NULL; + nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; + const NMPlatformIP4Address * address; + const NMPlatformIP4Route * route; + guint32 tmp; + const char * expected_addr = "192.168.1.106"; + const char * expected_gw = "192.168.1.1"; + const char * expected_dns1 = "216.254.95.2"; + const char * expected_dns2 = "216.231.41.2"; + const char * expected_search1 = "foobar.com"; + const char * expected_search2 = "blah.foobar.com"; + const char * expected_route1_dest = "10.1.1.5"; + const char * expected_route1_gw = "10.1.1.1"; + const char * expected_route2_dest = "100.99.88.56"; + const char * expected_route2_gw = "10.1.1.1"; + const char *const * strarr; + const in_addr_t * ia_arr; + guint u; + + options = fill_table(generic_options, NULL); + l3cd = _ip4_config_from_options(1, "eth0", options); + + g_assert_cmpint(nm_l3_config_data_get_num_addresses(l3cd, AF_INET), ==, 1); + address = nmtst_l3_config_data_get_address_at_4(l3cd, 0); g_assert(inet_pton(AF_INET, expected_addr, &tmp) > 0); g_assert(address->address == tmp); g_assert(address->peer_address == tmp); g_assert_cmpint(address->plen, ==, 24); - /* Gateway */ - g_assert(inet_pton(AF_INET, expected_gw, &tmp) > 0); - g_assert(nmtst_ip4_config_get_gateway(ip4_config) == tmp); + nmtst_assert_ip_address(AF_INET, + nmtst_l3_config_data_get_best_gateway(l3cd, AF_INET), + expected_gw); - g_assert_cmpint(nm_ip4_config_get_num_wins(ip4_config), ==, 0); + g_assert(!nm_l3_config_data_get_wins(l3cd, &u)); + g_assert_cmpint(u, ==, 0); - g_assert_cmpint(nm_ip4_config_get_mtu(ip4_config), ==, 987); + g_assert_cmpint(nm_l3_config_data_get_mtu(l3cd), ==, 987); - /* Domain searches */ - g_assert_cmpint(nm_ip4_config_get_num_searches(ip4_config), ==, 2); - g_assert_cmpstr(nm_ip4_config_get_search(ip4_config, 0), ==, expected_search1); - g_assert_cmpstr(nm_ip4_config_get_search(ip4_config, 1), ==, expected_search2); + strarr = nm_l3_config_data_get_searches(l3cd, AF_INET, &u); + g_assert_cmpint(u, ==, 2); + g_assert_cmpstr(strarr[0], ==, expected_search1); + g_assert_cmpstr(strarr[1], ==, expected_search2); - /* DNS servers */ - g_assert_cmpint(nm_ip4_config_get_num_nameservers(ip4_config), ==, 2); - g_assert(inet_pton(AF_INET, expected_dns1, &tmp) > 0); - g_assert(nm_ip4_config_get_nameserver(ip4_config, 0) == tmp); - g_assert(inet_pton(AF_INET, expected_dns2, &tmp) > 0); - g_assert(nm_ip4_config_get_nameserver(ip4_config, 1) == tmp); + ia_arr = nm_l3_config_data_get_nameservers(l3cd, AF_INET, &u); + g_assert_cmpint(u, ==, 2); + nmtst_assert_ip4_address(ia_arr[0], expected_dns1); + nmtst_assert_ip4_address(ia_arr[1], expected_dns2); - /* Routes */ - g_assert_cmpint(nm_ip4_config_get_num_routes(ip4_config), ==, 3); + g_assert_cmpint(nm_l3_config_data_get_num_routes(l3cd, AF_INET), ==, 3); - /* Route #1 */ - route = _nmtst_ip4_config_get_route(ip4_config, 0); + route = nmtst_l3_config_data_get_route_at_4(l3cd, 0); g_assert(inet_pton(AF_INET, expected_route1_dest, &tmp) > 0); g_assert(route->network == tmp); g_assert(inet_pton(AF_INET, expected_route1_gw, &tmp) > 0); @@ -133,69 +130,63 @@ test_generic_options(void) g_assert_cmpint(route->plen, ==, 32); g_assert_cmpint(route->metric, ==, 0); - /* Route #2 */ - route = _nmtst_ip4_config_get_route(ip4_config, 1); + route = nmtst_l3_config_data_get_route_at_4(l3cd, 1); g_assert(route->network == nmtst_inet4_from_string(expected_route2_dest)); g_assert(route->gateway == nmtst_inet4_from_string(expected_route2_gw)); g_assert_cmpint(route->plen, ==, 32); g_assert_cmpint(route->metric, ==, 0); - route = _nmtst_ip4_config_get_route(ip4_config, 2); + route = nmtst_l3_config_data_get_route_at_4(l3cd, 2); g_assert(route->network == nmtst_inet4_from_string("0.0.0.0")); g_assert(route->gateway == nmtst_inet4_from_string("192.168.1.1")); g_assert_cmpint(route->plen, ==, 0); g_assert_cmpint(route->metric, ==, 0); - - g_hash_table_destroy(options); } static void test_wins_options(void) { - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const NMPlatformIP4Address * address; - guint32 tmp; - const char * expected_wins1 = "63.12.199.5"; - const char * expected_wins2 = "150.4.88.120"; - static const Option data[] = {{"netbios_name_servers", "63.12.199.5 150.4.88.120"}, + gs_unref_hashtable GHashTable *options = NULL; + nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; + const NMPlatformIP4Address * address; + const char * expected_wins1 = "63.12.199.5"; + const char * expected_wins2 = "150.4.88.120"; + static const Option data[] = {{"netbios_name_servers", "63.12.199.5 150.4.88.120"}, {NULL, NULL}}; + const in_addr_t * ia_arr; + guint u; - options = fill_table(generic_options, NULL); - options = fill_table(data, options); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); + options = fill_table(generic_options, NULL); + options = fill_table(data, options); + l3cd = _ip4_config_from_options(1, "eth0", options); - /* IP4 address */ - g_assert_cmpint(nm_ip4_config_get_num_addresses(ip4_config), ==, 1); - address = _nmtst_ip4_config_get_address(ip4_config, 0); + g_assert_cmpint(nm_l3_config_data_get_num_addresses(l3cd, AF_INET), ==, 1); + address = nmtst_l3_config_data_get_address_at_4(l3cd, 0); g_assert(address); - g_assert_cmpint(nm_ip4_config_get_num_wins(ip4_config), ==, 2); - g_assert(inet_pton(AF_INET, expected_wins1, &tmp) > 0); - g_assert(nm_ip4_config_get_wins(ip4_config, 0) == tmp); - g_assert(inet_pton(AF_INET, expected_wins2, &tmp) > 0); - g_assert(nm_ip4_config_get_wins(ip4_config, 1) == tmp); - g_hash_table_destroy(options); + ia_arr = nm_l3_config_data_get_wins(l3cd, &u); + g_assert_cmpint(u, ==, 2); + nmtst_assert_ip4_address(ia_arr[0], expected_wins1); + nmtst_assert_ip4_address(ia_arr[1], expected_wins2); } static void test_vendor_option_metered(void) { - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; + gs_unref_hashtable GHashTable *options = NULL; + nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; static const Option data[] = {{"vendor_encapsulated_options", "ANDROID_METERED"}, {NULL, NULL}}; - options = fill_table(generic_options, NULL); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); - g_assert(nm_ip4_config_get_metered(ip4_config) == FALSE); - g_hash_table_destroy(options); - g_clear_object(&ip4_config); - - options = fill_table(generic_options, NULL); - options = fill_table(data, options); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); - g_assert(nm_ip4_config_get_metered(ip4_config) == TRUE); - g_hash_table_destroy(options); + options = fill_table(generic_options, NULL); + l3cd = _ip4_config_from_options(1, "eth0", options); + g_assert(nm_l3_config_data_get_metered(l3cd) == NM_TERNARY_DEFAULT); + nm_clear_pointer(&options, g_hash_table_destroy); + nm_clear_l3cd(&l3cd); + + options = fill_table(generic_options, NULL); + options = fill_table(data, options); + l3cd = _ip4_config_from_options(1, "eth0", options); + g_assert(nm_l3_config_data_get_metered(l3cd) == TRUE); } static void @@ -252,18 +243,18 @@ test_parse_search_list(void) } static void -ip4_test_route(NMIP4Config *ip4_config, - guint route_num, - const char * expected_dest, - const char * expected_gw, - guint expected_prefix) +ip4_test_route(const NML3ConfigData *l3cd, + guint route_num, + const char * expected_dest, + const char * expected_gw, + guint expected_prefix) { const NMPlatformIP4Route *route; guint32 tmp; g_assert(expected_prefix <= 32); - route = _nmtst_ip4_config_get_route(ip4_config, route_num); + route = nmtst_l3_config_data_get_route_at_4(l3cd, route_num); g_assert(inet_pton(AF_INET, expected_dest, &tmp) > 0); g_assert(route->network == tmp); g_assert(inet_pton(AF_INET, expected_gw, &tmp) > 0); @@ -272,110 +263,105 @@ ip4_test_route(NMIP4Config *ip4_config, g_assert_cmpint(route->metric, ==, 0); } -static void -ip4_test_gateway(NMIP4Config *ip4_config, const char *expected_gw) -{ - guint32 tmp; - - g_assert_cmpint(nm_ip4_config_get_num_addresses(ip4_config), ==, 1); - g_assert(inet_pton(AF_INET, expected_gw, &tmp) > 0); - g_assert(nmtst_ip4_config_get_gateway(ip4_config) == tmp); -} +#define ip4_test_gateway(l3cd, expected_gw) \ + G_STMT_START \ + { \ + const NML3ConfigData *_l3cd = (l3cd); \ + \ + g_assert_cmpint(nm_l3_config_data_get_num_addresses(_l3cd, AF_INET), ==, 1); \ + nmtst_assert_ip_address(AF_INET, \ + nmtst_l3_config_data_get_best_gateway(_l3cd, AF_INET), \ + expected_gw); \ + } \ + G_STMT_END static void test_classless_static_routes_1(void) { - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const char * expected_route1_dest = "192.168.10.0"; - const char * expected_route1_gw = "192.168.1.1"; - const char * expected_route2_dest = "10.0.0.0"; - const char * expected_route2_gw = "10.17.66.41"; - static const Option data[] = { + gs_unref_hashtable GHashTable *options = NULL; + nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; + const char * expected_route1_dest = "192.168.10.0"; + const char * expected_route1_gw = "192.168.1.1"; + const char * expected_route2_dest = "10.0.0.0"; + const char * expected_route2_gw = "10.17.66.41"; + static const Option data[] = { /* dhclient custom format */ {"rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 8 10 10 17 66 41"}, {NULL, NULL}}; - options = fill_table(generic_options, NULL); - options = fill_table(data, options); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); + options = fill_table(generic_options, NULL); + options = fill_table(data, options); + l3cd = _ip4_config_from_options(1, "eth0", options); /* IP4 routes */ - g_assert_cmpint(nm_ip4_config_get_num_routes(ip4_config), ==, 3); - ip4_test_route(ip4_config, 0, expected_route1_dest, expected_route1_gw, 24); - ip4_test_route(ip4_config, 1, expected_route2_dest, expected_route2_gw, 8); - ip4_test_route(ip4_config, 2, "0.0.0.0", "192.168.1.1", 0); - - g_hash_table_destroy(options); + g_assert_cmpint(nm_l3_config_data_get_num_routes(l3cd, AF_INET), ==, 3); + ip4_test_route(l3cd, 0, expected_route1_dest, expected_route1_gw, 24); + ip4_test_route(l3cd, 1, expected_route2_dest, expected_route2_gw, 8); + ip4_test_route(l3cd, 2, "0.0.0.0", "192.168.1.1", 0); } static void test_classless_static_routes_2(void) { - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const char * expected_route1_dest = "192.168.10.0"; - const char * expected_route1_gw = "192.168.1.1"; - const char * expected_route2_dest = "10.0.0.0"; - const char * expected_route2_gw = "10.17.66.41"; - static const Option data[] = { + gs_unref_hashtable GHashTable *options = NULL; + nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; + const char * expected_route1_dest = "192.168.10.0"; + const char * expected_route1_gw = "192.168.1.1"; + const char * expected_route2_dest = "10.0.0.0"; + const char * expected_route2_gw = "10.17.66.41"; + static const Option data[] = { /* dhcpcd format */ {"classless_static_routes", "192.168.10.0/24 192.168.1.1 10.0.0.0/8 10.17.66.41"}, {NULL, NULL}}; - options = fill_table(generic_options, NULL); - options = fill_table(data, options); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); + options = fill_table(generic_options, NULL); + options = fill_table(data, options); + l3cd = _ip4_config_from_options(1, "eth0", options); /* IP4 routes */ - g_assert_cmpint(nm_ip4_config_get_num_routes(ip4_config), ==, 3); - ip4_test_route(ip4_config, 0, expected_route1_dest, expected_route1_gw, 24); - ip4_test_route(ip4_config, 1, expected_route2_dest, expected_route2_gw, 8); - ip4_test_route(ip4_config, 2, "0.0.0.0", expected_route1_gw, 0); - - g_hash_table_destroy(options); + g_assert_cmpint(nm_l3_config_data_get_num_routes(l3cd, AF_INET), ==, 3); + ip4_test_route(l3cd, 0, expected_route1_dest, expected_route1_gw, 24); + ip4_test_route(l3cd, 1, expected_route2_dest, expected_route2_gw, 8); + ip4_test_route(l3cd, 2, "0.0.0.0", expected_route1_gw, 0); } static void test_fedora_dhclient_classless_static_routes(void) { - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const char * expected_route1_dest = "129.210.177.128"; - const char * expected_route1_gw = "192.168.0.113"; - const char * expected_route2_dest = "2.0.0.0"; - const char * expected_route2_gw = "10.34.255.6"; - const char * expected_gateway = "192.168.0.113"; - static const Option data[] = { + gs_unref_hashtable GHashTable *options = NULL; + nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; + const char * expected_route1_dest = "129.210.177.128"; + const char * expected_route1_gw = "192.168.0.113"; + const char * expected_route2_dest = "2.0.0.0"; + const char * expected_route2_gw = "10.34.255.6"; + const char * expected_gateway = "192.168.0.113"; + static const Option data[] = { /* Fedora dhclient format */ {"classless_static_routes", "0 192.168.0.113 25.129.210.177.132 192.168.0.113 7.2 10.34.255.6"}, {NULL, NULL}}; - options = fill_table(generic_options, NULL); - options = fill_table(data, options); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); + options = fill_table(generic_options, NULL); + options = fill_table(data, options); + l3cd = _ip4_config_from_options(1, "eth0", options); /* IP4 routes */ - g_assert_cmpint(nm_ip4_config_get_num_routes(ip4_config), ==, 3); - ip4_test_route(ip4_config, 0, expected_route1_dest, expected_route1_gw, 25); - ip4_test_route(ip4_config, 1, expected_route2_dest, expected_route2_gw, 7); - ip4_test_route(ip4_config, 2, "0.0.0.0", expected_route1_gw, 0); + g_assert_cmpint(nm_l3_config_data_get_num_routes(l3cd, AF_INET), ==, 3); + ip4_test_route(l3cd, 0, expected_route1_dest, expected_route1_gw, 25); + ip4_test_route(l3cd, 1, expected_route2_dest, expected_route2_gw, 7); + ip4_test_route(l3cd, 2, "0.0.0.0", expected_route1_gw, 0); - /* Gateway */ - ip4_test_gateway(ip4_config, expected_gateway); - - g_hash_table_destroy(options); + ip4_test_gateway(l3cd, expected_gateway); } static void test_dhclient_invalid_classless_routes_1(void) { - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const char * expected_route1_dest = "192.168.10.0"; - const char * expected_route1_gw = "192.168.1.1"; - static const Option data[] = { + gs_unref_hashtable GHashTable *options = NULL; + nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; + const char * expected_route1_dest = "192.168.10.0"; + const char * expected_route1_gw = "192.168.1.1"; + static const Option data[] = { /* dhclient format */ {"rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 45 10 17 66 41"}, {NULL, NULL}}; @@ -384,27 +370,25 @@ test_dhclient_invalid_classless_routes_1(void) options = fill_table(data, options); NMTST_EXPECT_NM_WARN("*ignoring invalid classless static routes*"); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); + l3cd = _ip4_config_from_options(1, "eth0", options); g_test_assert_expected_messages(); /* IP4 routes */ - g_assert_cmpint(nm_ip4_config_get_num_routes(ip4_config), ==, 2); - ip4_test_route(ip4_config, 0, expected_route1_dest, expected_route1_gw, 24); - ip4_test_route(ip4_config, 1, "0.0.0.0", expected_route1_gw, 0); - - g_hash_table_destroy(options); + g_assert_cmpint(nm_l3_config_data_get_num_routes(l3cd, AF_INET), ==, 2); + ip4_test_route(l3cd, 0, expected_route1_dest, expected_route1_gw, 24); + ip4_test_route(l3cd, 1, "0.0.0.0", expected_route1_gw, 0); } static void test_dhcpcd_invalid_classless_routes_1(void) { - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const char * expected_route1_dest = "10.1.1.5"; - const char * expected_route1_gw = "10.1.1.1"; - const char * expected_route2_dest = "100.99.88.56"; - const char * expected_route2_gw = "10.1.1.1"; - static const Option data[] = { + gs_unref_hashtable GHashTable *options = NULL; + nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; + const char * expected_route1_dest = "10.1.1.5"; + const char * expected_route1_gw = "10.1.1.1"; + const char * expected_route2_dest = "100.99.88.56"; + const char * expected_route2_gw = "10.1.1.1"; + static const Option data[] = { /* dhcpcd format */ {"classless_static_routes", "192.168.10.0/24 192.168.1.1 10.0.adfadf/44 10.17.66.41"}, {NULL, NULL}}; @@ -413,30 +397,28 @@ test_dhcpcd_invalid_classless_routes_1(void) options = fill_table(data, options); NMTST_EXPECT_NM_WARN("*ignoring invalid classless static routes*"); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); + l3cd = _ip4_config_from_options(1, "eth0", options); g_test_assert_expected_messages(); /* Test falling back to old-style static routes if the classless static * routes are invalid. */ - g_assert_cmpint(nm_ip4_config_get_num_routes(ip4_config), ==, 3); - ip4_test_route(ip4_config, 0, expected_route1_dest, expected_route1_gw, 32); - ip4_test_route(ip4_config, 1, expected_route2_dest, expected_route2_gw, 32); - ip4_test_route(ip4_config, 2, "0.0.0.0", "192.168.1.1", 0); - - g_hash_table_destroy(options); + g_assert_cmpint(nm_l3_config_data_get_num_routes(l3cd, AF_INET), ==, 3); + ip4_test_route(l3cd, 0, expected_route1_dest, expected_route1_gw, 32); + ip4_test_route(l3cd, 1, expected_route2_dest, expected_route2_gw, 32); + ip4_test_route(l3cd, 2, "0.0.0.0", "192.168.1.1", 0); } static void test_dhclient_invalid_classless_routes_2(void) { - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const char * expected_route1_dest = "10.1.1.5"; - const char * expected_route1_gw = "10.1.1.1"; - const char * expected_route2_dest = "100.99.88.56"; - const char * expected_route2_gw = "10.1.1.1"; - static const Option data[] = { + gs_unref_hashtable GHashTable *options = NULL; + nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; + const char * expected_route1_dest = "10.1.1.5"; + const char * expected_route1_gw = "10.1.1.1"; + const char * expected_route2_dest = "100.99.88.56"; + const char * expected_route2_gw = "10.1.1.1"; + static const Option data[] = { {"rfc3442_classless_static_routes", "45 10 17 66 41 24 192 168 10 192 168 1 1"}, {NULL, NULL}}; @@ -444,30 +426,28 @@ test_dhclient_invalid_classless_routes_2(void) options = fill_table(data, options); NMTST_EXPECT_NM_WARN("*ignoring invalid classless static routes*"); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); + l3cd = _ip4_config_from_options(1, "eth0", options); g_test_assert_expected_messages(); /* Test falling back to old-style static routes if the classless static * routes are invalid. */ - g_assert_cmpint(nm_ip4_config_get_num_routes(ip4_config), ==, 3); - ip4_test_route(ip4_config, 0, expected_route1_dest, expected_route1_gw, 32); - ip4_test_route(ip4_config, 1, expected_route2_dest, expected_route2_gw, 32); - ip4_test_route(ip4_config, 2, "0.0.0.0", "192.168.1.1", 0); - - g_hash_table_destroy(options); + g_assert_cmpint(nm_l3_config_data_get_num_routes(l3cd, AF_INET), ==, 3); + ip4_test_route(l3cd, 0, expected_route1_dest, expected_route1_gw, 32); + ip4_test_route(l3cd, 1, expected_route2_dest, expected_route2_gw, 32); + ip4_test_route(l3cd, 2, "0.0.0.0", "192.168.1.1", 0); } static void test_dhcpcd_invalid_classless_routes_2(void) { - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const char * expected_route1_dest = "10.1.1.5"; - const char * expected_route1_gw = "10.1.1.1"; - const char * expected_route2_dest = "100.99.88.56"; - const char * expected_route2_gw = "10.1.1.1"; - static const Option data[] = { + gs_unref_hashtable GHashTable *options = NULL; + nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; + const char * expected_route1_dest = "10.1.1.5"; + const char * expected_route1_gw = "10.1.1.1"; + const char * expected_route2_dest = "100.99.88.56"; + const char * expected_route2_gw = "10.1.1.1"; + static const Option data[] = { {"classless_static_routes", "10.0.adfadf/44 10.17.66.41 192.168.10.0/24 192.168.1.1"}, {NULL, NULL}}; @@ -475,7 +455,7 @@ test_dhcpcd_invalid_classless_routes_2(void) options = fill_table(data, options); NMTST_EXPECT_NM_WARN("*ignoring invalid classless static routes*"); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); + l3cd = _ip4_config_from_options(1, "eth0", options); g_test_assert_expected_messages(); /* Test falling back to old-style static routes if the classless static @@ -483,22 +463,20 @@ test_dhcpcd_invalid_classless_routes_2(void) */ /* Routes */ - g_assert_cmpint(nm_ip4_config_get_num_routes(ip4_config), ==, 3); - ip4_test_route(ip4_config, 0, expected_route1_dest, expected_route1_gw, 32); - ip4_test_route(ip4_config, 1, expected_route2_dest, expected_route2_gw, 32); - ip4_test_route(ip4_config, 2, "0.0.0.0", "192.168.1.1", 0); - - g_hash_table_destroy(options); + g_assert_cmpint(nm_l3_config_data_get_num_routes(l3cd, AF_INET), ==, 3); + ip4_test_route(l3cd, 0, expected_route1_dest, expected_route1_gw, 32); + ip4_test_route(l3cd, 1, expected_route2_dest, expected_route2_gw, 32); + ip4_test_route(l3cd, 2, "0.0.0.0", "192.168.1.1", 0); } static void test_dhclient_invalid_classless_routes_3(void) { - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const char * expected_route1_dest = "192.168.10.0"; - const char * expected_route1_gw = "192.168.1.1"; - static const Option data[] = { + gs_unref_hashtable GHashTable *options = NULL; + nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; + const char * expected_route1_dest = "192.168.10.0"; + const char * expected_route1_gw = "192.168.1.1"; + static const Option data[] = { {"rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 32 128 10 17 66 41"}, {NULL, NULL}}; @@ -506,25 +484,23 @@ test_dhclient_invalid_classless_routes_3(void) options = fill_table(data, options); NMTST_EXPECT_NM_WARN("*ignoring invalid classless static routes*"); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); + l3cd = _ip4_config_from_options(1, "eth0", options); g_test_assert_expected_messages(); /* IP4 routes */ - g_assert_cmpint(nm_ip4_config_get_num_routes(ip4_config), ==, 2); - ip4_test_route(ip4_config, 0, expected_route1_dest, expected_route1_gw, 24); - ip4_test_route(ip4_config, 1, "0.0.0.0", expected_route1_gw, 0); - - g_hash_table_destroy(options); + g_assert_cmpint(nm_l3_config_data_get_num_routes(l3cd, AF_INET), ==, 2); + ip4_test_route(l3cd, 0, expected_route1_dest, expected_route1_gw, 24); + ip4_test_route(l3cd, 1, "0.0.0.0", expected_route1_gw, 0); } static void test_dhcpcd_invalid_classless_routes_3(void) { - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const char * expected_route1_dest = "192.168.10.0"; - const char * expected_route1_gw = "192.168.1.1"; - static Option data[] = { + gs_unref_hashtable GHashTable *options = NULL; + nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; + const char * expected_route1_dest = "192.168.10.0"; + const char * expected_route1_gw = "192.168.1.1"; + static Option data[] = { {"classless_static_routes", "192.168.10.0/24 192.168.1.1 128/32 10.17.66.41"}, {NULL, NULL}}; @@ -532,133 +508,124 @@ test_dhcpcd_invalid_classless_routes_3(void) options = fill_table(data, options); NMTST_EXPECT_NM_WARN("*DHCP provided invalid classless static route*"); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); + l3cd = _ip4_config_from_options(1, "eth0", options); g_test_assert_expected_messages(); /* IP4 routes */ - g_assert_cmpint(nm_ip4_config_get_num_routes(ip4_config), ==, 2); - ip4_test_route(ip4_config, 0, expected_route1_dest, expected_route1_gw, 24); - ip4_test_route(ip4_config, 1, "0.0.0.0", expected_route1_gw, 0); - - g_hash_table_destroy(options); + g_assert_cmpint(nm_l3_config_data_get_num_routes(l3cd, AF_INET), ==, 2); + ip4_test_route(l3cd, 0, expected_route1_dest, expected_route1_gw, 24); + ip4_test_route(l3cd, 1, "0.0.0.0", expected_route1_gw, 0); } static void test_dhclient_gw_in_classless_routes(void) { - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const char * expected_route1_dest = "192.168.10.0"; - const char * expected_route1_gw = "192.168.1.1"; - const char * expected_gateway = "192.2.3.4"; - static Option data[] = { + gs_unref_hashtable GHashTable *options = NULL; + nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; + const char * expected_route1_dest = "192.168.10.0"; + const char * expected_route1_gw = "192.168.1.1"; + const char * expected_gateway = "192.2.3.4"; + static Option data[] = { {"rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 0 192 2 3 4"}, {NULL, NULL}}; - options = fill_table(generic_options, NULL); - options = fill_table(data, options); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); + options = fill_table(generic_options, NULL); + options = fill_table(data, options); + l3cd = _ip4_config_from_options(1, "eth0", options); /* IP4 routes */ - g_assert_cmpint(nm_ip4_config_get_num_routes(ip4_config), ==, 2); - ip4_test_route(ip4_config, 0, expected_route1_dest, expected_route1_gw, 24); - ip4_test_route(ip4_config, 1, "0.0.0.0", "192.2.3.4", 0); - - /* Gateway */ - ip4_test_gateway(ip4_config, expected_gateway); + g_assert_cmpint(nm_l3_config_data_get_num_routes(l3cd, AF_INET), ==, 2); + ip4_test_route(l3cd, 0, expected_route1_dest, expected_route1_gw, 24); + ip4_test_route(l3cd, 1, "0.0.0.0", "192.2.3.4", 0); - g_hash_table_destroy(options); + ip4_test_gateway(l3cd, expected_gateway); } static void test_dhcpcd_gw_in_classless_routes(void) { - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const char * expected_route1_dest = "192.168.10.0"; - const char * expected_route1_gw = "192.168.1.1"; - const char * expected_gateway = "192.2.3.4"; - static Option data[] = { + gs_unref_hashtable GHashTable *options = NULL; + nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; + const char * expected_route1_dest = "192.168.10.0"; + const char * expected_route1_gw = "192.168.1.1"; + const char * expected_gateway = "192.2.3.4"; + static Option data[] = { {"classless_static_routes", "192.168.10.0/24 192.168.1.1 0.0.0.0/0 192.2.3.4"}, {NULL, NULL}}; - options = fill_table(generic_options, NULL); - options = fill_table(data, options); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); + options = fill_table(generic_options, NULL); + options = fill_table(data, options); + l3cd = _ip4_config_from_options(1, "eth0", options); /* IP4 routes */ - g_assert_cmpint(nm_ip4_config_get_num_routes(ip4_config), ==, 2); - ip4_test_route(ip4_config, 0, expected_route1_dest, expected_route1_gw, 24); - ip4_test_route(ip4_config, 1, "0.0.0.0", "192.2.3.4", 0); - - /* Gateway */ - ip4_test_gateway(ip4_config, expected_gateway); + g_assert_cmpint(nm_l3_config_data_get_num_routes(l3cd, AF_INET), ==, 2); + ip4_test_route(l3cd, 0, expected_route1_dest, expected_route1_gw, 24); + ip4_test_route(l3cd, 1, "0.0.0.0", "192.2.3.4", 0); - g_hash_table_destroy(options); + ip4_test_gateway(l3cd, expected_gateway); } static void test_escaped_domain_searches(void) { - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const char * expected_search0 = "host1"; - const char * expected_search1 = "host2"; - const char * expected_search2 = "host3"; + gs_unref_hashtable GHashTable *options = NULL; + nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; + const char * expected_search0 = "host1"; + const char * expected_search1 = "host2"; + const char * expected_search2 = "host3"; static const Option data[] = {{"domain_search", "host1\\032host2\\032host3"}, {NULL, NULL}}; + const char *const * strarr; + guint u; - options = fill_table(generic_options, NULL); - options = fill_table(data, options); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); - - /* domain searches */ - g_assert_cmpint(nm_ip4_config_get_num_searches(ip4_config), ==, 3); - g_assert_cmpstr(nm_ip4_config_get_search(ip4_config, 0), ==, expected_search0); - g_assert_cmpstr(nm_ip4_config_get_search(ip4_config, 1), ==, expected_search1); - g_assert_cmpstr(nm_ip4_config_get_search(ip4_config, 2), ==, expected_search2); + options = fill_table(generic_options, NULL); + options = fill_table(data, options); + l3cd = _ip4_config_from_options(1, "eth0", options); - g_hash_table_destroy(options); + strarr = nm_l3_config_data_get_searches(l3cd, AF_INET, &u); + g_assert_cmpint(u, ==, 3); + g_assert_cmpstr(strarr[0], ==, expected_search0); + g_assert_cmpstr(strarr[1], ==, expected_search1); + g_assert_cmpstr(strarr[2], ==, expected_search2); } static void test_invalid_escaped_domain_searches(void) { - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; + gs_unref_hashtable GHashTable *options = NULL; + nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; static const Option data[] = {{"domain_search", "host1\\aahost2\\032host3"}, {NULL, NULL}}; + const char *const * strarr; + guint u; options = fill_table(generic_options, NULL); options = fill_table(data, options); NMTST_EXPECT_NM_WARN("*invalid domain search*"); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); + l3cd = _ip4_config_from_options(1, "eth0", options); g_test_assert_expected_messages(); - /* domain searches */ - g_assert_cmpint(nm_ip4_config_get_num_searches(ip4_config), ==, 0); - - g_hash_table_destroy(options); + strarr = nm_l3_config_data_get_searches(l3cd, AF_INET, &u); + g_assert_cmpint(u, ==, 0); + g_assert(!strarr); } static void test_ip4_missing_prefix(const char *ip, guint32 expected_prefix) { - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const NMPlatformIP4Address * address; + gs_unref_hashtable GHashTable *options = NULL; + nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; + const NMPlatformIP4Address * address; options = fill_table(generic_options, NULL); g_hash_table_insert(options, "ip_address", (gpointer) ip); g_hash_table_remove(options, "subnet_mask"); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); + l3cd = _ip4_config_from_options(1, "eth0", options); - g_assert_cmpint(nm_ip4_config_get_num_addresses(ip4_config), ==, 1); - address = _nmtst_ip4_config_get_address(ip4_config, 0); + g_assert_cmpint(nm_l3_config_data_get_num_addresses(l3cd, AF_INET), ==, 1); + address = nmtst_l3_config_data_get_address_at_4(l3cd, 0); g_assert(address); g_assert_cmpint(address->plen, ==, expected_prefix); - - g_hash_table_destroy(options); } static void @@ -682,9 +649,9 @@ test_ip4_missing_prefix_8(void) static void test_ip4_prefix_classless(void) { - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const NMPlatformIP4Address * address; + gs_unref_hashtable GHashTable *options = NULL; + nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; + const NMPlatformIP4Address * address; /* Ensure that the missing-subnet-mask handler doesn't mangle classless * subnet masks at all. The handler should trigger only if the server @@ -695,14 +662,12 @@ test_ip4_prefix_classless(void) g_hash_table_insert(options, "ip_address", "172.16.54.22"); g_hash_table_insert(options, "subnet_mask", "255.255.252.0"); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); + l3cd = _ip4_config_from_options(1, "eth0", options); - g_assert_cmpint(nm_ip4_config_get_num_addresses(ip4_config), ==, 1); - address = _nmtst_ip4_config_get_address(ip4_config, 0); + g_assert_cmpint(nm_l3_config_data_get_num_addresses(l3cd, AF_INET), ==, 1); + address = nmtst_l3_config_data_get_address_at_4(l3cd, 0); g_assert(address); g_assert_cmpint(address->plen, ==, 22); - - g_hash_table_destroy(options); } #define COMPARE_ID(src, is_str, expected, expected_len) \ |