2/25/2019

DNSの存在しない名前へのクエリについて (NO!)

ジェフ・ヒューストンのブログより。

February 2019
Geoff Huston

「No!」のどの部分がDNSに認識されていないのか?

ルートサーバーを含む権威DNSサーバーインフラへの攻撃の効果的な形式の1つは、いわゆるランダム名攻撃です。特定のドメイン名のオンライン可用性を目標としたい場合、ランダム名攻撃はそのドメイン内の名前を解決するクエリでドメイン名の正式なネームサーバを飽和させようと試みます。そのようなレベルの負荷では、「正当な」クエリはもはや答えられません。その結果、名前が消えて、サービス拒否攻撃が成功します。

この攻撃は、他の多くの形式の攻撃よりはるかに簡単に実行できます。高度な形式のクエリパケットの作成や、高度なレベルの攻撃ボットのコントロールを必要としません。選択した各ホストから必要なのは、ターゲットドメイン内でランダムな名前を生成し、そのランダムな名前を使用するURLを取得するだけです。これは通常、ホスト上で特権アクセスを必要としない単純なスクリプト内で実現されます。

DNSが「no such domain name」(NXDOMAIN)応答を処理する方法のため、この攻撃は信頼できるサーバーを標的にするのに効果的です。意図的に信頼できるサーバーにプレッシャーをかけることを目的としているため、攻撃者の目的はローカルのDNSリゾルバキャッシュを回避することです。分散攻撃でターゲットの名前空間内に存在する名前が使用されている場合、名前のクエリレベルが様々な組織的な攻撃者から増加するにつれて、解決応答は攻撃者のローカルの再帰リゾルバにキャッシュされます。信頼できるネームサーバを本質的に保護します。たとえ、攻撃は存在しないが一定のクエリ名を使用する場合でも、再帰リゾルバはDNS名が存在しないという事実をキャッシュし、このキャッシュされた情報を使用して同じ名前に対する後続のクエリに応答するので、リゾルバキャッシュは依然として有効です。攻撃がランダムに生成された名前を使用する場合、ローカルキャッシュは特定のクエリ名のみをキャッシュするため無効であり、新しいランダム名に対する各クエリは権限のあるサーバーに渡されて解決されます。

DNSが存在しない名前を解決するための要求をどのように処理するかを理解することは、この形式のランダム名攻撃に対してDNSをより強固にする方法を理解する上で重要な要素です。DNSのこの側面に焦点を当てるためにAPNICラボで、私たちが運営するドメインの一部である存在しないドメイン名へのクエリでDNSを取り除く実験をしていました。

方法は非常に簡単です。オンライン広告に埋め込まれたスクリプトを使用して測定実験を行い、サーバーインフラでクエリデータを収集します。このスクリプトは、存在しないランダムな名前に対するDNS解決クエリを生成します。その後、DNS再帰リゾルバがこれらの同じDNS名について権威あるネームサーバにクエリするのが分かります(図1)。

Nxd fig1

図1 – NXDOMAIN実験

1日あたり何百万ものエンドポイントに広告を表示するように指示することで、地理的な多様性とプラットフォームの多様性の両方に関して、インターネットの幅の大部分を網羅するビューを素早く得ることができます。

予測される結果

私たちはこの簡単な実験から何が期待できるかについての仮説を持っていました。

仮説を説明する前に、DNSリゾルバがどのように構成されているかについてのいくつかの背景を知る必要があります。クライアントには、1つ以上のDNSリゾルバのアドレスがロードされます。例えば、私のISPは2つのそのようなリゾルバアドレスを提供します。それらはDHCPベースの自動設定によって私のデバイスに渡されます。アプリケーションがDNSクエリを生成すると、アプリケーションホストのネームリゾルバ・ライブラリルーチンはこれらのリゾルバアドレスの1つにクエリを送信します。DNSはUDPプロトコルであるため、エンドホストが応答を受け取るという保証はありません。そのため、エンドホストはクエリを起動したときにタイマーを開始します。タイマーが期限切れになり、応答が受信されていない場合は、クエリが繰り返されます。エンドホストに複数のリゾルバが設定されている場合、繰り返しクエリは別のリゾルバに送信される可能性があります。連続してタイムアウトすると、クライアントは設定されたリゾルバ群に対してさらに繰り返しクエリを発行する可能性があります。連続した問い合わせ間の間隔は、総問い合わせ期間が経過するまで長くなることがあり、その時点で問い合わせは破棄されます。

