web-dev-qa-db-fra.com

Comment désactiver les recherches AAAA?

... 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 ...

  • à 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 de base comme glibc, le package de bibliothèque de remplacement doit être disponible à partir d'un référentiel connu pour être bien entretenu (par exemple, Debian Testing, Ubuntu univers, EPEL). L'auto-construction n'est pas une option pour tant de raisons que je ne sais même pas par où commencer, donc je ne les énumère pas du tout ...

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:

  • Désactiver complètement IPv6, par exemple en mettant sur liste noire l'ipv6 LKM dans /etc/modprobe.d/, ou sysctl -w net.ipv6.conf.all.disable_ipv6=1. ( Par curiosité: pourquoi le résolveur demande-t-il AAAA lorsque IPv6 est désactivé? )
  • Suppression de options inet6 depuis /etc/resolv.conf. Ce n'était pas là en premier lieu, inet6 est simplement activé par défaut de nos jours.
  • Réglage 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èle
  • Modification de precedence dans /etc/gai.conf. Cela n'affecte pas les requêtes DNS, mais uniquement la façon dont plusieurs réponses sont traitées.
  • L'utilisation de résolveurs externes (ou l'exécution d'un démon de résolveur local qui contourne les serveurs DNS endommagés) serait utile, mais est généralement interdite par les politiques de pare-feu de l'entreprise. Et cela peut rendre les ressources internes inaccessibles.

Idées laides alternatives:

  • Exécutez 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 connais pas de cache DNS capable de faire cela cependant.
  • Utilisez une correspondance intelligente iptables u32, ou Ondrej Caletka module DNS iptables pour faire correspondre les requêtes AAAA, afin de les rejeter par icmp (comment le libérateur de résolution réagirait-il à cela?), Ou de les rediriger vers un serveur DNS local qui répond à tout avec une NOERROR vide.

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.

36
Nils Toedtmann

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);
}
9
Michael Hampton

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.

4
BMDan

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

3
Robert Kerr

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=

0
Glueon