return any locally configured IP address if they exist
Fall back to 127.0.0.2/::1 only if there is no proper IP address configured on any interface.
This commit is contained in:
parent
15ef6d41d6
commit
8041b5bada
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,3 +1,4 @@
|
|||
README
|
||||
.deps
|
||||
.libs
|
||||
*.cache
|
||||
|
|
14
Makefile.am
14
Makefile.am
|
@ -23,6 +23,8 @@ lib_LTLIBRARIES = libnss_myhostname.la
|
|||
EXTRA_DIST=bootstrap.sh README LICENSE
|
||||
SUBDIRS=doc
|
||||
|
||||
AM_CPPFLAGS = -include $(top_builddir)/config.h
|
||||
|
||||
MAINTAINERCLEANFILES=README
|
||||
noinst_DATA = README
|
||||
|
||||
|
@ -39,8 +41,16 @@ homepage: all dist
|
|||
|
||||
.PHONY: homepage
|
||||
|
||||
libnss_myhostname_la_SOURCES = nss-myhostname.c
|
||||
libnss_myhostname_la_LDFLAGS = -avoid-version -module -export-dynamic -shrext .so.2
|
||||
libnss_myhostname_la_SOURCES = \
|
||||
nss-myhostname.c \
|
||||
netlink.c \
|
||||
netlink.h
|
||||
|
||||
libnss_myhostname_la_LDFLAGS = \
|
||||
-avoid-version \
|
||||
-module \
|
||||
-export-dynamic \
|
||||
-shrext .so.2
|
||||
|
||||
install-exec-hook:
|
||||
rm -f $(DESTDIR)$(libdir)/libnss_myhostname.la
|
||||
|
|
|
@ -24,8 +24,10 @@ AC_INIT([nss-myhostname],[0.2],[mzzlubfganzr (at) 0pointer (dot) de])
|
|||
AC_CONFIG_SRCDIR([nss-myhostname.c])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_CONFIG_MACRO_DIR(m4)
|
||||
AC_USE_SYSTEM_EXTENSIONS
|
||||
AC_SYS_LARGEFILE
|
||||
|
||||
AM_INIT_AUTOMAKE([foreign 1.9 -Wall])
|
||||
AM_INIT_AUTOMAKE([foreign 1.9 -Wall -Wno-portability silent-rules tar-pax subdir-objects dist-bzip2])
|
||||
|
||||
AC_SUBST(PACKAGE_URL, [http://0pointer.de/lennart/projects/nss-myhostname/])
|
||||
|
||||
|
@ -34,8 +36,8 @@ ac_default_prefix="/"
|
|||
# Checks for programs.
|
||||
AC_PROG_CC
|
||||
AC_PROG_CC_C99
|
||||
AC_USE_SYSTEM_EXTENSIONS
|
||||
AC_PROG_CPP
|
||||
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_LN_S
|
||||
AC_PROG_MAKE_SET
|
||||
|
@ -50,7 +52,8 @@ done
|
|||
|
||||
# libtool stuff
|
||||
AC_DISABLE_STATIC
|
||||
AC_PROG_LIBTOOL
|
||||
LT_PREREQ(2.2)
|
||||
LT_INIT
|
||||
|
||||
# Checks for header files.
|
||||
AC_HEADER_STDC
|
||||
|
|
232
netlink.c
Normal file
232
netlink.c
Normal file
|
@ -0,0 +1,232 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of nss-myhostname.
|
||||
|
||||
Copyright 2008-2011 Lennart Poettering
|
||||
|
||||
nss-myhostname is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License
|
||||
as published by the Free Software Foundation; either version 2.1 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
nss-myhostname is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with nss-myhostname; If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <asm/types.h>
|
||||
#include <inttypes.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "netlink.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 netlink_acquire_addresses(struct address **_list, unsigned *_n_list) {
|
||||
|
||||
struct {
|
||||
struct nlmsghdr hdr;
|
||||
struct rtgenmsg gen;
|
||||
} req;
|
||||
struct rtgenmsg *gen;
|
||||
int fd, r, on = 1;
|
||||
uint32_t seq = 4711;
|
||||
struct address *list = NULL;
|
||||
unsigned n_list = 0;
|
||||
|
||||
fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
|
||||
req.hdr.nlmsg_type = RTM_GETADDR;
|
||||
req.hdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP|NLM_F_ACK;
|
||||
req.hdr.nlmsg_seq = seq;
|
||||
req.hdr.nlmsg_pid = 0;
|
||||
|
||||
gen = NLMSG_DATA(&req.hdr);
|
||||
gen->rtgen_family = AF_UNSPEC;
|
||||
|
||||
if (send(fd, &req, req.hdr.nlmsg_len, 0) < 0) {
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
ssize_t bytes;
|
||||
struct msghdr msg;
|
||||
struct cmsghdr *cmsg;
|
||||
struct ucred *ucred;
|
||||
struct iovec iov;
|
||||
struct nlmsghdr *p;
|
||||
uint8_t cred_buffer[CMSG_SPACE(sizeof(struct ucred))];
|
||||
struct {
|
||||
struct nlmsghdr hdr;
|
||||
struct ifaddrmsg ifaddrmsg;
|
||||
uint8_t payload[16*1024];
|
||||
} resp;
|
||||
|
||||
memset(&iov, 0, sizeof(iov));
|
||||
iov.iov_base = &resp;
|
||||
iov.iov_len = sizeof(resp);
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.msg_name = NULL;
|
||||
msg.msg_namelen = 0;
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_control = cred_buffer;
|
||||
msg.msg_controllen = sizeof(cred_buffer);
|
||||
msg.msg_flags = 0;
|
||||
|
||||
bytes = recvmsg(fd, &msg, 0);
|
||||
if (bytes < 0) {
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
cmsg = CMSG_FIRSTHDR(&msg);
|
||||
if (!cmsg || cmsg->cmsg_type != SCM_CREDENTIALS) {
|
||||
r = -EIO;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
ucred = (struct ucred*) CMSG_DATA(cmsg);
|
||||
if (ucred->uid != 0 || ucred->pid != 0)
|
||||
continue;
|
||||
|
||||
for (p = &resp.hdr; bytes > 0; p = NLMSG_NEXT(p, bytes)) {
|
||||
struct ifaddrmsg *ifaddrmsg;
|
||||
struct rtattr *a;
|
||||
size_t l;
|
||||
void *local = NULL, *address = NULL;
|
||||
|
||||
if (!NLMSG_OK(p, (size_t) bytes)) {
|
||||
r = -EIO;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (p->nlmsg_seq != seq)
|
||||
continue;
|
||||
|
||||
if (p->nlmsg_type == NLMSG_DONE) {
|
||||
r = 0;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (p->nlmsg_type == NLMSG_ERROR) {
|
||||
struct nlmsgerr *nlmsgerr;
|
||||
|
||||
nlmsgerr = NLMSG_DATA(p);
|
||||
r = -nlmsgerr->error;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (p->nlmsg_type != RTM_NEWADDR)
|
||||
continue;
|
||||
|
||||
ifaddrmsg = NLMSG_DATA(p);
|
||||
|
||||
if (ifaddrmsg->ifa_family != AF_INET &&
|
||||
ifaddrmsg->ifa_family != AF_INET6)
|
||||
continue;
|
||||
|
||||
if (ifaddrmsg->ifa_scope == RT_SCOPE_HOST ||
|
||||
ifaddrmsg->ifa_scope == RT_SCOPE_NOWHERE)
|
||||
continue;
|
||||
|
||||
if (ifaddrmsg->ifa_flags & IFA_F_DEPRECATED)
|
||||
continue;
|
||||
|
||||
l = NLMSG_PAYLOAD(p, sizeof(struct ifaddrmsg));
|
||||
a = IFA_RTA(ifaddrmsg);
|
||||
|
||||
while (RTA_OK(a, l)) {
|
||||
|
||||
if (a->rta_type == IFA_ADDRESS)
|
||||
address = RTA_DATA(a);
|
||||
else if (a->rta_type == IFA_LOCAL)
|
||||
local = RTA_DATA(a);
|
||||
|
||||
a = RTA_NEXT(a, l);
|
||||
}
|
||||
|
||||
if (local)
|
||||
address = local;
|
||||
|
||||
if (!address)
|
||||
continue;
|
||||
|
||||
list = realloc(list, (n_list+1) * sizeof(struct address));
|
||||
if (!list) {
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
list[n_list].family = ifaddrmsg->ifa_family;
|
||||
list[n_list].scope = ifaddrmsg->ifa_scope;
|
||||
memcpy(list[n_list].address, address, ifaddrmsg->ifa_family == AF_INET ? 4 : 16);
|
||||
list[n_list].ifindex = ifaddrmsg->ifa_index;
|
||||
|
||||
n_list++;
|
||||
}
|
||||
}
|
||||
|
||||
finish:
|
||||
close(fd);
|
||||
|
||||
if (r < 0)
|
||||
free(list);
|
||||
else {
|
||||
qsort(list, n_list, sizeof(struct address), address_compare);
|
||||
|
||||
*_list = list;
|
||||
*_n_list = n_list;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
45
netlink.h
Normal file
45
netlink.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#ifndef foonetlinkhfoo
|
||||
#define foonetlinkhfoo
|
||||
|
||||
/***
|
||||
This file is part of nss-myhostname.
|
||||
|
||||
Copyright 2008-2011 Lennart Poettering
|
||||
|
||||
nss-myhostname is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License
|
||||
as published by the Free Software Foundation; either version 2.1 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
nss-myhostname is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with nss-myhostname; If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <sys/types.h>
|
||||
#include <assert.h>
|
||||
|
||||
struct address {
|
||||
unsigned char family;
|
||||
uint8_t address[16];
|
||||
unsigned char scope;
|
||||
int ifindex;
|
||||
};
|
||||
|
||||
int netlink_acquire_addresses(struct address **_list, unsigned *_n_list);
|
||||
|
||||
static inline size_t PROTO_ADDRESS_SIZE(int proto) {
|
||||
assert(proto == AF_INET || proto == AF_INET6);
|
||||
|
||||
return proto == AF_INET6 ? 16 : 4;
|
||||
}
|
||||
|
||||
#endif
|
269
nss-myhostname.c
269
nss-myhostname.c
|
@ -1,39 +1,38 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8 -*-*/
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of nss-myhostname.
|
||||
This file is part of nss-myhostname.
|
||||
|
||||
Copyright 2008 Lennart Poettering
|
||||
Copyright 2008-2011 Lennart Poettering
|
||||
|
||||
nss-myhostname is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License
|
||||
as published by the Free Software Foundation, either version 2.1
|
||||
of the License, or (at your option) any later version.
|
||||
nss-myhostname is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License
|
||||
as published by the Free Software Foundation; either version 2.1 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
nss-myhostname is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
nss-myhostname is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with nss-myhostname. If not, If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with nss-myhostname; If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
#include <nss.h>
|
||||
#include <sys/types.h>
|
||||
#include <netdb.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <net/if.h>
|
||||
#include <stdlib.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "netlink.h"
|
||||
|
||||
/* We use 127.0.0.2 as IPv4 address. This has the advantage over
|
||||
* 127.0.0.1 that it can be translated back to the local hostname. For
|
||||
|
@ -46,6 +45,50 @@
|
|||
|
||||
#define ALIGN(a) (((a+sizeof(void*)-1)/sizeof(void*))*sizeof(void*))
|
||||
|
||||
enum nss_status _nss_myhostname_gethostbyname4_r(
|
||||
const char *name,
|
||||
struct gaih_addrtuple **pat,
|
||||
char *buffer, size_t buflen,
|
||||
int *errnop, int *h_errnop,
|
||||
int32_t *ttlp);
|
||||
|
||||
enum nss_status _nss_myhostname_gethostbyname3_r(
|
||||
const char *name,
|
||||
int af,
|
||||
struct hostent *host,
|
||||
char *buffer, size_t buflen,
|
||||
int *errnop, int *h_errnop,
|
||||
int32_t *ttlp,
|
||||
char **canonp);
|
||||
|
||||
enum nss_status _nss_myhostname_gethostbyname2_r(
|
||||
const char *name,
|
||||
int af,
|
||||
struct hostent *host,
|
||||
char *buffer, size_t buflen,
|
||||
int *errnop, int *h_errnop);
|
||||
|
||||
enum nss_status _nss_myhostname_gethostbyname_r(
|
||||
const char *name,
|
||||
struct hostent *host,
|
||||
char *buffer, size_t buflen,
|
||||
int *errnop, int *h_errnop);
|
||||
|
||||
enum nss_status _nss_myhostname_gethostbyaddr2_r(
|
||||
const void* addr, socklen_t len,
|
||||
int af,
|
||||
struct hostent *host,
|
||||
char *buffer, size_t buflen,
|
||||
int *errnop, int *h_errnop,
|
||||
int32_t *ttlp);
|
||||
|
||||
enum nss_status _nss_myhostname_gethostbyaddr_r(
|
||||
const void* addr, socklen_t len,
|
||||
int af,
|
||||
struct hostent *host,
|
||||
char *buffer, size_t buflen,
|
||||
int *errnop, int *h_errnop);
|
||||
|
||||
enum nss_status _nss_myhostname_gethostbyname4_r(
|
||||
const char *name,
|
||||
struct gaih_addrtuple **pat,
|
||||
|
@ -53,11 +96,13 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
|
|||
int *errnop, int *h_errnop,
|
||||
int32_t *ttlp) {
|
||||
|
||||
unsigned ifi;
|
||||
unsigned lo_ifi;
|
||||
char hn[HOST_NAME_MAX+1];
|
||||
size_t l, idx, ms;
|
||||
char *r_name;
|
||||
struct gaih_addrtuple *r_tuple1, *r_tuple2;
|
||||
struct gaih_addrtuple *r_tuple, *r_tuple_prev = NULL;
|
||||
struct address *addresses = NULL, *a;
|
||||
unsigned n_addresses = 0, n;
|
||||
|
||||
memset(hn, 0, sizeof(hn));
|
||||
if (gethostname(hn, sizeof(hn)-1) < 0) {
|
||||
|
@ -72,14 +117,18 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
|
|||
return NSS_STATUS_NOTFOUND;
|
||||
}
|
||||
|
||||
/* If this fails, n_addresses is 0. Which is fine */
|
||||
netlink_acquire_addresses(&addresses, &n_addresses);
|
||||
|
||||
/* If this call fails we fill in 0 as scope. Which is fine */
|
||||
ifi = if_nametoindex(LOOPBACK_INTERFACE);
|
||||
lo_ifi = if_nametoindex(LOOPBACK_INTERFACE);
|
||||
|
||||
l = strlen(hn);
|
||||
ms = ALIGN(l+1)+ALIGN(sizeof(struct gaih_addrtuple))*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;
|
||||
}
|
||||
|
||||
|
@ -88,32 +137,53 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
|
|||
memcpy(r_name, hn, l+1);
|
||||
idx = ALIGN(l+1);
|
||||
|
||||
/* Second, fill in IPv4 tuple */
|
||||
r_tuple1 = (struct gaih_addrtuple*) (buffer + idx);
|
||||
r_tuple1->next = NULL;
|
||||
r_tuple1->name = r_name;
|
||||
r_tuple1->family = AF_INET;
|
||||
*(uint32_t*) r_tuple1->addr = LOCALADDRESS_IPV4;
|
||||
r_tuple1->scopeid = (uint32_t) ifi;
|
||||
idx += ALIGN(sizeof(struct gaih_addrtuple));
|
||||
if (n_addresses <= 0) {
|
||||
/* Second, fill in IPv6 tuple */
|
||||
r_tuple = (struct gaih_addrtuple*) (buffer + idx);
|
||||
r_tuple->next = r_tuple_prev;
|
||||
r_tuple->name = r_name;
|
||||
r_tuple->family = AF_INET6;
|
||||
memcpy(r_tuple->addr, LOCALADDRESS_IPV6, 16);
|
||||
r_tuple->scopeid = (uint32_t) lo_ifi;
|
||||
|
||||
/* Third, fill in IPv6 tuple */
|
||||
r_tuple2 = (struct gaih_addrtuple*) (buffer + idx);
|
||||
r_tuple2->next = r_tuple1;
|
||||
r_tuple2->name = r_name;
|
||||
r_tuple2->family = AF_INET6;
|
||||
memcpy(r_tuple2->addr, LOCALADDRESS_IPV6, 16);
|
||||
r_tuple2->scopeid = (uint32_t) ifi;
|
||||
idx += ALIGN(sizeof(struct gaih_addrtuple));
|
||||
idx += ALIGN(sizeof(struct gaih_addrtuple));
|
||||
r_tuple_prev = r_tuple;
|
||||
|
||||
/* Third, fill in IPv4 tuple */
|
||||
r_tuple = (struct gaih_addrtuple*) (buffer + idx);
|
||||
r_tuple->next = r_tuple_prev;
|
||||
r_tuple->name = r_name;
|
||||
r_tuple->family = AF_INET;
|
||||
*(uint32_t*) r_tuple->addr = LOCALADDRESS_IPV4;
|
||||
r_tuple->scopeid = (uint32_t) lo_ifi;
|
||||
|
||||
idx += ALIGN(sizeof(struct gaih_addrtuple));
|
||||
r_tuple_prev = r_tuple;
|
||||
}
|
||||
|
||||
/* Fourth, fill actual addresses in, but in backwards order */
|
||||
for (a = addresses + n_addresses - 1, n = 0; n < n_addresses; n++, a--) {
|
||||
r_tuple = (struct gaih_addrtuple*) (buffer + idx);
|
||||
r_tuple->next = r_tuple_prev;
|
||||
r_tuple->name = r_name;
|
||||
r_tuple->family = a->family;
|
||||
r_tuple->scopeid = a->ifindex;
|
||||
memcpy(r_tuple->addr, a->address, 16);
|
||||
|
||||
idx += ALIGN(sizeof(struct gaih_addrtuple));
|
||||
r_tuple_prev = r_tuple;
|
||||
}
|
||||
|
||||
/* Verify the size matches */
|
||||
assert(idx == ms);
|
||||
|
||||
*pat = r_tuple2;
|
||||
*pat = r_tuple_prev;
|
||||
|
||||
if (ttlp)
|
||||
*ttlp = 0;
|
||||
|
||||
free(addresses);
|
||||
|
||||
return NSS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -129,14 +199,27 @@ static enum nss_status fill_in_hostent(
|
|||
size_t l, idx, ms;
|
||||
char *r_addr, *r_name, *r_aliases, *r_addr_list;
|
||||
size_t alen;
|
||||
struct address *addresses = NULL, *a;
|
||||
unsigned n_addresses = 0, n, c;
|
||||
|
||||
alen = af == AF_INET ? 4 : 16;
|
||||
alen = PROTO_ADDRESS_SIZE(af);
|
||||
|
||||
netlink_acquire_addresses(&addresses, &n_addresses);
|
||||
|
||||
for (a = addresses, n = 0, c = 0; n < n_addresses; a++, n++)
|
||||
if (af == a->family)
|
||||
c++;
|
||||
|
||||
l = strlen(hn);
|
||||
ms = ALIGN(l+1)+sizeof(char*)+ALIGN(alen)+sizeof(char*)*2;
|
||||
ms = ALIGN(l+1)+
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -145,24 +228,57 @@ static enum nss_status fill_in_hostent(
|
|||
memcpy(r_name, hn, l+1);
|
||||
idx = ALIGN(l+1);
|
||||
|
||||
/* Second, create aliases array */
|
||||
/* Second, create (empty) aliases array */
|
||||
r_aliases = buffer + idx;
|
||||
*(char**) r_aliases = NULL;
|
||||
idx += sizeof(char*);
|
||||
|
||||
/* Third, add address */
|
||||
/* Third, add addresses */
|
||||
r_addr = buffer + idx;
|
||||
if (af == AF_INET)
|
||||
*(uint32_t*) r_addr = LOCALADDRESS_IPV4;
|
||||
else
|
||||
memcpy(r_addr, LOCALADDRESS_IPV6, 16);
|
||||
idx += ALIGN(alen);
|
||||
if (c > 0) {
|
||||
unsigned i = 0;
|
||||
|
||||
for (a = addresses, n = 0; n < n_addresses; a++, n++) {
|
||||
if (af != a->family)
|
||||
continue;
|
||||
|
||||
memcpy(r_addr + i*ALIGN(alen), a->address, alen);
|
||||
i++;
|
||||
}
|
||||
|
||||
assert(i == c);
|
||||
idx += c*ALIGN(alen);
|
||||
} else {
|
||||
if (af == AF_INET)
|
||||
*(uint32_t*) r_addr = LOCALADDRESS_IPV4;
|
||||
else
|
||||
memcpy(r_addr, LOCALADDRESS_IPV6, 16);
|
||||
|
||||
idx += ALIGN(alen);
|
||||
}
|
||||
|
||||
/* Fourth, add address pointer array */
|
||||
r_addr_list = buffer + idx;
|
||||
((char**) r_addr_list)[0] = r_addr;
|
||||
((char**) r_addr_list)[1] = NULL;
|
||||
idx += sizeof(char*)*2;
|
||||
if (c > 0) {
|
||||
unsigned i = 0;
|
||||
|
||||
for (a = addresses, n = 0; n < n_addresses; a++, n++) {
|
||||
if (af != a->family)
|
||||
continue;
|
||||
|
||||
((char**) r_addr_list)[i] = (r_addr + i*ALIGN(alen));
|
||||
i++;
|
||||
}
|
||||
|
||||
assert(i == c);
|
||||
((char**) r_addr_list)[c] = NULL;
|
||||
idx += (c+1)*sizeof(char*);
|
||||
|
||||
} else {
|
||||
((char**) r_addr_list)[0] = r_addr;
|
||||
((char**) r_addr_list)[1] = NULL;
|
||||
idx += 2*sizeof(char*);
|
||||
}
|
||||
|
||||
/* Verify the size matches */
|
||||
assert(idx == ms);
|
||||
|
@ -179,6 +295,8 @@ static enum nss_status fill_in_hostent(
|
|||
if (canonp)
|
||||
*canonp = r_name;
|
||||
|
||||
free(addresses);
|
||||
|
||||
return NSS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -235,7 +353,7 @@ enum nss_status _nss_myhostname_gethostbyname2_r(
|
|||
NULL);
|
||||
}
|
||||
|
||||
enum nss_status _nss_myhostname_gethostbyname_r (
|
||||
enum nss_status _nss_myhostname_gethostbyname_r(
|
||||
const char *name,
|
||||
struct hostent *host,
|
||||
char *buffer, size_t buflen,
|
||||
|
@ -260,35 +378,60 @@ enum nss_status _nss_myhostname_gethostbyaddr2_r(
|
|||
int32_t *ttlp) {
|
||||
|
||||
char hn[HOST_NAME_MAX+1];
|
||||
struct address *addresses = NULL, *a;
|
||||
unsigned n_addresses = 0, n;
|
||||
|
||||
if (len != PROTO_ADDRESS_SIZE(af)) {
|
||||
*errnop = EINVAL;
|
||||
*h_errnop = NO_RECOVERY;
|
||||
return NSS_STATUS_UNAVAIL;
|
||||
}
|
||||
|
||||
if (af == AF_INET) {
|
||||
if (len != 4 ||
|
||||
(*(uint32_t*) addr) != LOCALADDRESS_IPV4)
|
||||
goto not_found;
|
||||
|
||||
if ((*(uint32_t*) addr) == LOCALADDRESS_IPV4)
|
||||
goto found;
|
||||
|
||||
} else if (af == AF_INET6) {
|
||||
if (len != 16 ||
|
||||
memcmp(addr, LOCALADDRESS_IPV6, 16) != 0)
|
||||
goto not_found;
|
||||
|
||||
if (memcmp(addr, LOCALADDRESS_IPV6, 16) == 0)
|
||||
goto found;
|
||||
|
||||
} else {
|
||||
*errnop = EAFNOSUPPORT;
|
||||
*h_errnop = NO_DATA;
|
||||
return NSS_STATUS_UNAVAIL;
|
||||
}
|
||||
|
||||
netlink_acquire_addresses(&addresses, &n_addresses);
|
||||
|
||||
for (a = addresses, n = 0; n < n_addresses; n++, a++) {
|
||||
if (af != a->family)
|
||||
continue;
|
||||
|
||||
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:
|
||||
free(addresses);
|
||||
|
||||
memset(hn, 0, sizeof(hn));
|
||||
if (gethostname(hn, sizeof(hn)-1) < 0) {
|
||||
*errnop = errno;
|
||||
*h_errnop = NO_RECOVERY;
|
||||
|
||||
return NSS_STATUS_UNAVAIL;
|
||||
}
|
||||
|
||||
return fill_in_hostent(hn, af, host, buffer, buflen, errnop, h_errnop, ttlp, NULL);
|
||||
|
||||
not_found:
|
||||
*errnop = ENOENT;
|
||||
*h_errnop = HOST_NOT_FOUND;
|
||||
return NSS_STATUS_NOTFOUND;
|
||||
}
|
||||
|
||||
enum nss_status _nss_myhostname_gethostbyaddr_r(
|
||||
|
|
Loading…
Reference in a new issue