Jak wyłączyć wyszukiwanie AAAA?

35

... aby zrekompensować uszkodzenie uszkodzonych serwerów DNS, które są poza naszą kontrolą.

Nasz problem: wdrażamy urządzenia osadzone, które zbierają dane z czujników w różnych witrynach, głównie IPv4. Niektóre witryny mają źle utrzymywane sieci, np. Źle skonfigurowane lub w inny sposób uszkodzone pamięci podręczne DNS i / lub zapory ogniowe, które albo całkowicie ignorują zapytania AAAA, albo odpowiadają na nie zepsutymi odpowiedziami (np. Błędne IP źródłowe!). Jako zewnętrzny dostawca działu obiektów nie mamy prawie żadnego wpływu na (czasem niechętne) działy IT. Szanse na naprawienie serwerów DNS / zapór ogniowych w najbliższym czasie są znikome.

Wpływ na nasze urządzenie jest taki, że przy każdym gethostbyname () procesy muszą czekać, aż upłynie limit czasu zapytań AAAA, w którym to momencie niektóre procesy już całkowicie przekroczyły limit czasu prób połączenia.

Szukam rozwiązań, które są ...

  • w całym systemie. Nie mogę indywidualnie konfigurować dziesiątek aplikacji
  • niestałe i konfigurowalne. Musimy (ponownie) włączyć IPv6, gdzie / kiedy zostanie naprawiony / wdrożony. Ponowne uruchomienie jest w porządku.
  • Jeśli rozwiązanie wymaga zastąpienia biblioteki podstawowej, takiej jak glibc, pakiet biblioteki zastępczej powinien być dostępny z dobrze znanego repozytorium (np. Debian Testing, Ubuntu Universe, EPEL). Samodzielne budowanie nie jest opcją z tak wielu powodów, że nawet nie wiem od czego zacząć, więc po prostu ich nie wymieniam ...

Najbardziej oczywistym rozwiązaniem byłoby skonfigurowanie biblioteki resolvera, np. Przez / etc / { resolv , nsswitch , gai } .conf, aby nie wyszukiwała rekordów AAAA. no-inet6Sugerowana tutaj opcja resolv.conf byłaby dokładnie tym , czego szukam. Niestety nie jest zaimplementowany, przynajmniej nie w naszych systemach (libc6-2.13-38 + deb7u4 w Debian 7; libc6-2.19-0ubuntu6.3 w Ubuntu 14.04)

Jak więc? Można znaleźć następujące metody sugerowane na SF i gdzie indziej, ale żadna z nich nie działa:

  • Całkowite wyłączenie IPv6, np. Przez umieszczenie na czarnej liście LKM ipv6 w /etc/modprobe.d/ lub sysctl -w net.ipv6.conf.all.disable_ipv6=1. ( Z ciekawości: Dlaczego resolver prosi o AAAA, gdy IPv6 jest wyłączony? )
  • Usuwanie options inet6z /etc/resolv.conf. Po pierwsze, nie było go, obecnie inet6jest po prostu domyślnie włączone.
  • Ustawienie options single-requestw /etc/resolv.conf. Zapewnia to tylko, że zapytania A i AAAA są wykonywane sekwencyjnie, a nie równolegle
  • Zmiana precedencew /etc/gai.conf. Nie wpływa to na zapytania DNS, a jedynie na sposób przetwarzania wielu odpowiedzi.
  • Korzystanie z zewnętrznych programów tłumaczących (lub uruchamianie lokalnego demona tłumaczącego, który omija uszkodzone serwery DNS) pomógłby, ale zwykle jest to zabronione przez zasady zapory firmy. I może uniemożliwić dostęp do zasobów wewnętrznych.

Alternatywne brzydkie pomysły:

  • Uruchom pamięć podręczną DNS na localhost. Skonfiguruj go, aby przekazywał wszystkie zapytania inne niż AAAA, ale odpowiadał na zapytania AAAA za pomocą NOERROR lub NXDOMAIN (w zależności od wyniku odpowiedniego zapytania A). Nie znam jednak pamięci podręcznej DNS, która mogłaby to zrobić.
  • Użyj sprytnego dopasowania u32 iptables lub modułu DNS iptables Ondreja Caletki, aby dopasować zapytania AAAA, w celu ich odrzucenia przez icmp (jak zareaguje na to biblioteka tłumacząca?) Lub przekierowania ich na lokalny serwer DNS, który odpowiada na wszystko z pustym NOERROR.

