nss-myhostname: various modernizations

This commit is contained in:
Lennart Poettering 2014-07-10 19:55:53 +02:00
parent 096b677388
commit 5502f0d971
3 changed files with 120 additions and 120 deletions

View file

@ -26,43 +26,19 @@
#include <assert.h>
#include <sys/socket.h>
#include "socket-util.h"
struct address {
unsigned char family;
uint8_t address[16];
union in_addr_union address;
unsigned char scope;
int ifindex;
};
#define _public_ __attribute__ ((visibility("default")))
#define _hidden_ __attribute__ ((visibility("hidden")))
int ifconf_acquire_addresses(struct address **_list, unsigned *_n_list) _hidden_;
static inline size_t PROTO_ADDRESS_SIZE(int proto) {
assert(proto == AF_INET || proto == AF_INET6);
return proto == AF_INET6 ? 16 : 4;
}
static inline int address_compare(const void *_a, const void *_b) {
const struct address *a = _a, *b = _b;
/* Order lowest scope first, IPv4 before IPv6, lowest interface index first */
if (a->scope < b->scope)
return -1;
if (a->scope > b->scope)
return 1;
if (a->family == AF_INET && b->family == AF_INET6)
return -1;
if (a->family == AF_INET6 && b->family == AF_INET)
return 1;
if (a->ifindex < b->ifindex)
return -1;
if (a->ifindex > b->ifindex)
return 1;
return 0;
}
int ifconf_acquire_addresses(struct address **_list, unsigned *_n_list);

View file

