nss-resolve: use resolve-varlink-util.h helpers

Re-factor using the shared code introduced for resolvectl.
This commit is contained in:
Nick Rosbrook
2026-06-26 16:03:18 -04:00
parent 3ecf3aba94
commit 4e1943a209
+45 -196
View File
@@ -14,6 +14,7 @@
#include "json-util.h"
#include "netlink-util.h"
#include "nss-util.h"
#include "resolve-varlink-util.h"
#include "resolved-def.h"
#include "signal-util.h"
#include "string-util.h"
@@ -64,90 +65,6 @@ static int connect_to_resolved(sd_varlink **ret) {
return 0;
}
static uint32_t ifindex_to_scopeid(int family, const void *a, int ifindex) {
struct in6_addr in6;
if (family != AF_INET6 || ifindex == 0)
return 0;
/* Some apps can't deal with the scope ID attached to non-link-local addresses. Hence, let's suppress that. */
assert(sizeof(in6) == FAMILY_ADDRESS_SIZE(AF_INET6));
memcpy(&in6, a, sizeof(struct in6_addr));
return in6_addr_is_link_local(&in6) ? ifindex : 0;
}
typedef struct ResolveHostnameReply {
sd_json_variant *addresses;
char *name;
uint64_t flags;
} ResolveHostnameReply;
static void resolve_hostname_reply_destroy(ResolveHostnameReply *p) {
assert(p);
sd_json_variant_unref(p->addresses);
free(p->name);
}
static const sd_json_dispatch_field resolve_hostname_reply_dispatch_table[] = {
{ "addresses", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_variant, offsetof(ResolveHostnameReply, addresses), SD_JSON_MANDATORY },
{ "name", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(ResolveHostnameReply, name), 0 },
{ "flags", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(ResolveHostnameReply, flags), 0 },
{}
};
typedef struct AddressParameters {
int ifindex;
int family;
union in_addr_union address;
size_t address_size;
} AddressParameters;
static int json_dispatch_address(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
AddressParameters *p = ASSERT_PTR(userdata);
union in_addr_union buf = {};
sd_json_variant *i;
size_t n, k = 0;
assert(variant);
if (!sd_json_variant_is_array(variant))
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an array.", strna(name));
n = sd_json_variant_elements(variant);
if (!IN_SET(n, 4, 16))
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is array of unexpected size.", strna(name));
JSON_VARIANT_ARRAY_FOREACH(i, variant) {
int64_t b;
if (!sd_json_variant_is_integer(i))
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "Element %zu of JSON field '%s' is not an integer.", k, strna(name));
b = sd_json_variant_integer(i);
if (b < 0 || b > 0xff)
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL),
"Element %zu of JSON field '%s' is out of range 0%s255.",
k, strna(name), glyph(GLYPH_ELLIPSIS));
buf.bytes[k++] = (uint8_t) b;
}
p->address = buf;
p->address_size = k;
return 0;
}
static const sd_json_dispatch_field address_parameters_dispatch_table[] = {
{ "ifindex", SD_JSON_VARIANT_INTEGER, json_dispatch_ifindex, offsetof(AddressParameters, ifindex), 0 },
{ "family", SD_JSON_VARIANT_INTEGER, json_dispatch_address_family, offsetof(AddressParameters, family), SD_JSON_MANDATORY },
{ "address", SD_JSON_VARIANT_ARRAY, json_dispatch_address, 0, SD_JSON_MANDATORY },
{}
};
static uint64_t query_flag(
const char *name,
const int value,
@@ -191,6 +108,19 @@ static int query_ifindex(void) {
return ifindex;
}
static uint32_t ifindex_to_scopeid(ResolvedAddress *addr) {
assert(addr);
if (addr->family != AF_INET6 || addr->ifindex == 0)
return 0;
/* Some apps can't deal with the scope ID attached to non-link-local addresses. Hence, let's suppress that. */
if (in6_addr_is_link_local(&addr->in_addr.address.in6))
return addr->ifindex;
return 0;
}
enum nss_status _nss_resolve_gethostbyname4_r(
const char *name,
struct gaih_addrtuple **pat,
@@ -200,8 +130,8 @@ enum nss_status _nss_resolve_gethostbyname4_r(
_cleanup_(sd_varlink_unrefp) sd_varlink *link = NULL;
_cleanup_(sd_json_variant_unrefp) sd_json_variant *cparams = NULL;
_cleanup_(resolve_hostname_reply_destroy) ResolveHostnameReply p = {};
sd_json_variant *rparams, *entry;
_cleanup_(resolve_hostname_reply_done) ResolveHostnameReply p = {};
sd_json_variant *rparams;
int r;
PROTECT_ERRNO;
@@ -244,28 +174,17 @@ enum nss_status _nss_resolve_gethostbyname4_r(
goto not_found;
}
r = sd_json_dispatch(rparams, resolve_hostname_reply_dispatch_table, nss_json_dispatch_flags, &p);
r = dispatch_resolve_hostname_reply(NULL, rparams, nss_json_dispatch_flags, &p);
if (r < 0)
goto fail;
if (sd_json_variant_is_blank_array(p.addresses))
if (p.n_addresses == 0)
goto not_found;
size_t n_addresses = 0;
JSON_VARIANT_ARRAY_FOREACH(entry, p.addresses) {
AddressParameters q = {};
r = sd_json_dispatch(entry, address_parameters_dispatch_table, nss_json_dispatch_flags, &q);
if (r < 0)
goto fail;
if (!IN_SET(q.family, AF_INET, AF_INET6))
FOREACH_ARRAY(entry, p.addresses, p.n_addresses) {
if (!IN_SET(entry->family, AF_INET, AF_INET6))
continue;
if (q.address_size != FAMILY_ADDRESS_SIZE(q.family)) {
r = -EINVAL;
goto fail;
}
n_addresses++;
}
@@ -292,22 +211,16 @@ enum nss_status _nss_resolve_gethostbyname4_r(
struct gaih_addrtuple *r_tuple = NULL,
*r_tuple_first = (struct gaih_addrtuple*) (buffer + idx);
JSON_VARIANT_ARRAY_FOREACH(entry, p.addresses) {
AddressParameters q = {};
r = sd_json_dispatch(entry, address_parameters_dispatch_table, nss_json_dispatch_flags, &q);
if (r < 0)
goto fail;
if (!IN_SET(q.family, AF_INET, AF_INET6))
FOREACH_ARRAY(entry, p.addresses, p.n_addresses) {
if (!IN_SET(entry->family, AF_INET, AF_INET6))
continue;
r_tuple = (struct gaih_addrtuple*) (buffer + idx);
r_tuple->next = (struct gaih_addrtuple*) ((char*) r_tuple + ALIGN(sizeof(struct gaih_addrtuple)));
r_tuple->name = r_name;
r_tuple->family = q.family;
r_tuple->scopeid = ifindex_to_scopeid(q.family, &q.address, q.ifindex);
memcpy(r_tuple->addr, &q.address, q.address_size);
r_tuple->family = entry->family;
r_tuple->scopeid = ifindex_to_scopeid(entry);
memcpy(r_tuple->addr, entry->in_addr.address.bytes, FAMILY_ADDRESS_SIZE_SAFE(entry->family));
idx += ALIGN(sizeof(struct gaih_addrtuple));
}
@@ -364,8 +277,8 @@ enum nss_status _nss_resolve_gethostbyname3_r(
_cleanup_(sd_varlink_unrefp) sd_varlink *link = NULL;
_cleanup_(sd_json_variant_unrefp) sd_json_variant *cparams = NULL;
_cleanup_(resolve_hostname_reply_destroy) ResolveHostnameReply p = {};
sd_json_variant *rparams, *entry;
_cleanup_(resolve_hostname_reply_done) ResolveHostnameReply p = {};
sd_json_variant *rparams;
int r;
PROTECT_ERRNO;
@@ -412,28 +325,17 @@ enum nss_status _nss_resolve_gethostbyname3_r(
goto not_found;
}
r = sd_json_dispatch(rparams, resolve_hostname_reply_dispatch_table, nss_json_dispatch_flags, &p);
r = dispatch_resolve_hostname_reply(NULL, rparams, nss_json_dispatch_flags, &p);
if (r < 0)
goto fail;
if (sd_json_variant_is_blank_array(p.addresses))
if (p.n_addresses == 0)
goto no_data;
size_t n_addresses = 0;
JSON_VARIANT_ARRAY_FOREACH(entry, p.addresses) {
AddressParameters q = {};
r = sd_json_dispatch(entry, address_parameters_dispatch_table, nss_json_dispatch_flags, &q);
if (r < 0)
goto fail;
if (q.family != af)
FOREACH_ARRAY(entry, p.addresses, p.n_addresses) {
if (entry->family != af)
continue;
if (q.address_size != FAMILY_ADDRESS_SIZE(q.family)) {
r = -EINVAL;
goto fail;
}
n_addresses++;
}
@@ -468,22 +370,16 @@ enum nss_status _nss_resolve_gethostbyname3_r(
char *r_addr = buffer + idx;
size_t i = 0;
JSON_VARIANT_ARRAY_FOREACH(entry, p.addresses) {
AddressParameters q = {};
r = sd_json_dispatch(entry, address_parameters_dispatch_table, nss_json_dispatch_flags, &q);
if (r < 0)
goto fail;
if (q.family != af)
FOREACH_ARRAY(entry, p.addresses, p.n_addresses) {
if (entry->family != af)
continue;
if (q.address_size != alen) {
if (FAMILY_ADDRESS_SIZE_SAFE(entry->family) != alen) {
r = -EINVAL;
goto fail;
}
memcpy(r_addr + i*ALIGN(alen), &q.address, alen);
memcpy(r_addr + i*ALIGN(alen), entry->in_addr.address.bytes, alen);
i++;
}
@@ -540,40 +436,6 @@ try_again:
return NSS_STATUS_TRYAGAIN;
}
typedef struct ResolveAddressReply {
sd_json_variant *names;
uint64_t flags;
} ResolveAddressReply;
static void resolve_address_reply_destroy(ResolveAddressReply *p) {
assert(p);
sd_json_variant_unref(p->names);
}
static const sd_json_dispatch_field resolve_address_reply_dispatch_table[] = {
{ "names", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_variant, offsetof(ResolveAddressReply, names), SD_JSON_MANDATORY },
{ "flags", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(ResolveAddressReply, flags), 0 },
{}
};
typedef struct NameParameters {
int ifindex;
char *name;
} NameParameters;
static void name_parameters_destroy(NameParameters *p) {
assert(p);
free(p->name);
}
static const sd_json_dispatch_field name_parameters_dispatch_table[] = {
{ "ifindex", SD_JSON_VARIANT_INTEGER, json_dispatch_ifindex, offsetof(NameParameters, ifindex), 0 },
{ "name", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(NameParameters, name), SD_JSON_MANDATORY },
{}
};
enum nss_status _nss_resolve_gethostbyaddr2_r(
const void* addr, socklen_t len,
int af,
@@ -584,8 +446,8 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
_cleanup_(sd_varlink_unrefp) sd_varlink *link = NULL;
_cleanup_(sd_json_variant_unrefp) sd_json_variant *cparams = NULL;
_cleanup_(resolve_address_reply_destroy) ResolveAddressReply p = {};
sd_json_variant *rparams, *entry;
_cleanup_(resolve_address_reply_done) ResolveAddressReply p = {};
sd_json_variant *rparams;
int r;
PROTECT_ERRNO;
@@ -634,25 +496,18 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
goto not_found;
}
r = sd_json_dispatch(rparams, resolve_address_reply_dispatch_table, nss_json_dispatch_flags, &p);
r = dispatch_resolve_address_reply(NULL, rparams, nss_json_dispatch_flags, &p);
if (r < 0)
goto fail;
if (sd_json_variant_is_blank_array(p.names))
if (p.n_names == 0)
goto not_found;
size_t ms = 0, idx;
JSON_VARIANT_ARRAY_FOREACH(entry, p.names) {
_cleanup_(name_parameters_destroy) NameParameters q = {};
FOREACH_ARRAY(entry, p.names, p.n_names)
ms += ALIGN(strlen(entry->name) + 1);
r = sd_json_dispatch(entry, name_parameters_dispatch_table, nss_json_dispatch_flags, &q);
if (r < 0)
goto fail;
ms += ALIGN(strlen(q.name) + 1);
}
size_t n_names = sd_json_variant_elements(p.names);
size_t n_names = p.n_names;
ms += ALIGN(len) + /* the address */
2 * sizeof(char*) + /* pointer to the address, plus trailing NULL */
n_names * sizeof(char*); /* pointers to aliases, plus trailing NULL */
@@ -683,16 +538,10 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
char *r_name = buffer + idx;
size_t i = 0;
JSON_VARIANT_ARRAY_FOREACH(entry, p.names) {
_cleanup_(name_parameters_destroy) NameParameters q = {};
r = sd_json_dispatch(entry, name_parameters_dispatch_table, nss_json_dispatch_flags, &q);
if (r < 0)
goto fail;
size_t l = strlen(q.name);
FOREACH_ARRAY(entry, p.names, p.n_names) {
size_t l = strlen(entry->name);
char *z = buffer + idx;
memcpy(z, q.name, l + 1);
memcpy(z, entry->name, l + 1);
if (i > 0)
((char**) r_aliases)[i - 1] = z;