...私たちの管理外にある壊れたDNSサーバーを補うため。
私たちの問題:さまざまな、主にIPv4のみのサイトでセンサーデータを収集する組み込みデバイスを展開しています。一部のサイトでは、ネットワークのメンテナンスが不十分です。 AAAAクエリを完全に無視するか、壊れた応答(たとえば、間違ったソースIP!)で応答する、誤って構成された、または壊れたDNSキャッシュやファイアウォール。施設部門への外部サプライヤーとして、私たちは(時には消極的な)IT部門にほとんど影響を与えません。彼らがDNSサーバー/ファイアウォールをいつでも修正する可能性は非常に小さいです。
デバイスへの影響は、各gethostbyname()で、プロセスはAAAAクエリがタイムアウトするまで待機する必要があることです。この時点で、一部のプロセスはすでに接続試行を完全にタイムアウトしています。
私はある解決策を探しています...
最も明白な解決策は、リゾルバライブラリを構成することです。 /etc/{ resolv , nsswitch , gai }.confを使用して、AAAAレコードを照会しません。推奨されるresolv.confオプションno-inet6
here は、exactly私が探しているものです。残念ながら、少なくとも私たちのシステムには実装されていません(Debian 7ではlibc6-2.13-38 + deb7u4、Ubuntu 14.04ではlibc6-2.19-0ubuntu6.3)。
では、どうやって? SFや他の場所で提案されている次の方法が見つかりましたが、どれも機能しません。
sysctl -w net.ipv6.conf.all.disable_ipv6=1
のipv6 LKMをブラックリストに登録する。 (好奇心から:リゾルバーがIPv6が無効になっているAAAAを要求するのはなぜですか?)options inet6
を削除します。そもそもそこにはありませんでした。inet6
は、最近デフォルトで有効になっているだけです。options single-request
を設定します。これにより、AおよびAAAAクエリが並列ではなく順次実行されることが保証されますprecedence
を変更します。これはDNSクエリには影響せず、複数の応答が処理される方法にのみ影響します。醜い代替案:
SEには同様の関連する質問があることに注意してください。私の質問は、解決しようとしている実際の問題を詳しく説明している限りは異なります。明確な要件がリストされており、推奨されないいくつかの非実用的なソリューションがブラックリストに含まれ、単一のアプリケーションに固有ではないためです。 このディスカッション に続いて、質問を投稿しました。
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);
}
_
疑わしい場合は、ソースコードをご覧ください。だから、見てみましょう... gethostbyname() は面白そうです。これは、現在の状況を正確に説明しています。最初にIPv6を試してから、希望する答えが得られない場合はIPv4にフォールバックしてください。このRES_USE_INET6
フラグとは何ですか?さかのぼって、それは res_setoptions() から来ています。 resolv.conf
が読み込まれる場所です。
そして....それは私がアイデアから抜け出しました。 RES_USE_INET6
にない場合にresolv.conf
が設定されているのがどのようになっているのかは、まったくわかりません。
BINDをローカルリゾルバとして使用できます。AAAAをフィルタリングするオプションがあります。
https://kb.isc.org/article/AA-00576/0/Filter-AAAA-option-in-BIND-9-.html
PDNS-recursorをセットアップし、/ etc/resolv.confに設定して、その中の「AAAA」ルックアップを拒否しましたか? query-local-address6=
のようなものを使用する