Skip to content

Instantly share code, notes, and snippets.

@pandax381
Created October 27, 2016 09:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pandax381/a96b7fc08af533d5d868209d6bb49b17 to your computer and use it in GitHub Desktop.
Save pandax381/a96b7fc08af533d5d868209d6bb49b17 to your computer and use it in GitHub Desktop.
#include <limits.h>
#include <nss.h>
#include <sys/types.h>
#include <netdb.h>
#include <errno.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <net/if.h>
#include <stdlib.h>
#include <arpa/inet.h>
#ifdef DEBUG
#include <syslog.h>
#define DBG_TRACE syslog(LOG_DEBUG, "dbg_trace: %s (%d)\n", __FILE__, __LINE__)
#else
#define DBG_TRACE
#endif
#define LOCALADDRESS_IPV4 (htonl(0x7F000002))
#define LOCALADDRESS_IPV6 &in6addr_loopback
#define LOOPBACK_INTERFACE "lo"
#define ALIGN(a) (((a+sizeof(void*)-1)/sizeof(void*))*sizeof(void*))
#define _public_ __attribute__ ((visibility("default")))
inline size_t PROTO_ADDRESS_SIZE(int proto) {
assert(proto == AF_INET || proto == AF_INET6);
return proto == AF_INET6 ? 16 : 4;
}
enum nss_status
_nss_dummy_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, char *buffer, size_t buflen, int *errnop, int *h_errnop, int32_t *ttlp) _public_;
enum nss_status
_nss_dummy_gethostbyname3_r (const char *name, int af, struct hostent *result, char *buffer, size_t buflen, int *errnop, int *h_errnop, int32_t *ttlp, char **canonp) _public_;
enum nss_status
_nss_dummy_gethostbyname2_r (const char *name, int af, struct hostent *result, char *buffer, size_t buflen, int *errnop, int *h_errnop) _public_;
enum nss_status
_nss_dummy_gethostbyname_r (const char *name, struct hostent *result, char *buffer, size_t buflen, int *errnop, int *h_errnop) _public_;
enum nss_status
_nss_dummy_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) _public_;
enum nss_status
_nss_dummy_gethostbyaddr_r (const void* addr, socklen_t len, int af, struct hostent *result, char *buffer, size_t buflen, int *errnop, int *h_errnop) _public_;
enum nss_status
_nss_dummy_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, char *buffer, size_t buflen, int *errnop, int *h_errnop, int32_t *ttlp)
{
unsigned index;
size_t n, offset, size;
char *hostname;
struct gaih_addrtuple *tuple, *prev = NULL;
DBG_TRACE;
index = if_nametoindex(LOOPBACK_INTERFACE);
n = strlen(name) + 1;
size = ALIGN(n) + ALIGN(sizeof(struct gaih_addrtuple)) * 2;
if (buflen < size) {
*errnop = ENOMEM;
*h_errnop = NO_RECOVERY;
return NSS_STATUS_TRYAGAIN;
}
/* hostname */
hostname = buffer;
memcpy(hostname, name, n);
offset = ALIGN(n);
/* AF_INET6 */
tuple = (struct gaih_addrtuple*) (buffer + offset);
tuple->next = prev;
tuple->name = hostname;
tuple->family = AF_INET6;
memcpy(tuple->addr, LOCALADDRESS_IPV6, PROTO_ADDRESS_SIZE(AF_INET6));
tuple->scopeid = (uint32_t) index;
offset += ALIGN(sizeof(struct gaih_addrtuple));
prev = tuple;
/* AF_INET */
tuple = (struct gaih_addrtuple*) (buffer + offset);
tuple->next = prev;
tuple->name = hostname;
tuple->family = AF_INET;
*(uint32_t*) tuple->addr = LOCALADDRESS_IPV4;
tuple->scopeid = (uint32_t) index;
offset += ALIGN(sizeof(struct gaih_addrtuple));
prev = tuple;
assert(offset == size);
*pat = prev;
if (ttlp)
*ttlp = 0;
return NSS_STATUS_SUCCESS;
}
static enum nss_status
fill_in_hostent (const char *name, int af, struct hostent *result, char *buffer, size_t buflen, int *errnop, int *h_errnop, int32_t *ttlp, char **canonp)
{
size_t n, offset, size;
char *addr, *hostname, *aliases, *addr_list;
size_t alen;
DBG_TRACE;
alen = PROTO_ADDRESS_SIZE(af);
n = strlen(name) + 1;
size = ALIGN(n) + sizeof(char*) + ALIGN(alen) + sizeof(char*) * 2;
if (buflen < size) {
*errnop = ENOMEM;
*h_errnop = NO_RECOVERY;
return NSS_STATUS_TRYAGAIN;
}
/* hostname */
hostname = buffer;
memcpy(hostname, name, n);
offset = ALIGN(n);
/* aliases (empty) */
aliases = buffer + offset;
*(char**) aliases = NULL;
offset += sizeof(char*);
/* address */
addr = buffer + offset;
if (af == AF_INET)
*(uint32_t*) addr = LOCALADDRESS_IPV4;
else
memcpy(addr, LOCALADDRESS_IPV6, alen);
offset += ALIGN(alen);
/* address list */
addr_list = buffer + offset;
((char**) addr_list)[0] = addr;
((char**) addr_list)[1] = NULL;
offset += sizeof(char*) * 2;
assert(offset == size);
result->h_name = hostname;
result->h_aliases = (char**) aliases;
result->h_addrtype = af;
result->h_length = alen;
result->h_addr_list = (char**) addr_list;
if (ttlp)
*ttlp = 0;
if (canonp)
*canonp = hostname;
return NSS_STATUS_SUCCESS;
}
enum nss_status
_nss_dummy_gethostbyname3_r (const char *name, int af, struct hostent *result, char *buffer, size_t buflen, int *errnop, int *h_errnop, int32_t *ttlp, char **canonp)
{
DBG_TRACE;
if (af == AF_UNSPEC)
af = AF_INET;
if (af != AF_INET && af != AF_INET6) {
*errnop = EINVAL;
*h_errnop = NO_RECOVERY;
return NSS_STATUS_UNAVAIL;
}
return fill_in_hostent(name, af, result, buffer, buflen, errnop, h_errnop, ttlp, canonp);
}
enum nss_status
_nss_dummy_gethostbyname2_r (const char *name, int af, struct hostent *result, char *buffer, size_t buflen, int *errnop, int *h_errnop)
{
DBG_TRACE;
return _nss_dummy_gethostbyname3_r(name, af, result, buffer, buflen, errnop, h_errnop, NULL, NULL);
}
enum nss_status
_nss_dummy_gethostbyname_r (const char *name, struct hostent *result, char *buffer, size_t buflen, int *errnop, int *h_errnop)
{
DBG_TRACE;
return _nss_dummy_gethostbyname2_r(name, AF_UNSPEC, result, buffer, buflen, errnop, h_errnop);
}
enum nss_status
_nss_dummy_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)
{
char name[HOST_NAME_MAX+1];
DBG_TRACE;
if (len != PROTO_ADDRESS_SIZE(af)) {
*errnop = EINVAL;
*h_errnop = NO_RECOVERY;
return NSS_STATUS_UNAVAIL;
}
if (af != AF_INET && af != AF_INET6) {
*errnop = EAFNOSUPPORT;
*h_errnop = NO_DATA;
return NSS_STATUS_UNAVAIL;
}
memset(name, 0, sizeof(name));
if (gethostname(name, sizeof(name) - 1) == -1) {
*errnop = errno;
*h_errnop = NO_RECOVERY;
return NSS_STATUS_UNAVAIL;
}
return fill_in_hostent(name, af, host, buffer, buflen, errnop, h_errnop, ttlp, NULL);
}
enum nss_status
_nss_dummy_gethostbyaddr_r (const void* addr, socklen_t len, int af, struct hostent *result, char *buffer, size_t buflen, int *errnop, int *h_errnop)
{
DBG_TRACE;
return _nss_dummy_gethostbyaddr2_r(addr, len, af, result, buffer, buflen, errnop, h_errnop, NULL);
}
@pandax381
Copy link
Author