クエリ間のタイムアウト期間、およびクエリがリゾルバ内でアクティブなままでいる時間の合計は、DNSリゾルバの実装とローカル構成設定によって異なります。そのようなアプローチの一例、Microsoftのクライアント・リゾルバライブラリにはクエリーリピート手順の説明があります。

再クエリを実行するのは、クライアントリゾルバライブラリだけではありません。再帰的リゾルバでも同様のタイムアウトメカニズムが使用されています。これらのリゾルバは、応答を受け取らないときにさらにクエリを発行することもあります。名前に対して 2つ以上の権威ネームサーバーが設定されている場合、繰り返しのクエリはネームサーバー群全体に送信されます。典型的には、エンドホストからよりも再帰的リゾルバから再問い合わせするためのはるかに保守的なアプローチを私たちは目にします。エンドホストとフォワーディングリゾルバの両方が非常に攻撃的な一連の再クエリタイマーを使用すると、ロードされたサーバー上で一つのクエリがクエリの嵐を引き起こす可能性があり、一時的な処理イベントが意図しないサービス拒否攻撃に変わる可能性があります!

一般的な振る舞いの原則は、応答しないサーバーはリゾルバからさらにクエリを引き出すことですが、これらの再クエリはサーバーに大きな負荷をかけてはいけません。

クエリと同様に、応答を見てみましょう。ゾーンに名前が存在しない場合は、DNS応答がクエリをした側に返送されます。DNS応答は応答コード3、NXDOMAINを使用します。この応答は、名前がゾーンに含まれていないことを示しています。リゾルバはこの応答を自分のクエリに対する終了応答として解釈する必要があります。これはローカルにキャッシュ可能な応答であるため、クエリの種類に関係なく、同じ名前に対して繰り返しクエリが行われた場合、キャッシュの有効期間中、キャッシュリゾルバはそのローカルキャッシュから回答できます。

私たちはこれで質問に答える事ができます。NXDOMAINでクエリに応答すると、何が期待されますか?

権威サーバーがすべてのクエリに応答しており、複合ネットワーク遅延とサーバー処理遅延の遅延がクライアントの再送信タイマー値の範囲内であると仮定して、各クライアントから1つのクエリが表示されると想定しました。

実験で使用したサーバーのパケットキャプチャを実行して全てのクエリに回答し、これらの名前に対する全てのクエリが一致する応答を生成したことを確認しました。

サーバへの遅延が長いクライアントの場合、繰り返しクエリが発生する可能性がありますが、未解決のクエリがまだクライアントに対して「オープン」であると仮定すると、最初の応答が2番目のクエリのタイムアウトの時間枠内にクライアントに届く可能性があります。

これらの理由で、私たちは例外的な遅延条件がいささかレアであると予想していたので、ドメインの権威サーバによって見られるようにそれぞれの存在しないユニークな名前のための平均クエリ数は2よりはるかに1の値に近いだろうと期待していました。

実際の結果

私たちは実験のランダムなサンプルからのデータを使用し、そして権威サーバーに提示されている名前の最初の30秒以内に存在しない名前のための質問だけを調べました。このデータセットには、6,269,472の測定値が含まれていました。

これらの存在しないドメインに対する権威サーバーで確認されたDNSクエリの数は14,003,675、またはクエリされた一意の名前あたり平均2.23クエリでした。特に上記の我々の期待を考えると、これは驚くほど高い価値です。

実験用に4台のサーバーを運用し、シンガポール、フランクフルト、ダラス、サンパウロにサーバーを配置し、エンドホストがクエリに与えられる名前がそれらの位置に最も近いサーバにDNSクエリを向けるように、実験エンドホストを地理的に配置します。私たちは、エンドホストへの往復時間はほとんどすべての測定エンドポイントで0.5秒以内であり、クライアントソフトウェアで1秒の再クエリータイマーを使用すると、クエリータイムアウトが発生して再クエリを実行して、パフォーマンスが低下するのは10%未満になると予想されます。一意の名前あたり2つを超えるクエリのこの平均は、予想される結果のかなり上回っています。

平均値は大量の情報を隠すため、個々の実験の分布を理解するのに役立ちます。大きすぎるクエリを使用した実験は少数しか見ていないのでしょうか? あるいは、よりノーマルな分布を見ているのでしょうか。

Nxd fig2

