... pour compenser les serveurs DNS cassés qui sont hors de notre contrôle.
Notre problème: nous déployons des appareils intégrés qui collectent les données des capteurs sur divers sites, principalement IPv4 uniquement. Certains sites ont des réseaux mal entretenus, par exemple caches DNS et/ou pare-feu mal configurés ou autrement cassés qui ignorent complètement les requêtes AAAA ou y répondent avec des réponses cassées (par exemple, mauvaise adresse IP source!). En tant que fournisseur externe du service des installations, nous n'avons pratiquement aucune influence sur les services informatiques (parfois réticents). Les chances pour eux de réparer leurs serveurs DNS/pare-feu à tout moment sont minuscules.
L'effet sur notre appareil est qu'avec chaque gethostbyname (), les processus doivent attendre que les requêtes AAAA expirent, auquel cas certains processus ont déjà complètement expiré leurs tentatives de connexion.
Je recherche des solutions qui sont ...
La solution la plus évidente serait de configurer la bibliothèque de résolveurs, par ex. via /etc/{ resolv , nsswitch , gai }.conf pour ne pas interroger les enregistrements AAAA. Une option resolv.conf no-inet6
comme suggéré ici serait exactement ce que je recherche. Malheureusement, il n'est pas implémenté, du moins pas sur nos systèmes (libc6-2.13-38 + deb7u4 sur Debian 7; libc6-2.19-0ubuntu6.3 sur Ubuntu 14.04)
Alors comment? On trouve les méthodes suivantes suggérées sur SF et ailleurs, mais aucune ne fonctionne:
sysctl -w net.ipv6.conf.all.disable_ipv6=1
. ( Par curiosité: pourquoi le résolveur demande-t-il AAAA lorsque IPv6 est désactivé? )options inet6
depuis /etc/resolv.conf. Ce n'était pas là en premier lieu, inet6
est simplement activé par défaut de nos jours.options single-request
dans /etc/resolv.conf. Cela garantit uniquement que les requêtes A et AAAA sont effectuées séquentiellement plutôt qu'en parallèleprecedence
dans /etc/gai.conf. Cela n'affecte pas les requêtes DNS, mais uniquement la façon dont plusieurs réponses sont traitées.Idées laides alternatives:
Notez qu'il existe des questions similaires sur SE. Ma question diffère dans la mesure où elle élabore le problème réel que j'essaie de résoudre, car elle énumère des exigences explicites, car elle met sur liste noire des solutions non fonctionnelles souvent suggérées et comme elle n'est pas spécifique à une seule application. Après cette discussion , j'ai posté ma question.
Arrêtez d'utiliser gethostbyname()
. Vous devriez plutôt utiliser getaddrinfo()
, et cela devrait être le cas depuis des années maintenant. La page de manuel vous en avertit même.
Les fonctions gethostbyname * (), gethostbyaddr * (), herror () et hstrerror () sont obsolètes. Les applications doivent utiliser getaddrinfo (3), getnameinfo (3) et gai_strerror (3) à la place.
Voici un exemple de programme rapide en C qui montre la recherche uniquement Un enregistrement pour un nom et une capture Wireshark montrant que uniquement Une recherche d'enregistrements a été effectuée sur le réseau.
En particulier, vous devez définir ai_family
Sur AF_INET
Si vous souhaitez uniquement effectuer des recherches d'enregistrement A. Cet exemple de programme imprime uniquement les adresses IP renvoyées. Voir la page de manuel getaddrinfo()
pour un exemple plus complet de la façon d'établir des connexions sortantes.
Dans le capture Wireshark , 172.25.50.3 est le résolveur DNS local; la capture a été effectuée là-bas, vous voyez donc également ses requêtes et réponses sortantes. Notez que seulement un enregistrement A a été demandé. Aucune recherche AAAA n'a jamais été effectuée.
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <stdlib.h>
#include <netdb.h>
#include <stdio.h>
int main(void) {
struct addrinfo hints;
struct addrinfo *result, *rp;
int s;
char Host[256];
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = 0;
s = getaddrinfo("www.facebook.com", NULL, &hints, &result);
if (s != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
exit(EXIT_FAILURE);
}
for (rp = result; rp != NULL; rp = rp->ai_next) {
getnameinfo(rp->ai_addr, rp->ai_addrlen, Host, sizeof(Host), NULL, 0, NI_NUMERICHOST);
printf("%s\n", Host);
}
freeaddrinfo(result);
}
En cas de doute, rendez-vous sur le code source! Voyons donc ... gethostbyname () semble intéressant; qui décrit exactement ce que nous voyons: essayez d'abord IPv6, puis revenez à IPv4 si vous n'obtenez pas la réponse que vous aimez. Qu'est-ce que c'est ça RES_USE_INET6
drapeau? En remontant, cela vient de res_setoptions () . C'est ici que resolv.conf
est lu.
Et ... c'est moi à court d'idées. Je ne sais vraiment pas comment c'est que RES_USE_INET6
est défini s'il n'est pas dans resolv.conf
.
Vous pouvez utiliser BIND comme résolveur local, il a une option pour filtrer AAAA:
https://kb.isc.org/article/AA-00576/0/Filter-AAAA-option-in-BIND-9-.html
Avez-vous essayé de configurer le récurseur PDNS, de le définir dans votre /etc/resolv.conf et de lui refuser les recherches "AAAA"? Utiliser quelque chose comme query-local-address6=