web-dev-qa-db-ja.com

AAAAルックアップを無効にする方法は?

...私たちの管理外にある壊れたDNSサーバーを補うため。

私たちの問題:さまざまな、主にIPv4のみのサイトでセンサーデータを収集する組み込みデバイスを展開しています。一部のサイトでは、ネットワークのメンテナンスが不十分です。 AAAAクエリを完全に無視するか、壊れた応答(たとえば、間違ったソースIP!)で応答する、誤って構成された、または壊れたDNSキャッシュやファイアウォール。施設部門への外部サプライヤーとして、私たちは(時には消極的な)IT部門にほとんど影響を与えません。彼らがDNSサーバー/ファイアウォールをいつでも修正する可能性は非常に小さいです。

デバイスへの影響は、各gethostbyname()で、プロセスはAAAAクエリがタイムアウトするまで待機する必要があることです。この時点で、一部のプロセスはすでに接続試行を完全にタイムアウトしています。

私はある解決策を探しています...

  • システム全体。数十のアプリケーションを個別に再構成できない
  • 非永続的で構成可能です。修正/ロールアウトされる場所/時期にIPv6を(再)有効にする必要があります。再起動はOKです。
  • ソリューションでglibcなどのコアライブラリの交換が必要な場合は、よく保守されることがわかっているリポジトリ(Debian Testing、Ubuntuユニバース、EPELなど)から代替ライブラリパッケージを入手できる必要があります。自己構築は多くの理由でオプションではないので、どこから始めればよいのかさえわからないので、それらをまったくリストしません...

最も明白な解決策は、リゾルバライブラリを構成することです。 /etc/{ resolv , nsswitch , gai }.confを使用して、AAAAレコードを照会しません。推奨されるresolv.confオプションno-inet6here は、exactly私が探しているものです。残念ながら、少なくとも私たちのシステムには実装されていません(Debian 7ではlibc6-2.13-38 + deb7u4、Ubuntu 14.04ではlibc6-2.19-0ubuntu6.3)。

では、どうやって? SFや他の場所で提案されている次の方法が見つかりましたが、どれも機能しません。

  • IPv6を完全に無効にする。 /etc/modprobe.d/またはsysctl -w net.ipv6.conf.all.disable_ipv6=1のipv6 LKMをブラックリストに登録する。 (好奇心から:リゾルバーがIPv6が無効になっているAAAAを要求するのはなぜですか?
  • /etc/resolv.confからoptions inet6を削除します。そもそもそこにはありませんでした。inet6は、最近デフォルトで有効になっているだけです。
  • /etc/resolv.confにoptions single-requestを設定します。これにより、AおよびAAAAクエリが並列ではなく順次実行されることが保証されます
  • /etc/gai.confのprecedenceを変更します。これはDNSクエリには影響せず、複数の応答が処理される方法にのみ影響します。
  • 外部リゾルバを使用する(または、壊れたDNSサーバーを回避するローカルリゾルバデーモンを実行する)と役立ちますが、通常、会社のファイアウォールポリシーでは許可されていません。また、内部リソースにアクセスできなくなります。

醜い代替案:

  • LocalhostでDNSキャッシュを実行します。すべての非AAAクエリを転送するが、NOERRORまたはNXDOMAIN(対応するAクエリの結果に応じて)でAAAAクエリに応答するように設定します。ただし、これを実行できるDNSキャッシュについては知りません。
  • いくつかの巧妙なiptables u32一致、またはOndrej Caletkaの iptables DNSモジュール を使用して、AAAAクエリを一致させ、それらをicmp-reject(リゾルバlibがそれにどのように反応するか)、またはそれらにリダイレクトします。空のNOERRORですべてに応答するローカルDNSサーバー。

SEには同様の関連する質問があることに注意してください。私の質問は、解決しようとしている実際の問題を詳しく説明している限りは異なります。明確な要件がリストされており、推奨されないいくつかの非実用的なソリューションがブラックリストに含まれ、単一のアプリケーションに固有ではないためです。 このディスカッション に続いて、質問を投稿しました。

36
Nils Toedtmann

gethostbyname()の使用を中止します。代わりにgetaddrinfo()を使用する必要があります。マニュアルページはこれについてさえ警告しています。

Gethostbyname *()、gethostbyaddr *()、herror()、およびhstrerror()関数は廃止されました。アプリケーションでは、代わりにgetaddrinfo(3)、getnameinfo(3)、およびgai_strerror(3)を使用する必要があります。

これは、名前のonlyAレコードの検索と、それを示すWiresharkキャプチャを示すCの簡単なサンプルプログラムですonlyレコードルックアップがネットワーク経由で行われました。

特に、Aレコードの検索のみを実行する場合は、_ai_family_を_AF_INET_に設定する必要があります。このサンプルプログラムは、返されたIPアドレスのみを出力します。発信接続を確立する方法のより完全な例については、getaddrinfo()のマニュアルページを参照してください。

Wiresharkキャプチャ では、172.25.50.3がローカルDNSリゾルバーです。キャプチャはそこで行われたため、送信クエリと応答も表示されます。 onlyAレコードが要求されたことに注意してください。 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);
}
_
9
Michael Hampton

疑わしい場合は、ソースコードをご覧ください。だから、見てみましょう... gethostbyname() は面白そうです。これは、現在の状況を正確に説明しています。最初にIPv6を試してから、希望する答えが得られない場合はIPv4にフォールバックしてください。このRES_USE_INET6フラグとは何ですか?さかのぼって、それは res_setoptions() から来ています。 resolv.confが読み込まれる場所です。

そして....それは私がアイデアから抜け出しました。 RES_USE_INET6にない場合にresolv.confが設定されているのがどのようになっているのかは、まったくわかりません。

4
BMDan

BINDをローカルリゾルバとして使用できます。AAAAをフィルタリングするオプションがあります。

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

3
Robert Kerr

PDNS-recursorをセットアップし、/ etc/resolv.confに設定して、その中の「AAAA」ルックアップを拒否しましたか? query-local-address6=のようなものを使用する

0
Glueon