図2 – 存在しない一意の名前ごとのクエリ数の分布

図2は、各実験のクエリ数の分布を示しています。

驚くべきことに、名前が定義されていないことを証明するために一つのクエリを使用した実験は43%に過ぎませんでした。この数字は、実験の半数以上が最初のNXDOMAIN応答を受け入れなかったことを意味します。更に36%のリゾルバシステムが2つのクエリを使用してドメイン名が存在しないことを確認し、21%が3つ以上のクエリを使用しました。エンドホストでの実験の初期ロードから30秒にわたるクエリ数の範囲は、1クエリから297クエリまででした!

より低い範囲のクエリ(1〜100)をよく見ると、対数スケールのプロット(図3)がほぼ直線的に減少しています。これは、スケールのないデータの指数関数的な減少と相関しています。

Nxd fig3

図3 - ユニークな存在しない名前ごとのクエリ数のより低い分布範囲

連続するクエリ間の時間間隔はどうですか? 識別できるな時間の特徴はありますか? 最初のクエリの時間をサーバーで見られる時間を開始時間とし、最初のクエリとクエリの時間との間の時間差を使って連続するすべてのクエリを記録すると、これらの時間の分布を見ることができます。そして、私たちはこれらの時間差の分布を調べることができます。それらは図4に示されています。

Nxd fig4

図4 - 最初のクエリから再クエリまでの経過時間の分布

特に最初の問い合わせから4秒から12秒の間に、局所的なピークの間に識別可能な1秒の間隔がある。5、10、20秒のピークもバックグラウンドよりはるかに高いです。しかし、そのような規則的なピークは主要な印ではありません。

この再クエリパターンに寄与する要因はおそらくいくつかあります。

Happy Eyeball

図3と図4で厳密に2つのクエリが密集して配置されているという非常に多くのインスタンスは、Happy Eyeballテクニック(RFC 8305)を使用したデュアルスタックの名前解決の副作用を示しています。デュアルスタックホスト上で実行されているHappy Eyeballアプリケーションは、クエリ名が存在するかどうかに関係なく、名前のAレコードとAAAAレコードに対するクエリを本質的に並行して生成します。

これらのクエリレコードを分割して、AおよびAAAAクエリタイプレコードのクエリ数を別々に見てみましょう(図5)。

Nxd fig5

図5 - AクエリとAAAAクエリが分離された、固有の存在しない名前ごとのクエリ数の分布範囲の下限

このデータの見直しでは、6,269,472(または実験の58%)のうち3,689,593の実験で名前が定義されていないことを証明するためにシングルクエリが使用されました。「シングル」は、一つのAクエリ、一つのAAAAクエリ、あるいは1つのAクエリと1つのAAAAクエリの両方です。それでも、40%強の時間で、同じクエリ名に対して複数のAクエリや複数のAAAAクエリが表示されることがあります。

エンドユーザーの約20%がデュアルスタック・プラットフォームを使用していることを考えると、Happy Eyeballアルゴリズムは、存在しない名前を解決しようとする場合、DNSに同様の追加のクエリ負荷を追加するようです。

一方、4,560,076のクエリをシングルクエリのインスタンスとして扱うことができるため、Happy Eyeballアプローチでは存在しない名前に対する追加クエリをいくつか説明していますが、それでも残りの9,443,599のクエリの説明を探す必要があります。私たちは、同じ存在しないドメイン名に対してクエリを繰り返します。

再クエリのリゾルバ

ここで、応答を失った可能性がありますか? リゾルバがNXDOMAIN応答を受信すると、そのリゾルバが「正常に」実行している場合はそれ以上のクエリを中止し、応答を受信しなかった場合(または制御不能のエラー状態になった場合のみ)、再クエリするという合理的な前提があります。同じクエリタイプに対する同じリゾルバアドレスからの再クエリ間隔の分布を図6に示します。

Nxd fig6

図6 - 同じリゾルバに対する再クエリ間隔の分布

同じリゾルバは、4ms以内に同じクエリを約1%繰り返します。リゾルバがミリ秒の再クエリタイマーを使用することは期待されておらず、再帰的リゾルバは未処理のクエリのリストを保持し、未処理のクエリと同じ名前の新しいクエリを生成しないこと、そして未処理のクエリと同じ名前の新しいクエリを生成ないことを考えると予想外です。