@ -23,16 +23,37 @@
#include "sd-rtnl.h"
#include "rtnl-util.h"
#include "macro.h"
#include "ifconf.h"
static int address_compare(const void *_a, const void *_b) {
const struct address *a = _a, *b = _b;
/* Order lowest scope first, IPv4 before IPv6, lowest interface index first */
if (a->scope < b->scope)
return -1;
if (a->scope > b->scope)
return 1;
if (a->family == AF_INET && b->family == AF_INET6)
return -1;
if (a->family == AF_INET6 && b->family == AF_INET)
return 1;
if (a->ifindex < b->ifindex)
return -1;
if (a->ifindex > b->ifindex)
return 1;
return 0;
}
int ifconf_acquire_addresses(struct address **_list, unsigned *_n_list) {
_cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
_cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
sd_rtnl_message *m;
_cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
_cleanup_free_ struct address *list = NULL;
struct address *new_list = NULL;
unsigned n_list = 0;
size_t n_list = 0, n_allocated = 0;
sd_rtnl_message *m;
int r;
r = sd_rtnl_open(&rtnl, 0);
@ -46,18 +67,11 @@ int ifconf_acquire_addresses(struct address **_list, unsigned *_n_list) {
r = sd_rtnl_call(rtnl, req, 0, &reply);
if (r < 0)
return r;
m = reply;
do {
uint16_t type;
unsigned char scope;
for (m = reply; m; m = sd_rtnl_message_next(m)) {
struct address *a;
unsigned char flags;
unsigned char family;
int ifindex;
union {
struct in_addr in;
struct in6_addr in6;
} address;
uint16_t type;
r = sd_rtnl_message_get_errno(m);
if (r < 0)
@ -70,13 +84,6 @@ int ifconf_acquire_addresses(struct address **_list, unsigned *_n_list) {
if (type != RTM_NEWADDR)
continue;
r = sd_rtnl_message_addr_get_scope(m, &scope);
if (r < 0)
return r;
if (scope == RT_SCOPE_HOST || scope == RT_SCOPE_NOWHERE)
continue;
r = sd_rtnl_message_addr_get_flags(m, &flags);
if (r < 0)
return r;
@ -84,58 +91,59 @@ int ifconf_acquire_addresses(struct address **_list, unsigned *_n_list) {
if (flags & IFA_F_DEPRECATED)
continue;
r = sd_rtnl_message_addr_get_family(m, &family);
if (!GREEDY_REALLOC(list, n_allocated, n_list+1))
return -ENOMEM;
a = list + n_list;
r = sd_rtnl_message_addr_get_scope(m, &a->scope);
if (r < 0)
return r;
switch (family) {
if (a->scope == RT_SCOPE_HOST || a->scope == RT_SCOPE_NOWHERE)
continue;
r = sd_rtnl_message_addr_get_family(m, &a->family);
if (r < 0)
return r;
switch (a->family) {
case AF_INET:
r = sd_rtnl_message_read_in_addr(m, IFA_LOCAL, &address.in);
r = sd_rtnl_message_read_in_addr(m, IFA_LOCAL, &a->address.in);
if (r < 0) {
r = sd_rtnl_message_read_in_addr(m, IFA_ADDRESS, &address.in);
r = sd_rtnl_message_read_in_addr(m, IFA_ADDRESS, &a->address.in);
if (r < 0)
continue;
}
break;
case AF_INET6:
r = sd_rtnl_message_read_in6_addr(m, IFA_LOCAL, &address.in6);
r = sd_rtnl_message_read_in6_addr(m, IFA_LOCAL, &a->address.in6);
if (r < 0) {
r = sd_rtnl_message_read_in6_addr(m, IFA_ADDRESS, &address.in6);
r = sd_rtnl_message_read_in6_addr(m, IFA_ADDRESS, &a->address.in6);
if (r < 0)
continue;
}
break;
default:
continue;
}
r = sd_rtnl_message_addr_get_ifindex(m, &ifindex);
r = sd_rtnl_message_addr_get_ifindex(m, &a->ifindex);
if (r < 0)
return r;
new_list = realloc(list, (n_list+1) * sizeof(struct address));
if (!new_list)
return -ENOMEM;
else
list = new_list;
assert_cc(sizeof(address) <= 16);
list[n_list].family = family;
list[n_list].scope = scope;
memcpy(list[n_list].address, &address, sizeof(address));
list[n_list].ifindex = ifindex;
n_list++;
} while ((m = sd_rtnl_message_next(m)));
};
if (n_list)
qsort(list, n_list, sizeof(struct address), address_compare);
*_n_list = n_list;
*_list = list;
list = NULL;
*_n_list = n_list;
return 0;
}

View file

@ -98,32 +98,39 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
int *errnop, int *h_errnop,
int32_t *ttlp) {
unsigned lo_ifi;
char hn[HOST_NAME_MAX+1] = {};
const char *canonical = NULL;
size_t l, idx, ms;
char *r_name;
struct gaih_addrtuple *r_tuple, *r_tuple_prev = NULL;
struct address *addresses = NULL, *a;
_cleanup_free_ struct address *addresses = NULL;
_cleanup_free_ char *hn = NULL;
const char *canonical = NULL;
unsigned n_addresses = 0, n;
uint32_t local_address_ipv4;
struct address *a;
size_t l, idx, ms;
char *r_name;
int lo_ifi;
if (strcasecmp(name, "localhost") == 0) {
assert(name);
assert(pat);
assert(buffer);
assert(errnop);
assert(h_errnop);
if (is_localhost(name)) {
/* We respond to 'localhost', so that /etc/hosts
* is optional */
canonical = "localhost";
local_address_ipv4 = htonl(INADDR_LOOPBACK);
} else {
/* We respond to our local host name */
if (gethostname(hn, sizeof(hn)-1) < 0) {
*errnop = errno;
hn = gethostname_malloc();
if (!hn) {
*errnop = ENOMEM;
*h_errnop = NO_RECOVERY;
return NSS_STATUS_UNAVAIL;
return NSS_STATUS_TRYAGAIN;
}
if (strcasecmp(name, hn) != 0) {
/* We respond to our local host name, our our hostname suffixed with a single dot. */
if (!streq(name, hn) && !streq_ptr(startswith(name, hn), ".")) {
*errnop = ENOENT;
*h_errnop = HOST_NOT_FOUND;
return NSS_STATUS_NOTFOUND;
@ -140,11 +147,10 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
lo_ifi = n_addresses <= 0 ? if_nametoindex(LOOPBACK_INTERFACE) : 0;
l = strlen(canonical);
ms = ALIGN(l+1)+ALIGN(sizeof(struct gaih_addrtuple))*(n_addresses > 0 ? n_addresses : 2);
ms = ALIGN(l+1) + ALIGN(sizeof(struct gaih_addrtuple)) * (n_addresses > 0 ? n_addresses : 2);
if (buflen < ms) {
*errnop = ENOMEM;
*h_errnop = NO_RECOVERY;
free(addresses);
return NSS_STATUS_TRYAGAIN;
}
@ -184,7 +190,7 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
r_tuple->name = r_name;
r_tuple->family = a->family;
r_tuple->scopeid = a->ifindex;
memcpy(r_tuple->addr, a->address, 16);
memcpy(r_tuple->addr, &a->address, 16);
idx += ALIGN(sizeof(struct gaih_addrtuple));
r_tuple_prev = r_tuple;
@ -202,8 +208,6 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
if (ttlp)
*ttlp = 0;
free(addresses);
return NSS_STATUS_SUCCESS;
}
@ -224,6 +228,12 @@ static enum nss_status fill_in_hostent(
struct address *a;
unsigned n, c;
assert(canonical);
assert(result);
assert(buffer);
assert(errnop);
assert(h_errnop);
alen = PROTO_ADDRESS_SIZE(af);
for (a = addresses, n = 0, c = 0; n < n_addresses; a++, n++)
@ -234,15 +244,14 @@ static enum nss_status fill_in_hostent(
l_additional = additional ? strlen(additional) : 0;
ms = ALIGN(l_canonical+1)+
(additional ? ALIGN(l_additional+1) : 0) +
sizeof(char*)+
sizeof(char*) +
(additional ? sizeof(char*) : 0) +
(c > 0 ? c : 1)*ALIGN(alen)+
(c > 0 ? c+1 : 2)*sizeof(char*);
(c > 0 ? c : 1) * ALIGN(alen)+
(c > 0 ? c+1 : 2) * sizeof(char*);
if (buflen < ms) {
*errnop = ENOMEM;
*h_errnop = NO_RECOVERY;
free(addresses);
return NSS_STATUS_TRYAGAIN;
}
@ -277,7 +286,7 @@ static enum nss_status fill_in_hostent(
if (af != a->family)
continue;
memcpy(r_addr + i*ALIGN(alen), a->address, alen);
memcpy(r_addr + i*ALIGN(alen), &a->address, alen);
i++;
}
@ -330,8 +339,6 @@ static enum nss_status fill_in_hostent(
if (canonp)
*canonp = r_name;
free(addresses);
return NSS_STATUS_SUCCESS;
}
@ -344,11 +351,17 @@ enum nss_status _nss_myhostname_gethostbyname3_r(
int32_t *ttlp,
char **canonp) {
char hn[HOST_NAME_MAX+1] = {};
struct address *addresses = NULL;
unsigned n_addresses = 0;
_cleanup_free_ struct address *addresses = NULL;
const char *canonical, *additional = NULL;
_cleanup_free_ char *hn = NULL;
uint32_t local_address_ipv4;
unsigned n_addresses = 0;
assert(name);
assert(host);
assert(buffer);
assert(errnop);
assert(h_errnop);
if (af == AF_UNSPEC)
af = AF_INET;
@ -359,17 +372,18 @@ enum nss_status _nss_myhostname_gethostbyname3_r(
return NSS_STATUS_UNAVAIL;
}
if (strcasecmp(name, "localhost") == 0) {
if (is_localhost(name)) {
canonical = "localhost";
local_address_ipv4 = htonl(INADDR_LOOPBACK);
} else {
if (gethostname(hn, sizeof(hn)-1) < 0) {
*errnop = errno;
hn = gethostname_malloc();
if (!hn) {
*errnop = ENOMEM;
*h_errnop = NO_RECOVERY;
return NSS_STATUS_UNAVAIL;
return NSS_STATUS_TRYAGAIN;
}
if (strcasecmp(name, hn) != 0) {
if (!streq(name, hn) && !streq_ptr(startswith(name, hn), ".")) {
*errnop = ENOENT;
*h_errnop = HOST_NOT_FOUND;
return NSS_STATUS_NOTFOUND;
@ -435,12 +449,18 @@ enum nss_status _nss_myhostname_gethostbyaddr2_r(
int *errnop, int *h_errnop,
int32_t *ttlp) {
char hn[HOST_NAME_MAX+1] = {};
struct address *addresses = NULL;
struct address *a;
unsigned n_addresses = 0, n;
uint32_t local_address_ipv4 = LOCALADDRESS_IPV4;
const char *canonical = NULL, *additional = NULL;
uint32_t local_address_ipv4 = LOCALADDRESS_IPV4;
_cleanup_free_ struct address *addresses = NULL;
_cleanup_free_ char *hn = NULL;
unsigned n_addresses = 0, n;
struct address *a;
assert(addr);
assert(host);
assert(buffer);
assert(errnop);
assert(h_errnop);
if (len != PROTO_ADDRESS_SIZE(af)) {
*errnop = EINVAL;
@ -478,26 +498,22 @@ enum nss_status _nss_myhostname_gethostbyaddr2_r(
if (af != a->family)
continue;
if (memcmp(addr, a->address, PROTO_ADDRESS_SIZE(af)) == 0)
if (memcmp(addr, &a->address, PROTO_ADDRESS_SIZE(af)) == 0)
goto found;
}
*errnop = ENOENT;
*h_errnop = HOST_NOT_FOUND;
free(addresses);
return NSS_STATUS_NOTFOUND;
found:
if (!canonical) {
if (gethostname(hn, sizeof(hn)-1) < 0) {
*errnop = errno;
hn = gethostname_malloc();
if (!hn) {
*errnop = ENOMEM;
*h_errnop = NO_RECOVERY;
free(addresses);
return NSS_STATUS_UNAVAIL;
return NSS_STATUS_TRYAGAIN;
}
canonical = hn;