Comment désactiver les recherches AAAA?

35

... pour compenser les serveurs DNS cassés qui sont hors de notre contrôle.

Notre problème: nous déployons des périphériques intégrés qui collectent les données de capteurs sur divers sites, principalement IPv4. Certains sites ont des réseaux mal entretenus, par exemple des caches DNS et / ou des pare-feu mal configurés ou autrement cassés qui ignorent complètement les requêtes AAAA ou leur répondent avec des réponses cassées (par exemple, une adresse IP source incorrecte!). En tant que fournisseur externe du département des installations, nous n’avons pratiquement aucune influence sur les départements informatiques (parfois réticents). Les chances qu’ils réparent leurs serveurs / pare-feu DNS dans un proche avenir sont infimes.

L'effet sur notre périphérique est que, avec chaque gethostbyname (), les processus doivent attendre que les requêtes AAAA expirent, moment auquel certains processus ont déjà dépassé leur délai de tentative de connexion.

Je cherche des solutions qui sont ...

  • à l'échelle du système. Je ne peux pas reconfigurer des dizaines d'applications individuellement
  • non permanent et configurable. Nous devons (réactiver) IPv6 où / quand il est corrigé / déployé. Le redémarrage est OK.
  • Si une solution nécessite le remplacement d’une bibliothèque principale telle que glibc, le package de bibliothèque de remplacement doit être disponible à partir d’un référentiel dont la maintenance est assurée (par exemple, Debian Testing, univers Ubuntu, EPEL). L'auto-construction n'est pas une option pour tant de raisons que je ne sais même pas par où commencer, alors je ne les énumère pas du tout ...

La solution la plus évidente serait de configurer la bibliothèque de résolveur, par exemple via / etc / { resolv , nsswitch , gai } .conf pour ne pas interroger les enregistrements AAAA. Une option de resolv.conf no-inet6telle que suggérée 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 alors? On trouve les méthodes suivantes suggérées sur SF et ailleurs, mais aucune d'entre elles ne fonctionne:

  • Désactiver complètement IPv6, par exemple en mettant en liste noire le LKM ipv6 dans /etc/modprobe.d/, ou sysctl -w net.ipv6.conf.all.disable_ipv6=1. ( Par curiosité: pourquoi le résolveur demande-t-il un AAAA lorsque IPv6 est désactivé? )
  • Suppression options inet6de /etc/resolv.conf. Ce n'était pas là en premier lieu, inet6est simplement activé par défaut ces jours-ci.
  • Configuration options single-requestdans /etc/resolv.conf. Cela garantit uniquement que les requêtes A et AAAA sont effectuées de manière séquentielle plutôt qu'en parallèle
  • Changer precedencedans /etc/gai.conf. Cela n'affecte pas les requêtes DNS, mais seulement le traitement de plusieurs réponses.
  • L'utilisation de résolveurs externes (ou l'exécution d'un démon de résolveur local qui contourne les serveurs DNS cassés) serait utile, mais est généralement interdite par les stratégies de pare-feu de l'entreprise. Et cela peut rendre les ressources internes inaccessibles.

Idées alternatives laides:

  • Exécuter un cache DNS sur localhost. Configurez-le pour transférer toutes les requêtes non-AAAA, mais pour répondre aux requêtes AAAA avec NOERROR ou NXDOMAIN (selon le résultat de la requête A correspondante). Je ne suis pas au courant d'un cache DNS capable de le faire cependant.
  • Utilisez une correspondance intelligente iptables u32 ou le module DNS iptables d’ Ondrej Caletka pour faire correspondre les requêtes AAAA, afin de les rejeter par icmp (comment le résolver lib réagirait-il?) Ou de les rediriger vers un serveur DNS local qui répond tout avec un NOERROR vide.

Notez qu'il existe des questions similaires sur SE. Ma question diffère dans la mesure où elle élabore le problème que je tente de résoudre, car elle énonce des exigences explicites, une liste noire de solutions non fonctionnelles souvent proposées, et comme elle n'est pas spécifique à une seule application. Suite à cette discussion , j'ai posté ma question.

Nils Toedtmann
la source
13
PS: Contrairement à la croyance populaire chez SF, il existe de bonnes raisons de désactiver IPv6 / AAAA sur une machine appartenant à un réseau uniquement IPv4, même lorsque le système DNS fonctionne: réduction de la charge de diffusion; Réduire la charge sur les résolveurs DNS de près de 50%; Réduisez les temps de démarrage des connexions (de manière significative lorsque les caches DNS sont lents); Suivez les meilleures pratiques pour désactiver les fonctionnalités non fonctionnelles afin d'améliorer la sécurité et la stabilité. Certes, si j'oublie de réactiver IPv6 une fois qu'il devient disponible, mon système devient alors un ballast hérité d'IPv4 qui entrave le déploiement d'IPv6. On devrait être autorisé à peser les avantages énumérés contre ce con.
Nils Toedtmann
Une raison pour laquelle vous n'exécutez pas de résolution complète sur localhost? De cette façon, vous éliminez la dépendance vis-à-vis des résolveurs DNS (apparemment) non fiables.
Sander Steffann
Les politiques de pare-feu de la société @SanderSteffann Company l'interdisent généralement. Mais ailleurs, c'est une option. Je vais l'ajouter à ma question plus tard.
Nils Toedtmann
3
@joeqwerty Nous ne faisons aucune hypothèse quant à la prise en charge d'IPv6 sur le site. Nous supposons cependant que les serveurs DNS sont conformes à la norme. En outre, certains services informatiques ne disposent malheureusement pas des compétences nécessaires pour configurer correctement leur infrastructure. Désolé d'être franc à ce sujet.
Nils Toedtmann
4
Je comprends ce que vous dites. Vous devez faire en sorte que votre boîte fonctionne sur son réseau et non l'inverse, et c'est ce que vous demandez ici. Je suis juste un peu vexé quand, dans le domaine informatique, blâmons nos clients et ne les respecte pas. Ils sont notre pain et notre beurre. Pour le meilleur ou pour le pire, nous devons respecter cela et les respecter. Nos clients ne sont pas un obstacle à notre activité, ils sont la raison de notre activité.
joeqwerty