0.2秒、0.28秒、0.38秒、および0.8秒で、クエリ間隔の明確なピークがあります。0.8秒のピークをいくつかのDNSリゾルバの実装の再クエリ間隔に関連付けることは可能です。特定のリゾルバでは、0.2、0.28、0.38秒というかなりアグレッシブな再クエリタイマーがあるかもしれません。0.15秒未満の即時再クエリー負荷がこのように高いのはなぜかは不明です。この間隔はおそらく従来の再クエリ間隔には短すぎるが、ネットワークレベルのパケット重複の結果となるには十分に長くはありません。

データの累積分布(図7)は、総クエリ負荷の約12%が同じリゾルバからの反復クエリであり、再クエリ間隔は1.6秒以内であることを示しています。リゾルバの約8%が、前のクエリの200ミリ秒で再クエリします。これは非常に高速な再送信であるように見え、それがローカルの再クエリタイマー値に基づいていることはほとんどありません。

Nxd fig7

図7 - 同じリゾルバの再クエリ間隔の累積分布

同じリゾルバからの繰り返し問い合わせの原因に関する従来の仮定は、ネットワークパスの輻輳またはローカルリゾルバの輻輳が原因で、リゾルバが以前の応答を受け取っていないことです。ただし、このような短い間隔内で多数のクエリが繰り返されることは、その前提と一致しているようには見えません。

考えられる説明は、再帰リゾルバの集中です。クライアントに2つの転送リゾルバが設定されているが、どちらかのリゾルバへのクエリが同じ再帰リゾルバに渡される場合、以前のクエリがまだ応答を待っている間に再帰リゾルバへのクエリが到着する可能性があります。再帰リゾルバがそのタスクキューを管理する方法によっては、これらの重複したクエリは処理キュー内に残り、まだアクティブ前のクエリにもかかわらず順番に解決される可能性があります。

プライミング・リゾルバファーム

同じリゾルバIPアドレスからのクエリ以外にも、クエリが繰り返される可能性があるもう1つの原因が考えられます。これは、構成が不十分なリゾルバファームです。リゾルバファームは、多くの大規模DNSリゾルバで使用されています。全てのクエリを一つのDNSリゾルバインスタンスに渡すのではなく、スレーブリゾルバのコレクションがあり、着信クエリは解決のためにスレーブインスタンスにスケジュールされます。

私たちが見ているのは、共通のアドレスプレフィックスを共有するリゾルバIPアドレスのクラスタが同じクエリ名に対して繰り返しクエリを作成するという多数のインスタンスです。この動作の例を表1に示します。

リゾルバ クエリ時間
7x.xxx.0.178 0.752
6z.zzz.161.146 0.865
7x.xxx.0.230 0.980
6z.zzz.161.220 1.094
7x.xxx.0.188 1.201
6z.zzz.161.182 1.319
7x.xxx.0.180 1.430
6z.zzz.161.144 1.542
7x.xxx.0.226 1.650
7x.xxx.0.138 1.654
6z.zzz.161.134 1.762
6z.zzz.161.222 1.775

表1 - リゾルバファームの繰り返しクエリ

まとめてリゾルバファームを形成する一連のリゾルバを識別する方法について、非常に近似的な仮定をすることができます。最も簡単な方法は、共通の/24 IPv4アドレスプレフィックスまたは共通の/48 IPv6プレフィックスを共有する全てのリゾルバアドレスをグループ化し、それらを同じリゾルバセットのメンバーと見なすことです。

共通のアドレスプレフィックスを共有するリゾルバからの繰り返しクエリ間の間隔時間の分布は、同じリゾルバIPアドレスからのクエリの以前のケースと非常によく似ています(図8)。リゾルバファームからのクエリの全体量は、クエリ全体の負荷の約29%を占めるように見えます。

Nxd fig8

図8 - 共通アドレスプレフィックスリゾルバの再クエリ間隔を最大30秒に設定した場合の累積分布

共通の/24(IPv6の場合は/48)のこの分類を使用したクエリの繰り返しの発生率は重要です。同じリゾルバがクエリ負荷全体の約12%を占め、さらに16%が同じサブネットにあるリゾルバからのものです。

リゾルバファームクエリ間の時間間隔を図9に示します。

Nxd fig9

図9 - リゾルバファームの再クエリ間隔の分布

リゾルバファームの他の要素が同じクエリ操作を実行するように「フロントロード」シグネチャがあることと、0.38秒および0.8秒でピーク時間が再クエリされることの両方があることは明らかです。そして、0.38秒と0.8秒にピーク時間の再クエリがあり、これは同じリゾルバの再クエリの時間間隔と一致しています。

