[LINUX] Erstellen Sie Ihren eigenen Namensauflösungsdienst

Einführung

Was ist ein Namensauflösungsdienst?

Ist ein PC mit dem Namen "Beispiel" mit dem Netzwerk (LAN) verbunden, das Sie gerade verwenden? Wenn Sie eine temporäre virtuelle Maschine erstellen, können Sie eine Maschine mit einem Namen wie foo oder hoge erstellen, aber ich glaube nicht, dass Sie normalerweise diesen Computernamen verwenden. Gibt es auch eine Definition für den Namen "Beispiel" in "/ etc / hosts"? Wenn beispielsweise "127.0.0.1 Beispiel" angezeigt wird, sollte das Ausführen von "Ping-Beispiel" das Ping-Ergebnis von Ihrem Computer zurückgeben.

Von nun an gibt es keinen Host mit dem Namen "example", es gibt keine solche Definition in "/ etc / hosts", und das Ausführen von "ping example" führt zu "ping: unknown host example". Wir gehen davon aus, dass es angezeigt wird.

Die Suche nach einer IP-Adresse aus einem Hostnamen wird als Namensauflösung bezeichnet. Typische Beispiele sind "Hosts-Datei" und "DNS-Resolver". Was zu kontaktieren ist, wird automatisch bestimmt. Es wird von einer Funktion namens nsswitch (Name Service Switch) bereitgestellt. Schauen wir uns zunächst diese Konfigurationsdatei an. Versuchen Sie, / etc / nsswitch.conf anzuzeigen.

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 der Mitte gibt es eine Definition von "Hosts:", die mit "Dateien" beginnt. Es folgen "mdns4" oder "mdns4_minimal" und dann "dns". Wenn Sie Samba installiert haben, können Sie auch "Gewinne" haben.

Die führenden "Dateien" geben an, dass zuerst nach der Definition "/ etc / hosts" gesucht werden soll. Das "mdns" -System ist je nach Betriebssystemkonfiguration möglicherweise nicht verfügbar, aber es scheint, dass es viele Fälle gibt, in denen es in neueren Betriebssystemen als Standard verwendet werden kann. Dies wird als mDNS (Multicast DNS) bezeichnet, eine Standardfunktion zur Namensauflösung in macOS. Selbst unter Windows können Sie es verwenden, indem Sie "Bonjour for Windows" von Apple installieren. Es scheint, dass Windows 10 mDNS standardmäßig unterstützt. Wenn es also richtig eingestellt ist, ping [Hostname] Wenn Sie es wie .local ausführen, ist die Namensauflösung erfolgreich und Sie sehen das Ergebnis des Pings. Das endgültige dns ist eine Spezifikation, die den DNS-Server nach der Auflösung von Internetnamen abfragt.

Wenn der Hostname und die IP-Adresse vorbestimmt sind, ist es am einfachsten und gebräuchlichsten, sie in "/ etc / hosts" zu definieren. Wenn Sie die Namensauflösung dynamisch von einem Programm in einem anderen Dateiformat als Hosts oder einer Datenbank durchführen möchten, können Sie eine eigene Namensauflösungsbibliothek erstellen und diese nach Belieben in nsswitch.conf registrieren.

machen

In diesem Artikel entwickeln wir eine Namensauflösungsbibliothek in C-Sprache. Die Entität ist ein gemeinsam genutztes Objekt.

Es ist keine Übertreibung zu sagen, dass die Namensauflösungsfunktion die Grundlage für den Betriebssystembetrieb ist. Daher sind Root-Rechte erforderlich, um sie in das Betriebssystem zu integrieren. Wenn das Programm fehlerhaft ist, kann dies in einigen Fällen eine schwerwiegende Sicherheitslücke darstellen. Bitte seien Sie dort vorsichtig.

Quellcode

Das gesamte Programm einschließlich Makefile wird im folgenden Repository abgelegt.

https://github.com/soramimi/libnss-example