Zauważ, że podobne pytania dotyczą SE. Moje pytanie różni się tym, że opisuje rzeczywisty problem, który próbuję rozwiązać, ponieważ zawiera wyraźne wymagania, ponieważ zawiera listę często sugerowanych niedziałających rozwiązań i nie jest specyficzny dla pojedynczej aplikacji. Po tej dyskusji opublikowałem swoje pytanie.

Nils Toedtmann
źródło
13
PS: Wbrew powszechnemu przekonaniu o SF, istnieje kilka dobrych powodów, aby wyłączyć IPv6 / AAAA na maszynie w sieci opartej tylko na IPv4, nawet tam, gdzie działa DNS: Zmniejszyć obciążenie emisji; Zmniejsz obciążenie translatorów DNS o prawie 50%; Skróć czas uruchamiania połączenia (znacznie tam, gdzie pamięci podręczne DNS są opóźnione); Postępuj zgodnie z najlepszymi praktykami, aby wyłączyć niefunkcjonalne funkcje w celu zwiększenia bezpieczeństwa i stabilności. Trzeba przyznać, że jeśli zapomnę ponownie włączyć IPv6, gdy tylko będzie dostępny, to mój system stanie się starszym statecznikiem IPv4, który utrudnia wdrożenie IPv6. Należy pozwolić na porównanie wymienionych profesjonalistów z tym oszustwem.
Nils Toedtmann
Jest jakiś powód, dla którego nie uruchamiasz pełnego resolvera na localhost? W ten sposób eliminujesz zależność od (pozornie) niewiarygodnych programów rozpoznawania nazw DNS innych osób.
Sander Steffann
@SanderSteffann Firma zapory ogniowej zwykle tego nie zezwala. Ale gdzie indziej jest to opcja. Dodam to do mojego pytania później.
Nils Toedtmann
3
@joeqwerty Nie przyjmujemy żadnych założeń dotyczących tego, czy protokół IPv6 jest obsługiwany w witrynie. Zakładamy jednak, że serwery DNS są zgodne ze standardami. Niektóre działy IT niestety nie mają umiejętności prawidłowego konfigurowania infrastruktury. Przepraszam, że jestem tępy.
Nils Toedtmann
4
Rozumiem co mówisz. Musisz sprawić, by Twoje urządzenie działało w ich sieci, a nie na odwrót, i o to tutaj pytasz. Trochę się denerwuję, kiedy w branży IT obwiniamy naszych klientów i ich nie szanujemy. Są naszym chlebem i masłem. Na dobre i na złe musimy to szanować i szanować. Nasi klienci nie są przeszkodą dla naszej działalności, są przyczyną naszej działalności.
joeqwerty

Odpowiedzi:

9

Przestań używać gethostbyname(). Powinieneś używać getaddrinfo()zamiast tego i powinieneś być od lat. Strona podręcznika ostrzega cię nawet przed tym.

Funkcje gethostbyname * (), gethostbyaddr * (), herror () i hstrerror () są przestarzałe. Aplikacje powinny zamiast tego używać getaddrinfo (3), getnameinfo (3) i gai_strerror (3).

Oto szybki przykładowy program w C, który pokazuje wyszukiwanie tylko rekordów A dla nazwy, i przechwycenie Wireshark pokazujące, że tylko wyszukiwania rekordów A przebiegały przez sieć.

W szczególności trzeba ustawić ai_family, aby AF_INETjeśli tylko chcą wyszukiwań protokołem sporządzonym. Ten przykładowy program drukuje tylko zwrócone adresy IP. Zobacz getaddrinfo()stronę podręcznika, aby uzyskać pełniejszy przykład wykonywania połączeń wychodzących.

W przechwytywaniu Wireshark 172.25.50.3 to lokalny program rozpoznawania nazw DNS; przechwytywanie zostało tam zrobione, więc można zobaczyć także wychodzące zapytania i odpowiedzi. Zauważ, że zażądano tylko rekordu A. Nigdy nie przeprowadzono wyszukiwania AAAA.