リゾルバクエリファームをロードするための累積時間分布を図10に示します。リゾルバファーム全体のクエリ時間の半分は0.25秒未満です。

Nxd fig10

図10 - リゾルバファームの再クエリ間隔の累積分布

それで、DNSが「NO!」のどの部分を理解できるのでしょうか。

「NO」の回答を効率的に処理できないというDNSの明らかな不能の説明の一部は、Happy EyeballがDNSの負荷を増大させるという副作用をもたらしたIPv6移行にあります。AおよびAAAAレコードに対して2つの連続したDNSクエリを使用することは、すべてのデュアルスタックエンドホストが単純な名前解決機能に対して2倍のDNSクエリ負荷を生成することを意味します。デュアルスタックエンドポイントの数が現在全体の約20%になっていることを考えると、DNS内に存在しない名前に対して平均約1.2回のクエリが発生すると予想されます。ある意味でこれはデュアルスタックの世界では避けられない副産物です。デュアルスタック展開のレベルが上がるにつれて、DNSでのAおよびAAAAクエリーの同時使用の増加が見込まれます。

しかし、存在しないドメイン名の平均クエリ率は、デュアルスタックホストのプールだけで生成できるものよりはるかに高いことがわかります。他に何が起こっていますか?

DNSにUDPを選択すると、いくつかの興味深い妥協点があります。軽量データグラムプロトコルの使用は、単純なクエリ応答アプリケーションモデルをサポートするための非常に効率的な方法です。DNSのスケーリング能力は、一部には、DNSトランスポート・プロトコルとしてのUDPの選択によるものです。これらのUDPベースのトランザクションではパケット損失の可能性が常に存在しており、ある程度まで再クエリの発生率はパケット損失によるものです。しかし、パケット損失だけで観察されたDNS再クエリ結果を得るために、インターネット上で約50%のパケット損失率を経験しています。かなり壊滅的なレベルのパケット損失が発生したことに気付くでしょう!

データグラムモデルはDNSクライアントにさらにいくつかの困難をもたらします。クライアントは、照会または応答のいずれかがドロップされたことを明確かつ明確に決定することはできません。クライアントができるのは、一定時間待機し、その時点で応答がないことがトランザクションの消失を示していると見なすことだけです。非常に短い再送信タイマは、輻輳時に高速の解決サービスを提供する可能性があります。ただし、再クエリタイマーが短いと、DNSの一時的な輻輳インシデントが悪化する可能性があります。そのため、アグレッシブな再クエリタイマーがDNSクエリの負荷に寄与している可能性があります。

この時点で、存在しないドメイン名に対する高い残存クエリ率を説明するため、DNSリゾルバの不正動作の領域に向かいます。共通のアドレスプレフィックスを共有するクラスタ内のすべてのリゾルバが、ほぼ同時に同じ名前に対するクエリを生成するリゾルバファームの動作が観察されています。NXDOMAIN応答を完全に無視し、受信する可能性のある応答に関係なく高いクエリレートを継続するように見える、高頻度クエリーレートモードに陥るリゾルバ動作も観察されます。

Happy Eyeballを考慮に入れると、存在しない名前に対する61%の解決努力が、権威ネームサーバーへの一つのDNSクエリで解決されることが朗報です。もっと悪いかもしれません。

それほど良くない(悪い)ニュースは、存在しない名前に対する解決の努力の39%が権威ネームサーバーへの単純なDNS問い合わせでは解決されないことです。これは印象的な結果ではありません。

この単純なテストでは、クエリ負荷の分類をいくつか実行できました。これを図11に示します。この方法でクエリ全体の約60%を占めることができました。残りの40件は、この段階でまだ不明です。

Nxd fig11

図11 - クエリの動作と相対的なクエリの量

名前が存在し、解決できる場合はどうでしょうか?

DNSは「YES」を「NO」よりもよく把握していますか?

いいのですが、それほどではありません。名前は、73%の割合で一つのクエリで解決されます。しかし、残りの27%は、名前解決を完了するために2つ以上のクエリを観測しました。解決可能な名前を解決するには、平均してDNS 1.65クエリが必要です。

NOの回答がYESよりも多くのフォローアップDNSクエリを生成する理由については興味深い問題です。これまでのところ、答えが何であるかについての明確な考えはありません。