組み込みLinuxデバイスで、起動時にIPアドレス0.0.0.0
の逆ルックアップを実行することを要求するアプリケーションを実行しています。これは最終的にgethostbyaddr
を呼び出すことになります。
gethostbyaddr
呼び出しがすぐに(失敗して)完了することもありますが、5秒または10秒の遅延(DNSタイムアウト?)が表示されることもあります。遅延が発生するケースをまだ特定できていません。
いくつかのヒント:
初期のinitスクリプトの1つでこれを実行すると、起動時にIP6サポートが無効になります。
echo 1 >/proc/sys/net/ipv6/conf/all/disable_ipv6
echo 1 >/proc/sys/net/ipv6/conf/default/disable_ipv6
echo 1 >/proc/sys/net/ipv6/conf/lo/disable_ipv6
これは(私が思うに)これを破棄する必要があります: https://www.netroby.com/view/3695
私はAvahi/MDNSを使用していません。これは破棄する必要があります: https://bugs.launchpad.net/ubuntu/+source/nss-mdns/+bug/9494
デバイスはローカルDNSサービスを実行していません
この問題は、DHCPまたは静的IP構成のいずれかで発生します。 DHCPを使用する場合、DSLルーターは自分自身をDNSサーバーとしてアドバタイズします。ただし、静的IP構成を使用する場合は、DNSサーバーとして8.8.8.8を使用します(したがって、DSLルーター側のバグのあるDNSサーバーを破棄する必要があります)
ここで何が起こっているのかについてのアイデアはありますか?
更新:
/etc/nsswitch.conf
の関連行は現在次のとおりです。
hosts: files dns
簡単なテストアプリで問題を再現することができました。タイムアウトが発生したときのstrace出力のフラグメントは次のとおりです。
291 23:34:30 connect(6, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("8.8.8.8")}, 16) = 0 <0.000077>
291 23:34:30 gettimeofday({tv_sec=1514849670, tv_usec=139862}, NULL) = 0 <0.000032>
291 23:34:30 poll([{fd=6, events=POLLOUT}], 1, 0) = 1 ([{fd=6, revents=POLLOUT}]) <0.000049>
291 23:34:30 send(6, "\r\231\1\0\0\1\0\0\0\0\0\0\0010\0010\0010\0010\7in-addr\4arp"..., 38, MSG_NOSIGNAL) = 38 <0.000128>
291 23:34:30 poll([{fd=6, events=POLLIN}], 1, 5000) = 0 (Timeout) <5.005152>
291 23:34:35 gettimeofday({tv_sec=1514849675, tv_usec=147536}, NULL) = 0 <0.000088>
291 23:34:35 poll([{fd=6, events=POLLOUT}], 1, 0) = 1 ([{fd=6, revents=POLLOUT}]) <0.000086>
291 23:34:35 send(6, "\r\231\1\0\0\1\0\0\0\0\0\0\0010\0010\0010\0010\7in-addr\4arp"..., 38, MSG_NOSIGNAL) = 38 <0.000206>
291 23:34:35 poll([{fd=6, events=POLLIN}], 1, 5000) = 1 ([{fd=6, revents=POLLIN}]) <0.045356>
291 23:34:35 ioctl(6, FIONREAD, [106]) = 0 <0.000087>
291 23:34:35 recvfrom(6, "\r\231\201\203\0\1\0\0\0\1\0\0\0010\0010\0010\0010\7in-addr\4arp"..., 1024, 0, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("8.8.8.8")}, [28->16]) = 106 <0.000096>
最初のDNS要求は応答を受け取りません。その後、5秒のタイムアウトの後、ほとんどすぐに応答を受け取る再試行があります。
ネットワークが完全に稼働していなかった(DNS要求が失われた)か、ランダムなパケット損失であった可能性があります(特にWiFiで発生します)。前者は、アプリの起動をもう少し待つことで対処できます。後者はかなり避けられません。
ただし、役立つ可能性のあるいくつかのアプローチ:
アプリを修正します。これはオプションではないか、すでに実行していると思います。
0.0.0.0のエントリを/etc/hosts
に入力します。次に、「ファイル」を介して解決する必要があります。これは基本的に瞬時に行われます。もちろん、これには0.0.0.0に名前を付ける必要があり、アプリの動作が変わる場合と変わらない場合があります。これがうまくいく場合は、これが最も簡単なオプションです。
ボックスにDNSが必要ない場合は、/etc/nsswitch.conf
からDNSを削除して完全に無効にします。
0.0.0.in-addr.arpaに対して権限を持つように構成できるローカルDNSキャッシュを実行します。次に、0.0.0.0のNXDOMAINをすばやく返すことができます。これを実行できるローカルキャッシュを提供することを目的としたプログラムがいくつかあります。たとえば、dnsmasqはかなり人気があります。必要な機能に応じて、Unboundなどの他の機能もあります。
少なくともglibcでは、options timeout:2 attempts:4
のようなものを/etc/resolv.conf
に入れることで、タイムアウトと再試行の動作を変更できます。タイムアウトを減らす場合は、DNSサーバーが解決するのに時間がかかることがあるため、試行回数を増やすことをお勧めします(ただし、タイムアウトが発生すると、キャッシュから迅速に応答するはずです)。
独自のNSSモジュールを作成して、0.0.0.0のhosts
ルックアップをすばやく失敗させることができます。少なくともglibcについては、 glibcマニュアル§29 に説明があります。