Add the reason to error messages to make debugging easier.
Note that n_dhcp4_client_new() also returns positive internal error
values, so we can't use nm_utils_error_set_errno().
I think that artificially slowing down DHCP is not going to make users
happier, so let's decrease it to the minimum allowed value (1 ms).
Note that also dhclient and the internal client have it disabled. From
the dhclient.conf man page:
*initial-delay* parameter sets the maximum time client can wait after
start before commencing first transmission. According to RFC2131
Section 4.4.1, client should wait a random time between startup and
the actual first trans‐ mission. Previous versions of ISC DHCP client
used to wait random time up to 5 seconds, but that was unwanted due
to impact on startup time. As such, new versions have the default
initial delay set to 0. To restore old behavior, please set
initial-delay to 5.
This is inspired by the existing systemd integration, with a few differences:
* This parses the WPAD option, which systemd requested, but did not use.
* We hook into the DAD handling, only making use of the configured address
once DAD has completed successfully, and declining the lease if it fails.
There are still many areas of possible improvement. In particular, we need
to ensure the parsing of all options are compliant, as n-dhcp4 treats all
options as opaque, unlike sd-dhcp4. We probably also need to look at how
to handle failures and retries (in particular if we decline a lease).
We need to query the current MTU at client startu, as well as the hardware
broadcast address. Both these are provided by the kernel over netlink, so
it should simply be a matter of hooking that up with NM's netlink layer.
Contribution under LGPL2.0+, in addition to stated licenses.
The DHCP client is not meant to use the assigned address before DAD
has completed successfully, if enabled. And if DAD fails, the server
should be notified with a DECLINE, in order to potentially blacklist
the address.
Currently, none of the clients support this, but add the required
callbacks, and allow clients to opt in if they want.
Soon a new DHCP backend will be added that will take code from the
internal one. Change its license to LGPL so that the whole new backend
code can also be LGPL, which is the preferred license for new
NetworkManager code.
Acked-by: Dan Williams <dcbw@redhat.com>
Acked-by: Dan Winship <danw@redhat.com>
Acked-by: Lubomir Rintel <lkundrak@v3.sk>
Acked-by: Thomas Haller <thaller@redhat.com>
We no longer add these. If you use Emacs, configure it yourself.
Also, due to our "smart-tab" usage the editor anyway does a subpar
job handling our tabs. However, on the upside every user can choose
whatever tab-width he/she prefers. If "smart-tabs" are used properly
(like we do), every tab-width will work.
No manual changes, just ran commands:
F=($(git grep -l -e '-\*-'))
sed '1 { /\/\* *-\*- *[mM]ode.*\*\/$/d }' -i "${F[@]}"
sed '1,4 { /^\(#\|--\|dnl\) *-\*- [mM]ode/d }' -i "${F[@]}"
Check remaining lines with:
git grep -e '-\*-'
The ultimate purpose of this is to cleanup our files and eventually use
SPDX license identifiers. For that, first get rid of the boilerplate lines.
Maybe DHCP plugins should be configurable per address family and be
re-loadable via SIGHUP. But that just adds complexity.
Nowadays we always have the "internal" DHCP plugin, which is known to
support both IPv4 and IPv6. One day, we should get rid of all plugins
and only use one implementation (that works well). The "internal" plugin
is supposed to be(come) that.
That also means, that we are not going to add more (external) DHCP
plugins and we are not going to invest work in the existing plugins
(except the "internal" plugin).
Some DHCP plugins are known to not support IPv6. If the user selects
"dhcpcd" we should just fallback to the "internal" plugin. What's the
point of letting the activation fail? Probably users shouldn't use
"dhcpcd" plugin anyway, but that's a different story. Doing such fallback
could be a problem with forward compatibility if we ever would add IPv6
support to "dhcpcd". But we won't.
Also, we are going to add "n-dhcp4" as replacement for the systemd based
code. For a time, there will be an experimental plugin "nettools" that
eventually will become the new "internal" plugin. Until that happens,
we want for IPv6 automatically fallback to systemd based "internal"
plugin. This patch will make that simple.
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/merge_requests/173
The pid-file is private to NetworkManager. It should reside in NetworkManager's
run directory instead of "/var/run".
I don't think that changing this location can break existing uses. Why
would somebody outside of NetworkManager care about this file?
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/merge_requests/157
"RUNDIR" is set to "$runstatedir/NetworkManager". That is not correct,
we must use "$runstatedir".
I don't understand how this could have ever worked. Commit e2ecf5b808
('dhcp: dhcpcd uses a fixed path for PID files') seems to address this issue,
but already then "RUNDIR" was set to "$(localstatedir)/run/NetworkManager".
The library is called "libnm_core". So the dependency should be called
"libnm_core_dep", like in all other cases.
(cherry picked from commit c27ad37c27)
From the files under "shared/nm-utils" we build an internal library
that provides glib-based helper utilities.
Move the files of that basic library to a new subdirectory
"shared/nm-glib-aux" and rename the helper library "libnm-core-base.la"
to "libnm-glib-aux.la".
Reasons:
- the name "utils" is overused in our code-base. Everything's an
"utils". Give this thing a more distinct name.
- there were additional files under "shared/nm-utils", which are not
part of this internal library "libnm-utils-base.la". All the files
that are part of this library should be together in the same
directory, but files that are not, should not be there.
- the new name should better convey what this library is and what is isn't:
it's a set of utilities and helper functions that extend glib with
funcitonality that we commonly need.
There are still some files left under "shared/nm-utils". They have less
a unifying propose to be in their own directory, so I leave them there
for now. But at least they are separate from "shared/nm-glib-aux",
which has a very clear purpose.
(cherry picked from commit 80db06f768)
"shared/nm-utils" contains general purpose utility functions that only
depend on glib (and extend glib with some helper functions).
We will also add code that does not use glib, hence it would be good
if the part of "shared/nm-utils" that does not depend on glib, could be
used by these future projects.
Also, we use the term "utils" everywhere. While that covers the purpose
and content well, having everything called "nm-something-utils" is not
great. Instead, call this "nm-std-aux", inspired by "c-util/c-stdaux".
(cherry picked from commit b434b9ec07)
- use nm_utils_strsplit_set_full() instead of g_strsplit_set() to avoid allocating
a full strv array.
- refactor the code to return early and use cleanup attribute for freeing
memory.
- return TRUE/FALSE from process_dhclient_rfc3442_route(). It's simpler to
understand than returning the moved pointer and a success output variable.
The defaults for test timeouts in meson is 30 seconds. That is not long
enough when running
$ NMTST_USE_VALGRIND=1 ninja -C build test
Note that meson supports --timeout-multiplier, and automatically
increases the timeout when running under valgrind. However, meson
does not understand that we are running tests under valgrind via
NMTST_USE_VALGRIND=1 environment variable.
Timeouts are really not expected to be reached and are a mean of last
resort. Hence, increasing the timeout to a large value is likely to
have no effect or to fix test failures where the timeout was too rigid.
It's unlikely that the test indeed hangs and the increase of timeout
causes a unnecessary increase of waittime before aborting.
- regarding the DHCP options, we should not suppress them. If the lease
contains such bogus(?) addresses, we still want to expose them on
D-Bus without modification.
- regrading using the DNS server, ignore localhost addresses like done for
systemd-networkd ([1], [2]).
Until recently, the DHCP library would internally suppress such
addresses ([3]). That is no longer the case, and we should handle
them specially.
[1] https://github.com/systemd/systemd/issues/4524
[2] d9ec2e632d
[3] 334d5682ae
Imported from systemd:
The Router DHCP option may contain a list of one or more
routers ([1]). Extend the API of sd_dhcp_lease to return a
list instead of only the first.
Note that networkd still only uses the first router (if present).
Aside from extending the internal API of the DHCP client, there
is almost no change in behavior. The only visible difference in
behavior is that the "ROUTER" variable in the lease file is now a
list of addresses.
Note how RFC 2132 does not define certain IP addresses as invalid for the
router option. Still, previously sd_dhcp_lease_get_router() would never
return a "0.0.0.0" address. In fact, the previous API could not
differenciate whether no router option was present, whether it
was invalid, or whether its first router was "0.0.0.0". No longer let
the DHCP client library impose additional restrictions that are not
part of RFC. Instead, the caller should handle this. The patch does
that, and networkd only consideres the first router entry if it is not
"0.0.0.0".
[1] https://tools.ietf.org/html/rfc2132#section-3.5
This also required adjusting "src/dhcp/nm-dhcp-systemd.c" due to the
changed internal API.
f8862395e8
... and lease_to_ip6_config().
- Handle reasons that render the lease invalid first, before logging
anything. This way, upon invalid lease we don't have partially logged
about the lease.
- prefer logging one line for options that contain multiple values, for
example for search domains.
- reorder statements to consistently log first before calling add_option().
- prefer
g_string_append (nm_gstring_add_space_delimiter (str), ...
over
g_string_append_printf (str, "%s%s", str->len ? " " : "", ...
- use @addr_str buffer directly, instead of assigning to another
temporary variable.
For static functions inside a module, the compiler determines on its own
whether to inline the function.
Also, "inline" was used at some places that don't immediatly look like
candidates for inlining. It was most likely a copy&paste error.
The "ipv4.dhcp-client-id" is configurable per-profile and the default
value can be overwritten via connection defaults in NetworkManager.conf.
For "dhclient" DHCP plugin, the ultimate default for "ipv4.dhcp-client-id"
is determined by dhclient itself, or possibly by user configuration from
"/etc/dhcp".
For the "internal" DHCP plugin, the default must be decided by
NetworkManager. Also, the default here is important, as we preferably
won't change it anymore. That is because a changing the client-id
will result in different IP addresses after upgrade of NetworkManager
version. That should be avoided.
Still, change it now. If a downstream does not want this, it either needs
to patch the sources or add a configuration snippet like:
[connection-internal-dhcp-client-id-duid]
match-device=dhcp-plugin:internal
ipv4.dhcp-client-id=duid
The reason to change from the previous default "duid" to "mac" are the
following:
- "duid" is an RFC 4361 compatible client-id ([1]) and "mac" is defined
in RFC 2132.
- "duid" cannot (easily) be predicated a-priori as it is a hash of the
interface-name and "/etc/machine-id". In particular in cloud and server
environments, admins often prefer "mac" as they do know the MAC address
and pre-configure the DHCP server accordingly.
- with "dhclient" plugin, the default is decided by dhclient package or
user configuration in "/etc/dhcp". However, in fact the default is often
"client-identifier hardware" (for example on RHEL/CentOS).
- for RHEL/CentOS we require a way to select "mac" as default. That was
done by installing a configuration snippet via the NetworkManager-config-server
package. It's confusing to have the default depend on a package. Avoid
that. Also, users required "mac" in certain scenarios, but no users
explicitly asked for "duid" as default.
- our "duid" implementation generates a 32 bit IAID based on a hash of the
interface-name, and only 8 bytes entropy that contains a hash
of "/etc/machine-id". The point is, that is not a lot of entropy to
avoid conflicting client-ids. Another point is, that the choosen algorithm
for "duid" is suitable for RFC 4361, but it's only one of many possibly
implementations. Granted, each possibility has up and downsides but selecting
one of them as default seems wrong (given that it has obvious downsides
already). For "mac" there is only one straight-forward way to implement
it.
- RFC 7844 (Anonymity Profiles for DHCP Clients) is not yet supported by
NetworkManager. But we should not select a default client-id which
counteracts anonymit. Choosing "mac" does not reveal information which
is not already exposed.
[1] https://tools.ietf.org/html/rfc4361#section-4https://bugzilla.redhat.com/show_bug.cgi?id=1661165
There is really no problem here, allow it.
Previously we would assert against a non-zero prefix length.
But I am not sure that all callers really ensured that this
couldn't happen. Anyway, there is no problem we such addresses,
really.
Only we need to make sure that nm_ip4_config_add_dependent_routes()
and nm_ip6_config_add_dependent_routes() don't add prefix routes for
such addresses (which is the case now).
Preface: RFC 3442 (The Classless Static Route Option for Dynamic Host
Configuration Protocol (DHCP) version 4) states:
If the DHCP server returns both a Classless Static Routes option and
a Router option, the DHCP client MUST ignore the Router option.
Similarly, if the DHCP server returns both a Classless Static Routes
option and a Static Routes option, the DHCP client MUST ignore the
Static Routes option.
Changes:
- sd_dhcp_lease_get_routes() returns the combination of both option 33
(static routes) and 121 (classless static routes). If classless static
routes are provided, the state routes must be ignored.
- we collect the options hash that we expose on D-Bus. For that purpose,
we must not merge both option types as classless static routes. Instead,
we want to expose the values like we received them originally: as two
different options.
- we continue our deviation from RFC 3442, when receiving classless static
routes with option 3 (Router), we only ignore the router if we didn't
already receive a default route via classless static routes.
- in the past, NetworkManager treated the default route specially, and
one device could only have one default route. That limitation was
already (partly) lifted by commit 5c299454b4
(core: rework tracking of gateway/default-route in ip-config). However,
from DHCP we still would only accept one default route. Fix that for
internal client. Installing multiple default routes might make sense, as
kernel apparently can skip unreachable routers (as it notes via ICMP
messages) (rh#1634657).
https://bugzilla.redhat.com/show_bug.cgi?id=1634657
In ip4_start(), we iterate over @dhcp4_requests array and add the
options that are to be included. We do so, by calling
sd_dhcp_client_set_request_option().
Note that sd_dhcp_client_set_request_option() only appends the options
to a list, not taking special care about the order in which options are
added.
RFC 3442 (The Classless Static Route Option for Dynamic Host Configuration
Protocol (DHCP) version 4) says:
DHCP clients that support this option and send a parameter request
list MAY also request the Static Routes option, for compatibility
with older servers that don't support Classless Static Routes. The
Classless Static Routes option code MUST appear in the parameter
request list prior to both the Router option code and the Static
Routes option code, if present.
Compare to RFC 2132 (DHCP Options and BOOTP Vendor Extensions) which says
about the parameter request list:
The client MAY list the options in order of preference.
Note, with RFC 7844 (Anonymity Profiles for DHCP Clients), the order
should be randomized. But since we don't follow RFC 7844 (yet), let's follow
at least RFC 3442.
- check errors when accessing the lease. Some errors, like a failure
from sd_dhcp_lease_get_address() are fatal.
- while parsing the individual options, don't incrementally build the
NMPlatformIP4Address instance (and similar). Instead, parse the
options to individual variales, and only package them as platform
structure at the point where they are needed. It makes the code simpler,
because all individual bits (like "r_plen" variable) are only
initialized and used at one place. That is clearer than incrementally
building a platform structure, where you have to follow the code to
see how the structure mutates.
- drop redundant comments that only serve as a visual separator
for structuring the code. Instead, structure the code.
lease_to_ip4_config() can fail, if the lease is broken. As such, a function
that fails should not modifiy an in/out parameter. Avoid that, by not
having the caller pre-allocate the options hash, but instead allocate it
by the lease_to_ip*_config() functions, and return it only on success.
- use proper data types "guint16" and "bool" in static
option list. It saves a few bytes, but also it's the appropriate
type. Well, at least, it's the appropriate type for DHCPv6,
not for DHCPv4 (which is guint8).
- assert against failure of sd_dhcp_client_set_request_option() and
sd_dhcp6_client_set_request_option().
sd_dhcp6_client_set_request_option() only accepts a white-listed
set of options. Unexpected options are rejected with -EINVAL.
Currently supported are only:
- SD_DHCP6_OPTION_DNS_SERVERS
- SD_DHCP6_OPTION_DOMAIN_LIST
- SD_DHCP6_OPTION_SNTP_SERVERS
- SD_DHCP6_OPTION_NTP_SERVER
- SD_DHCP6_OPTION_RAPID_COMMIT
As such, SD_DHCP6_OPTION_CLIENTID is not accepted and requesting it
was silently ignored.
Fixes: d2dd3b2c90
While nm_utils_inet*_ntop() accepts a %NULL buffer to fallback
to a static buffer, don't do that.
I find the possibility of using a static buffer here error prone
and something that should be avoided. There is of course the downside,
that in some cases it requires an additional line of code to allocate
the buffer on the stack as auto-variable.