Is a PC named "example" connected to the network (LAN) you are using now? When you create a virtual machine for temporary use, you may build a machine with a name like foo or hoge, but I don't think you usually use that computer name. Also, is there a definition for the name "example" in / etc / hosts
? For example, if it says 127.0.0.1 example
, running ping example
should return the ping result from your machine.
From here on, there is no host named "example", there is no such definition in / etc / hosts
, and running ping example
will result in ping: unknown host example
. I will proceed with the assumption that it will be displayed.
Searching for an IP address from a host name is called name resolution. Typical examples are "hosts file" and "dns resolver". What to contact is automatically determined. It is provided by a feature called nsswitch (Name Service Switch). First, let's take a look at this configuration file. Try to display /etc/nsswitch.conf
.
soramimi@alice:~$ cat /etc/nsswitch.conf
# /etc/nsswitch.conf
#
# Example configuration of GNU Name Service Switch functionality.
# If you have the `glibc-doc-reference' and `info' packages installed, try:
# `info libc "Name Service Switch"' for information about this file.
passwd: compat
group: compat
shadow: compat
gshadow: files
hosts: files mdns4_minimal [NOTFOUND=return] dns
networks: files
protocols: db files
services: db files
ethers: db files
rpc: db files
netgroup: nis
In the middle, there is a definition of hosts:
, which starts with files
. It is followed by mdns4
or mdns4_minimal
, and then dns
. If you have Samba installed, you may also have wins
.
The leading files
specifies to search from the / etc / hosts
definition first. The mdns
system may not be available depending on the OS configuration, but it seems that there are many cases where it can be used as standard in recent OS. This is called mDNS (Multicast DNS), which is a standard name resolution function in macOS. Even on Windows, you can use it by installing "Bonjour for Windows" provided by Apple, and it seems that Windows 10 supports mDNS as standard, so if it is set correctly, ping [host name] If you run it like .local
, the name resolution will be successful and you will see the result of the ping. The final dns
is a specification that queries the DNS server for Internet name resolution.
If the host name and IP address are predetermined, it is easiest and most common to define them in / etc / hosts
. If you want to perform name resolution dynamically by a program using a file format other than hosts or a database, you can create your own name resolution library and register it in nsswitch.conf
as you like.
In this article, we will develop a name resolution library using C language. The entity is a shared object.
It is no exaggeration to say that the name resolution function is the basis of OS operation, so root privileges are required to incorporate it into the OS, and if there is a defect in the program, it can be a serious security hole in some cases. Please be careful there.
The entire program including the Makefile is placed in the following repository.
https://github.com/soramimi/libnss-example
There are only two functions in a single C source file. The second function only calls the first function, so there is effectively only one function.
main.c
#include <string.h>
#include <nss.h>
#include <netdb.h>
#include <stdlib.h>
#include <errno.h>
#include <arpa/inet.h>
#define ALIGN(idx) do { \
if (idx % sizeof(void*)) \
idx += (sizeof(void*) - idx % sizeof(void*)); /* Align on 32 bit boundary */ \
} while(0)
enum nss_status _nss_example_gethostbyname_r(const char *name, struct hostent *result, char *buffer, size_t buflen, int *errnop, int *h_errnop)
{
size_t idx, astart;
if (strcmp(name, "example") == 0) {
char const *host = "127.0.0.1";
*(char**)buffer = NULL;
result->h_aliases = (char**) buffer;
idx = sizeof(char*);
strcpy(buffer + idx, name);
result->h_name = buffer + idx;
idx += strlen(name) + 1;
ALIGN(idx);
result->h_addrtype = AF_INET;
result->h_length = sizeof(uint32_t);
struct in_addr addr;
inet_pton(AF_INET, host, &addr);
astart = idx;
memcpy(buffer+astart, &addr.s_addr, sizeof(uint32_t));
idx += sizeof(uint32_t);
result->h_addr_list = (char**)(buffer + idx);
result->h_addr_list[0] = buffer + astart;
result->h_addr_list[1] = NULL;
return NSS_STATUS_SUCCESS;
}
*errnop = EINVAL;
*h_errnop = NO_RECOVERY;
return NSS_STATUS_UNAVAIL;
}
enum nss_status _nss_example_gethostbyname2_r(const char *name, int af, struct hostent *result, char *buffer, size_t buflen, int *errnop, int *h_errnop)
{
if (af != AF_INET) {
*errnop = EAGAIN;
*h_errnop = NO_RECOVERY;
return NSS_STATUS_TRYAGAIN;
} else {
return _nss_example_gethostbyname_r(name, result, buffer, buflen, errnop, h_errnop);
}
}
All I'm doing is that when the name of the query is "example", it returns "127.0.0.1" as a result, that's it. At first glance, the process of storing the results in a structure peculiar to nsswitch seems to be troublesome, but this part is just a plagiarism of the achievements of our predecessors. The original program I referred to is this.
Compile.
soramimi@alice:~/develop/libnss-example$ make
gcc -g -O2 -Wall -Wpointer-arith -fPIC -c -o main.o main.c
gcc -g -O2 -Wall -Wpointer-arith -shared -Wl,-soname,libnss_example.so.2 -Wl,-z,defs -o libnss_example.so.2 main.o
I am compiling main.c
to create libnss_example.so.2
. Since it is a shared object, it has the extension .so
. Think of the last .2
as something like an API version. Other than this, it will not work, so be sure to add .2
at the end.
Then install it.
soramimi@alice:~/develop/libnss-example$ sudo make install
install -m755 -d /usr/lib/
install -m644 libnss_example.so.2 /usr/lib/libnss_example.so.2
I'm just copying it into / usr / lib /
.
Edit /etc/nsswitch.conf
. Add ʻexample to the end of the
hosts: `definition and you're done.
...
hosts: files mdns4_minimal [NOTFOUND=return] dns example
...
Ping and verify that the results are returned.
soramimi@alice:~$ ping example
PING example (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.034 ms
64 bytes from localhost (127.0.0.1): icmp_seq=2 ttl=64 time=0.033 ms
64 bytes from localhost (127.0.0.1): icmp_seq=3 ttl=64 time=0.029 ms
If you want to create your own name resolution library, for example libnss_hogehoge.so.2
instead of libnss_example.so.2
, all ʻexamples contained in
main.cand
MakefileReplace with
hogehoge. The two function names are also
_nss_hogehoge_gethostbyname_r and
_nss_hogehoge_gethostbyname2_r, respectively. Then, if there is an IP address to reply to
name received by the function, set the address in
struct in_addr addr, write it to the structure, and return
NSS_STATUS_SUCCESS`.
After compiling and installing, add the name of the newly created library to the hosts:
definition in /etc/nsswitch.conf
.
Recommended Posts