#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
źródło
Ciekawy! Zbadam, które aplikacje wyzwalają żądania AAAA. Jeśli to tylko nasza, przekażę twoją sugestię naszym twórcom. Ale mam przeczucie, że wiele programów w pakiecie Debian / Ubuntu cierpi z tego powodu i nie zamierzamy ich łatać.
Nils Toedtmann
Twoja aplikacja jest prawdopodobnie najważniejsza. Nawet jeśli nie możesz naprawić wszystkiego innego, może to poprawić sytuację.
Michael Hampton
4

W razie wątpliwości przejdź do kodu źródłowego! Zobaczmy więc ... gethostbyname () wygląda interesująco; to dokładnie opisuje to, co widzimy: najpierw wypróbuj IPv6, a następnie wróć do IPv4, jeśli nie otrzymasz odpowiedzi, którą lubisz. Co to za RES_USE_INET6flaga? Śledząc to, pochodzi z res_setoptions () . To jest gdzie resolv.confjest czytane.

I .... to ja z pomysłów. Nie jestem całkowicie pewien, jak to RES_USE_INET6się dzieje, jeśli nie jest resolv.conf.

BMDan
źródło
RES_USE_INET6 można ustawić za pomocą options inet6w resolv.conf. Wydaje mi się, że moim problemem jest to, że nie można go rozbroić po ustawieniu go w czasie kompilacji, co wydaje się obecnie robić wszystkie główne dystrybucje (prawda?). Dlatego prośba o funkcję, o options no_inet6której wspomniałem powyżej.
Nils Toedtmann
1
Niestety, jak widać z kodu, wydaje się, że nie ma no_inet6opcji w res_setoptions(). Jednak, jak widać z (nie-) ip6-dotint, jest to łatwa zmiana do dodania. Aby przetestować teorię, że jest domyślnie ustawiana przez twoją dystrybucję, złapałbym pliki źródłowe pakietu i skompilowałem je raz „dziewicą” (aby potwierdzić, że pakiet replikuje zachowanie), a następnie dodałem: { STRnLEN ("no-inet6"), 1, ~RES_USE_INET6 },do options[]tablicy i sprawdziłem, czy problem zniknie po ustawieniu tej opcji w resolv.conf.
BMDan
1
Na koniec: o ile warto, rozwiązałbym to, uruchamiając pamięć podręczną DNS na localhost (jak już wspomniałeś powyżej). Byłoby o wiele łatwiej utrzymać własną, zhakowaną serwer proxy / pamięć podręczną DNS, niż byłoby w przypadku zhakowanej wersji podstawowej biblioteki systemowej.
BMDan
3

Możesz użyć BIND jako lokalnego resolvera, ma opcję filtrowania AAAA:

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

Robert Kerr
źródło
2
To dość ciężki jak na urządzenie osadzone.
Michael Hampton
Dziękuję, nie wiedziałem o filtrze AAAA Binda. Jak wspomina Michael, prawdopodobnie nie jest to dla nas rozwiązanie ze względu na duży ślad Binda. Ale dla tych, którzy chcą odfiltrować odpowiedzi AAAA w innych scenariuszach, może to być realny sposób. Ubuntu faktycznie buduje bind z „--enable-filter-aaaa”, przynajmniej 14.04. Nie jestem pewien co do Debiana. - Zobacz także ipamworldwide.blogspot.co.uk/2011/09/…
Nils Toedtmann
1
Mam 14.04 i nie wydaje się, aby ta opcja filtrowania była dostępna.
Zitrax 06.04.17
0

Czy próbowałeś skonfigurować rekursor PDNS, ustawić go w pliku /etc/resolv.conf i odmówić wyszukiwania w nim „AAAA”? Używanie czegoś podobnegoquery-local-address6=

Glueon
źródło
1
query-local-address6=robi coś innego (z którego adresu IPv6 wysyłane są zapytania - zauważ, że nawet przy wyłączonym IPv6 żądania AAAA będą nadal rozpatrywane przez IPv4). Nie mogę też zidentyfikować żadnego innego ustawienia, które odfiltrowałoby zapytania AAAA ( doc.powerdns.com/html/built-in-recursor.html ). Bez tych informacji twoja odpowiedź nie jest zbyt pomocna :(
Nils Toedtmann