Un ordinateur nommé «exemple» est-il connecté au réseau (LAN) que vous utilisez actuellement? Lors de la création d'une machine virtuelle temporaire, vous pouvez créer une machine avec un nom comme foo ou hoge, mais je ne pense pas que vous utilisez généralement ce nom d'ordinateur. De plus, y a-t-il une définition pour le nom "exemple" dans / etc / hosts
? Par exemple, si elle indique «127.0.0.1 exemple», l'exécution de «exemple de ping» devrait renvoyer le résultat du ping de votre machine.
À partir de ce moment, il n'y a pas d'hôte nommé "exemple", il n'y a pas de définition de ce type dans / etc / hosts
, et l'exécution de ping example
aboutit à ping: unknown host example
. Je continuerai en supposant qu'il sera affiché.
La recherche d'une adresse IP à partir d'un nom d'hôte s'appelle la résolution de noms. Des exemples typiques sont "fichier hosts" et "résolveur dns". Ce qu'il faut contacter est automatiquement déterminé. Il est fourni par une fonctionnalité appelée nsswitch (Name Service Switch). Jetons d'abord un œil à ce fichier de configuration. Essayez d'afficher / 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
Au milieu, il y a une définition de hosts:
, qui commence par files
. Il est suivi de «mdns4» ou «mdns4_minimal», puis de «dns». Si vous avez installé Samba, vous pouvez également avoir wins
.
Le premier files
spécifie de rechercher d'abord à partir de la définition / etc / hosts
. Le système mdns
peut ne pas être disponible selon la configuration du système d'exploitation, mais il semble qu'il existe de nombreux cas où il peut être utilisé en standard dans un système d'exploitation récent. Cela s'appelle mDNS (Multicast DNS), qui est une fonction de résolution de nom standard dans macOS. Vous pouvez l'utiliser sur Windows en installant "Bonjour pour Windows" fourni par Apple, et il semble que Windows 10 prend en charge mDNS en standard, donc s'il est défini correctement, ping [nom d'hôte] Si vous l'exécutez comme .local
, la résolution du nom réussira et vous verrez le résultat du ping. Le «dns» final est une spécification qui interroge le serveur DNS pour la résolution de noms Internet.
Si le nom d'hôte et l'adresse IP sont prédéterminés, il est plus simple et plus courant de les définir dans / etc / hosts
. Si vous voulez effectuer une résolution de nom dynamiquement par un programme utilisant un format de fichier autre que les hôtes ou une base de données, vous pouvez créer votre propre bibliothèque de résolution de nom et l'enregistrer dans nsswitch.conf
comme vous le souhaitez.
Dans cet article, nous développerons une bibliothèque de résolution de noms utilisant le langage C. L'entité est un objet partagé.
Il n'est pas exagéré de dire que la fonction de résolution de noms est la base du fonctionnement du système d'exploitation, de sorte que les privilèges root sont nécessaires pour l'intégrer dans le système d'exploitation, et s'il y a un défaut dans le programme, cela peut être une faille de sécurité sérieuse dans certains cas. Soyez prudent là-bas.
L'ensemble du programme, y compris Makefile, est placé dans le référentiel suivant.
https://github.com/soramimi/libnss-example
Il n'y a que deux fonctions dans un fichier source en langage C. La deuxième fonction appelle uniquement la première fonction, il n'y a donc en fait qu'une seule fonction.
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);
}
}
Tout ce que nous faisons, c'est que lorsque le nom de la requête est "exemple", il renvoie "127.0.0.1" comme résultat, c'est tout. À première vue, le processus de stockage des résultats dans une structure propre à nsswitch semble gênant, mais cette partie n'est qu'une farce complète des réalisations de nos prédécesseurs. Le programme original auquel j'ai fait référence est this.
Compiler.
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
Je compile main.c
pour créer libnss_example.so.2
. Puisqu'il s'agit d'un objet partagé, il a l'extension «.so». Considérez le dernier «.2» comme quelque chose comme une version d'API. À part cela, cela ne fonctionnera pas, alors assurez-vous d'ajouter ".2" à la fin.
Puis installez-le.
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
Je le copie simplement dans / usr / lib /
.
Modifiez / etc / nsswitch.conf
. Ajoutez ʻexample à la fin de la définition de
hosts: ʻet vous avez terminé.
...
hosts: files mdns4_minimal [NOTFOUND=return] dns example
...
Exécutez un ping et vérifiez que le résultat est renvoyé.
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
Si vous voulez créer votre propre bibliothèque de résolution de noms, par exemple libnss_hogehoge.so.2
au lieu de libnss_example.so.2
, tous les exemples
sont contenus dans main.c
et Makefile
Remplacez par hogehoge
. Les deux noms de fonction sont également _nss_hogehoge_gethostbyname_r
et _nss_hogehoge_gethostbyname2_r
, respectivement. Ensuite, s'il y a une adresse IP pour répondre au nom
reçu par la fonction, définissez l'adresse sur struct in_addr addr
, écrivez-la dans la structure et renvoyez NSS_STATUS_SUCCESS
.
Après la compilation et l'installation, ajoutez le nom de la bibliothèque nouvellement créée à la définition hosts:
dans / etc / nsswitch.conf
.
Recommended Posts