diff options
author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2022-10-18 10:18:55 +0200 |
---|---|---|
committer | Yu Watanabe <watanabe.yu+github@gmail.com> | 2022-10-24 13:34:10 +0200 |
commit | 7d4e850323b4270979ac55dd0e6893a7c348c7e2 (patch) | |
tree | aa9eec29e07fa0bc56a14e8b4ab8f55343687652 /src/resolve/resolvectl.c | |
parent | resolvectl: rely on invoked_as() (diff) | |
download | systemd-7d4e850323b4270979ac55dd0e6893a7c348c7e2.tar.xz systemd-7d4e850323b4270979ac55dd0e6893a7c348c7e2.zip |
resolvconf-compat: first parse provided interface name as is
Then, try to drop multiple protocol specifiers at the end.
Strictly speaking, this breaks backward compatibility:
if eth0 and eth0.42 exists, then previously,
echo 'nameserver 192.168.0.1' | resolvconf -a eth0.42
adds the DNS server to eth0 instead of eth0.42, as we unconditionally
dropped the specifier after the last dot, and
echo 'nameserver 192.168.0.1' | resolvconf -a eth0.42.dhcp
adds the DNS server to eth0.42. However, with this commit, now
the both commands add the DNS server to eth0.42. But, hopefully,
this should be preferable behavior.
Fixes #25032.
Diffstat (limited to 'src/resolve/resolvectl.c')
-rw-r--r-- | src/resolve/resolvectl.c | 87 |
1 files changed, 55 insertions, 32 deletions
diff --git a/src/resolve/resolvectl.c b/src/resolve/resolvectl.c index 25ba129118..b07761a495 100644 --- a/src/resolve/resolvectl.c +++ b/src/resolve/resolvectl.c @@ -108,51 +108,74 @@ static int interface_info_compare(const InterfaceInfo *a, const InterfaceInfo *b return strcmp_ptr(a->name, b->name); } -int ifname_mangle(const char *s) { - _cleanup_free_ char *iface = NULL; - int ifi; +int ifname_mangle_full(const char *s, bool drop_protocol_specifier) { + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; + _cleanup_strv_free_ char **found = NULL; + int r; assert(s); - iface = strdup(s); - if (!iface) - return log_oom(); + if (drop_protocol_specifier) { + _cleanup_free_ char *buf = NULL; + int ifindex_longest_name = -ENODEV; - ifi = rtnl_resolve_interface(NULL, iface); - if (ifi < 0) { - if (ifi == -ENODEV && arg_ifindex_permissive) { - log_debug("Interface '%s' not found, but -f specified, ignoring.", iface); - return 0; /* done */ - } + /* When invoked as resolvconf, drop the protocol specifier(s) at the end. */ - return log_error_errno(ifi, "Failed to resolve interface \"%s\": %m", iface); - } + buf = strdup(s); + if (!buf) + return log_oom(); - if (arg_ifindex > 0 && arg_ifindex != ifi) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Specified multiple different interfaces. Refusing."); + for (;;) { + r = rtnl_resolve_interface(&rtnl, buf); + if (r > 0) { + if (ifindex_longest_name <= 0) + ifindex_longest_name = r; - arg_ifindex = ifi; - free_and_replace(arg_ifname, iface); + r = strv_extend(&found, buf); + if (r < 0) + return log_oom(); + } - return 1; -} + char *dot = strrchr(buf, '.'); + if (!dot) + break; -int ifname_resolvconf_mangle(const char *s) { - const char *dot; + *dot = '\0'; + } - assert(s); + unsigned n = strv_length(found); + if (n > 1) { + _cleanup_free_ char *joined = NULL; - dot = strrchr(s, '.'); - if (dot) { - _cleanup_free_ char *iface = NULL; + joined = strv_join(found, ", "); + log_warning("Found multiple interfaces (%s) matching with '%s'. Using '%s' (ifindex=%i).", + strna(joined), s, found[0], ifindex_longest_name); - log_debug("Ignoring protocol specifier '%s'.", dot + 1); - iface = strndup(s, dot - s); - if (!iface) - return log_oom(); - return ifname_mangle(iface); + } else if (n == 1) { + const char *proto; + + proto = ASSERT_PTR(startswith(s, found[0])); + if (!isempty(proto)) + log_info("Dropped protocol specifier '%s' from '%s'. Using '%s' (ifindex=%i).", + proto, s, found[0], ifindex_longest_name); + } + + r = ifindex_longest_name; } else - return ifname_mangle(s); + r = rtnl_resolve_interface(&rtnl, s); + if (r < 0) { + if (ERRNO_IS_DEVICE_ABSENT(r) && arg_ifindex_permissive) { + log_debug_errno(r, "Interface '%s' not found, but -f specified, ignoring: %m", s); + return 0; /* done */ + } + return log_error_errno(r, "Failed to resolve interface \"%s\": %m", s); + } + + if (arg_ifindex > 0 && arg_ifindex != r) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Specified multiple different interfaces. Refusing."); + + arg_ifindex = r; + return free_and_strdup_warn(&arg_ifname, found ? found[0] : s); /* found */ } static void print_source(uint64_t flags, usec_t rtt) { |