Es gibt nur zwei Funktionen in einer Quelldatei in C-Sprache. Die zweite Funktion ruft nur die erste Funktion auf, sodass es effektiv nur eine Funktion gibt.

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);
	}
}

Wie es funktioniert

Alles, was es tut, ist "127.0.0.1" als Ergebnis zurückzugeben, wenn der Abfragename "Beispiel" ist, das war's. Auf den ersten Blick scheint der Prozess des Speicherns der Ergebnisse in einer Struktur, die nsswitch eigen ist, mühsam zu sein, aber dieser Teil ist nur ein vollständiger Streich der Leistungen unserer Vorgänger. Das ursprüngliche Programm, auf das ich mich bezog, ist this.

kompilieren

Kompilieren.

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  

Ich kompiliere main.c, um libnss_example.so.2 zu erstellen. Da es sich um ein gemeinsam genutztes Objekt handelt, hat es die Erweiterung ".so". Stellen Sie sich die letzte ".2" als eine Art API-Version vor. Andernfalls funktioniert es nicht. Fügen Sie daher am Ende ".2" hinzu.

Installation

Dann installieren Sie es.

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

Ich kopiere es einfach in / usr / lib /.

Ändern Sie die Einstellungsdatei

Bearbeiten Sie / etc / nsswitch.conf. Fügen Sie am Ende der Definition von "Hosts" "Beispiel" hinzu: "und fertig.

...
hosts:          files mdns4_minimal [NOTFOUND=return] dns example
...

Ich werde das machen

Führen Sie einen Ping durch und überprüfen Sie, ob das Ergebnis zurückgegeben wird.

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

Wenn Sie es selbst ändern

Wenn Sie eine eigene Namensauflösungsbibliothek erstellen möchten, z. B. "libnss_hogehoge.so.2" anstelle von "libnss_example.so.2", dann sind alle "Beispiele" in "main.c" und "Makefile" enthalten Ersetzen Sie durch "hogehoge". Die beiden Funktionsnamen sind auch "_nss_hogehoge_gethostbyname_r" bzw. "_nss_hogehoge_gethostbyname2_r". Wenn dann eine IP-Adresse vorhanden ist, um auf den von der Funktion empfangenen Namen zu antworten, setzen Sie die Adresse in struct in_addr addr, schreiben Sie sie in die Struktur und geben Sie NSS_STATUS_SUCCESS zurück.

Fügen Sie nach dem Kompilieren und Installieren den Namen der neu erstellten Bibliothek zur Definition von "hosts:" in "/ etc / nsswitch.conf" hinzu.

Recommended Posts

Erstellen Sie Ihren eigenen Namensauflösungsdienst
Erstellen Sie Ihre eigene Ausnahme
Erstellen Sie Ihre eigene Django-Middleware
[Django] Erstellen Sie Ihre eigene 403, 404, 500-Fehlerseite
Erstellen Sie Ihre eigenen Linux-Befehle in Python
[LLDB] Erstellen Sie Ihren eigenen Befehl mit Python
Erstellen Sie mit Twisted Ihren eigenen DNS-Server
Erstellen Sie mit SQLAlchemy Ihren eigenen zusammengesetzten Wert
Erstellen Sie ein Rad Ihres eigenen OpenCV-Moduls
Memo zum Erstellen einer eigenen Box mit Peppers Python
Erstellen Sie Ihre eigenen Big Data in Python zur Validierung
Erstellen Sie Ihr eigenes Random Dot Stereogram (RDS) in Python.
[Blender x Python] Erstellen Sie Ihre eigene Funktion und Zusammenfassung
Reinforcement Learning 23 Erstellen und verwenden Sie Ihr eigenes Modul mit Colaboratory
Erstellen Sie Ihre eigene Diagrammstrukturklasse und deren Zeichnung mit Python
Docker ausprobieren: Erstellen Sie Ihr eigenes Container-Image für eine Python-Web-App
Erstellen Sie Ihre eigene IoT-Plattform mit Himbeerpi und ESP32 (Teil 1)