pandax381 commented Oct 27, 2016

Build & Install

$ gcc -shared -fPIC -DPIC -Wl,-soname -Wl,libnss_dummy.so.2 -o libnss_dummy.so.2 nss-dummy.c
$ sudo cp libnss_dummy.so.2 /lib/x86_64-linux-gnu/
$ sudo ldconfig

Configuration

$ diff -u /etc/nsswitch.conf.bak /etc/nsswitch.conf
--- /etc/nsswitch.conf.bak  2016-10-26 08:39:28.464291863 +0900
+++ /etc/nsswitch.conf  2016-10-27 18:55:21.363833754 +0900
@@ -8,7 +8,7 @@
 group:          compat
 shadow:         compat

-hosts:          files dns
+hosts:          files dummy dns
 networks:       files

 protocols:      db files

Test

$ ping -n -c 1 www.google.com
PING www.google.com (127.0.0.2) 56(84) bytes of data.
64 bytes from 127.0.0.2: icmp_req=1 ttl=64 time=0.018 ms

--- www.google.com ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.018/0.018/0.018/0.000 ms
$ ping6 -n -c 1 www.google.com
PING www.google.com(::1) 56 data bytes
64 bytes from ::1: icmp_seq=1 ttl=64 time=0.023 ms

--- www.google.com ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.023/0.023/0.023/0.000 ms

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment