mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-01-26 10:03:40 +03:00
nss-myhostname: various modernizations
This commit is contained in:
parent
096b677388
commit
5502f0d971
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user