nm-daemon-helper: add "service" argument

Introduce a new argument to specify a comma-separated list of NSS
services to use for the "resolve-address" command. For now only accept
"dns" and "files"; the latter can be used to do a lookup into
/etc/hosts.

Note that previously the command failed in presence of extra
arguments. Therefore, when downgrading NetworkManager without
restarting the service, the previously-installed version of the daemon
(newer) would spawn the helper with the extra argument, and the
newly-installed version of the helper (older) would fail. This issue
only impacts hostname resolution and can be fixed by just restarting
the daemon.

In the upgrade path everything works as before, with the only
difference that the helper will use by default both "dns" and "files"
services.

Don't strictly check for the absence of extra arguments, so that in
the future we can introduce more arguments without necessarily break
the downgrade path.

(cherry picked from commit 229bebfae9)
(cherry picked from commit c36a74f698)
(cherry picked from commit e86ddd9fc5)
This commit is contained in:
Beniamino Galvani 2024-06-19 20:14:14 +02:00 committed by Fernando Fernandez Mancera
parent cf75343da9
commit 717db10a9d

View file

@ -55,26 +55,31 @@ cmd_version(void)
static int
cmd_resolve_address(void)
{
nm_auto_free char *address = NULL;
nm_auto_free char *address = NULL;
nm_auto_free char *services = NULL;
union {
struct sockaddr_in in;
struct sockaddr_in6 in6;
} sockaddr;
socklen_t sockaddr_size;
char name[NI_MAXHOST];
char *saveptr = NULL;
char *service;
char *str;
int ret;
address = read_arg();
if (!address)
return RETURN_INVALID_ARGS;
if (more_args())
return RETURN_INVALID_ARGS;
services = read_arg();
if (!services) {
/* Called by an old NM version which doesn't support the 'services'
* argument. Use both services. */
services = strdup("dns,files");
}
memset(&sockaddr, 0, sizeof(sockaddr));
#if defined(__GLIBC__)
__nss_configure_lookup("hosts", "dns");
#endif
if (inet_pton(AF_INET, address, &sockaddr.in.sin_addr) == 1) {
sockaddr.in.sin_family = AF_INET;
@ -85,30 +90,51 @@ cmd_resolve_address(void)
} else
return RETURN_INVALID_ARGS;
ret = getnameinfo((struct sockaddr *) &sockaddr,
sockaddr_size,
name,
sizeof(name),
NULL,
0,
NI_NAMEREQD);
if (ret != 0) {
if (ret == EAI_SYSTEM) {
for (str = services; (service = strtok_r(str, ",", &saveptr)); str = NULL) {
if (!NM_IN_STRSET(service, "dns", "files")) {
fprintf(stderr, "Unsupported resolver service '%s'\n", service);
continue;
}
#if defined(__GLIBC__)
__nss_configure_lookup("hosts", service);
#endif
ret = getnameinfo((struct sockaddr *) &sockaddr,
sockaddr_size,
name,
sizeof(name),
NULL,
0,
NI_NAMEREQD);
if (ret == 0) {
printf("%s", name);
return RETURN_SUCCESS;
} else if (ret == EAI_SYSTEM) {
char buf[1024];
int errsv = errno;
fprintf(stderr,
"getnameinfo() failed: %d (%s), system error: %d (%s)\n",
"getnameinfo() via service '%s' failed: %d (%s), system error: %d (%s)\n",
service,
ret,
gai_strerror(ret),
errno,
strerror(errno));
} else {
fprintf(stderr, "getnameinfo() failed: %d (%s)\n", ret, gai_strerror(ret));
fprintf(stderr,
"getnameinfo() via service '%s' failed: %d (%s)\n",
service,
ret,
gai_strerror(ret));
}
return RETURN_ERROR;
#if !defined(__GLIBC__)
break;
#endif
}
printf("%s", name);
return RETURN_SUCCESS;
return RETURN_ERROR;
}
int