Réponses:

9

Arrêtez d'utiliser gethostbyname(). Vous devriez utiliser à la getaddrinfo()place, et cela depuis des années. La page de manuel vous en avertit même.

Les fonctions gethostbyname * (), gethostbyaddr * (), herror () et hstrerror () sont obsolètes. Les applications doivent plutôt utiliser getaddrinfo (3), getnameinfo (3) et gai_strerror (3).

Voici un exemple de programme rapide en C qui illustre la recherche des noms A uniquement pour un nom et une capture de Wireshark indiquant que seules les recherches A ont été effectuées sur le réseau.

En particulier, vous devez définir ai_familysur AF_INETsi vous souhaitez uniquement effectuer une recherche d'enregistrement. Cet exemple de programme imprime uniquement les adresses IP renvoyées. Voir la getaddrinfo()page de manuel pour un exemple plus complet sur la façon d'établir des connexions sortantes.

Dans la capture Wireshark , 172.25.50.3 est le résolveur DNS local; la capture a été prise là-bas, de sorte que vous voyez également ses requêtes et réponses sortantes. Notez que seul un enregistrement A a été demandé. Aucune recherche AAAA n'a jamais été faite.

#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);
}
Michael Hampton
la source
Intéressant! Je vais rechercher quelles applications déclenchent des requêtes AAAA. Si ce n'est que le nôtre, je transmettrai votre suggestion à nos développeurs. Mais j’ai bien l’impression que beaucoup de logiciels emballés sous Debian / Ubuntu en souffrent, et nous ne les corrigerons pas.
Nils Toedtmann
Votre application est probablement la plus importante. Même si vous ne pouvez pas tout réparer, cela peut améliorer la situation.
Michael Hampton
4

En cas de doute, rendez-vous sur le code source! Voyons donc ... gethostbyname () a l' air intéressant; cela décrit exactement ce que nous voyons: essayez d’abord IPv6, puis utilisez IPv4 si vous n’obtenez pas la réponse qui vous convient. C'est quoi ce RES_USE_INET6drapeau? En le retraçant, cela provient de res_setoptions () . Ceci est où resolv.confest lu dans.

Et .... c'est moi à court d'idées. Je ne sais absolument pas comment cela se RES_USE_INET6passe, sinon dans resolv.conf.

BMDan
la source
RES_USE_INET6 peut être défini via options inet6in resolv.conf. Je suppose que mon problème est qu’il ne peut pas être désactivé une fois qu’il a été défini au moment de la compilation, ce que toutes les principales distributions semblent faire ces jours-ci (correct?). Par conséquent, la demande de fonctionnalité pour options no_inet6celle que j'ai mentionnée ci-dessus.
Nils Toedtmann
1
Malheureusement, comme vous pouvez le constater à partir du code, il ne semble pas y avoir d’ no_inet6option dans res_setoptions(). Cependant, comme vous pouvez le voir sur (non) ip6-dotint, c'est un changement facile à ajouter. Pour tester la théorie selon laquelle il est défini par défaut par votre distribution, saisissez les fichiers source du paquet et le compilez une fois "vierge" (pour confirmer que le paquet reproduit le comportement), puis ajoutez: { STRnLEN ("no-inet6"), 1, ~RES_USE_INET6 },au options[]tableau et voyez si le problème disparaît lorsque vous définissez cette option dans resolv.conf.
BMDan
1
Enfin: pour ce que cela vaut, je résoudrais cela en exécutant un cache DNS sur localhost (comme vous le mentionnez ci-dessus). Ce serait beaucoup plus facile de gérer votre propre proxy / cache DNS piraté que de maintenir une version piratée d'une bibliothèque système principale.
BMDan
3

Vous pouvez utiliser BIND en tant que résolveur local. Il existe une option pour filtrer AAAA:

https://kb.isc.org/article/AA-00576/0/Filter-AAAA-option-in-BIND-9-.html

Robert Kerr
la source
2
C'est assez lourd pour un appareil embarqué.
Michael Hampton
Merci, je ne connaissais pas le filtre AAAA de Bind. Comme Michael le mentionne, ce n'est probablement pas une solution pour nous en raison de la taille de Bind. Mais pour ceux qui souhaitent filtrer les réponses AAAA dans d'autres scénarios, cela pourrait être un moyen viable. Ubuntu construit en fait une liaison avec "--enable-filter-aaaa", au moins le 14.04. Pas sûr de Debian. - Voir aussi ipamworldwide.blogspot.co.uk/2011/09/…
Nils Toedtmann le
1
Je suis sur 14.04 et il ne semble pas que cette option de filtrage soit disponible.
Zitrax
0

Avez-vous essayé de configurer PDNS-recursor, définissez-le dans votre /etc/resolv.conf et refusez les recherches "AAAA"? En utilisant quelque chose commequery-local-address6=

Glueon
la source
1
query-local-address6=fait quelque chose de différent (adresse IPv6 à partir de laquelle envoyer les requêtes - notez que même si IPv6 est désactivé, les demandes AAAA seront toujours résolues via IPv4). De plus, je ne peux identifier aucun autre paramètre filtrant les requêtes AAAA ( doc.powerdns.com/html/built-in-recursor.html ). Sans cette information, votre réponse ne serait pas très utile :(
Nils Toedtmann