【AD DS】DC ロケーターとは?詳細な仕組みについて解説!

  • 2022年9月11日
  • 2022年9月13日
  • AD DS

Active Directory ドメイン サービスで構築されたドメイン環境では、ドメイン コントローラーがユーザーやコンピューターの管理をしています。Active Directory の仕組みを利用して認証や設定の配布するためには、ドメインに参加している各クライアント端末は、ドメイン コントローラーに対して認証要求を投げたり、設定をダウンロードするため、ドメイン コントローラーへアクセスできる必要があります。

しかしながら、クライアント端末はどのコンピューターがドメイン コントローラーであるかはわからないため、ドメイン コントローラーを探す仕組みが必要です。

今回は、ドメイン コントローラーの探索機能である、DC ロケーターについて紹介します。

 

DC ロケーターとは?

DC ロケーターとは、Windows OS にあるドメイン コントローラーを探す機能のことです。この機能により、ドメイン環境に存在する利用可能なドメイン コントローラーを探すことができます。

Active Directory ドメイン サービスでは、認証や設定の配布などの役割をドメイン コントローラーが担っています。そのため、ドメイン環境を利用するには各端末は、ドメイン コントローラーを探して認証要求を行ったり、配布している設定(グループ ポリシー)を適用したりします。

DC ロケーターは、ドメイン コントローラーを探すときに呼び出されます

アプリケーションやサービスがドメイン コントローラーを探すときは、DsGetDcName 関数を呼び出して、DC ロケーターを利用します。DsGetDcName 関数を呼び出されると、DC ロケーターは指定されたドメインのドメイン コントローラーを探してきて、関数の呼び出し元のアプリケーションやサービスに返します。

DsGetDcName 関数で DC ロケーターを呼び出すと、ドメイン コントローラーの役割をもつサーバーを DNS 名前解決して、その中から利用可能なドメイン コントローラーを探します。利用可能なドメイン コントローラーを見つけたら、DsGetDcName 関数の呼び出し元へ結果を返します。

 

DsGetDcName 関数

DsGetDcName 関数は、DC ロケーターにドメイン コントローラーを探すことを命令できる関数です。

アプリケーションやサービスは、DC ロケーターに対してドメイン コントローラーをを探すように命令するときは、DsGetDcName 関数を呼び出します。DsGetDcName 関数には、以下のような引数が定義されています。

DSGETDCAPI DWORD DsGetDcNameA(
   LPCSTR ComputerName,
   LPCSTR DomainName,
   GUID *DomainGuid,
   LPCSTR SiteName,
   ULONG Flags,
   PDOMAIN_CONTROLLER_INFOA *DomainControllerInfo
);

関数の詳細については、マイクロソフトの公開情報からも確認できます。

DsGetDcNameA function (dsgetdc.h)
https://docs.microsoft.com/en-us/windows/win32/api/dsgetdc/nf-dsgetdc-dsgetdcnamea

 

DsGetDcName 関数には、いくつか引数が定義されており、その中でも重要な引数について説明します

 

DomainName
ドメイン コントローラーを探す対象のドメイン名を指定します。

SiteName
ドメイン コントローラーを探す対象のサイトを指定します。NULL を指定すると(=何も指定しないと)、そのコンピューターが所属しているサイトのドメイン コントローラーを探す動作となります。

Flags
ドメイン コントローラーを探す際の要件を指定することができます。例えば、DS_PDC_REQUIRED というフラグを指定すると、PDC エミュレーターという役割をもつドメイン コントローラーを探すことができます。この flags に指定できるフラグについては、後ほど説明します。

*DomainControllerInfo
DC ロケーターが探してきたドメイン コントローラーの情報がこの引数にセットされます。DsGetDCName 関数を呼び出したアプリケーションやサービスは、この引数の値にセットされているドメイン コントローラーへ接続します。 

 

引数 flags について

DsGetDcName 関数の引数 flags に指定できるフラグとして、多くのフラグが定義されています。今回は、中でもよく使われる重要なフラグを紹介します。

DS_BACKGROUND_ONLY

DC ロケーターは探してきたドメイン コントローラーの結果を 15 分間キャッシュとして保持します。アプリケーションやサービスが DsGetDCName 関数を呼び出すと、DC ロケーターはキャッシュが有効であれば、ドメイン コントローラーを探さずにキャッシュを結果として返します。flags に DS_BACKGROUND_ONLY が指定されていると、キャッシュが 15 分以上経過して有効でなくとも、DC ロケーターはキャッシュの結果を返す動作になります。

DS_DIRECTORY_SERVICE_<数字>_REQUIRED

flags に DS_DIRECTORY_SERVICE_<数字>_REQUIRED が指定されていると、指定のバージョン以上の OS のドメイン コントローラー探して結果を返す動作となります。各フラグの意味は以下の表の通りとなります。

DS_DIRECTORY_SERVICE_6_REQUIRED Windows Server 2008 以降の OS
DS_DIRECTORY_SERVICE_8_REQUIRED Windows Server 2012 以降の OS
DS_DIRECTORY_SERVICE_9_REQUIRED Windows Server 2012 R2 以降の OS
DS_DIRECTORY_SERVICE_10_REQUIRED Windows Server 2016 以降の OS

 

DS_FORCE_REDISCOVERY

DC ロケーターは探してきたドメイン コントローラーの結果を 15 分間キャッシュとして保持します。アプリケーションやサービスが DsGetDCName 関数を呼び出すと、DC ロケーターはキャッシュが有効であれば、ドメイン コントローラーを探さずにキャッシュを結果として返します。flags に DS_FORCE_REDISCOVERY が指定されていると、キャッシュを全く参照せずに、再度ドメイン コントローラーを探す動作となります。サービスやアプリケーションが DsGetDCName 関数を呼び出したときに、返されたドメイン コントローラーから応答がなかった後のリトライの時のように、再度 DsGetDCName 関数を呼び出すときに、確実に利用できるドメイン コントローラーを返してもらうことを目的として指定するフラグとなります。

 

DS_GC_SERVER_REQUIRED

flags に DS_GC_SERVER_REQUIRED フラグが指定されていると、グローバル カタログの役割をもっているドメイン コントローラーを返えされます。

 

DS_KDC_REQUIRED

flags に DS_KDC_REQUIRED フラグが指定されていると、Kerberos 認証の要求を受け付けられる Key Distribution Center (KDC) の役割をもつドメイン コントローラーを返えされます。

 

DS_ONLY_LDAP_NEEDED

flags に DS_ONLY_LDAP_NEEDED フラグが指定されていると、LDAP サーバーが返えされます。ドメインに参加している端末は、LDAP と呼ばれるプロトコルを使って、ドメイン コントローラーを対して AD データベースの内容をクエリしたりすることができます。LDAP に応答できるサーバーのことを LDAP サーバーと呼びます。

 

DS_TRY_NEXTCLOSEST_SITE

DsGetDcName 関数を呼び出すと、通常はコンピューターが所属するサイトのドメイン コントローラーが返されます。仮にコンピューターが東京サイトに所属している場合、東京サイトのドメイン コントローラーが返されます。ただし、東京サイトのドメイン コントローラーが全てダウンしている場合、クライアントはドメイン コントローラーをみつけることができません。その場合には、通常はドメイン内の全てのサイトを対象に、ドメイン コントローラーを探します。

flags に DS_TRY_NEXTCLOSEST_SITE を指定されていると、クライアントに所属するサイトから次に近いサイトのドメイン コントローラーを探すという動作になります。例えば、東京サイト、名古屋サイト、大阪サイト、福岡サイトがある場合、東京サイトに所属するコンピューターが東京サイトでドメイン コントローラーを見つけられない場合、次はより近い名古屋サイトを対象にドメイン コントローラーを対象にドメイン コントローラーを探します。

 

DS_WRITABLE_REQUIRED

flags に DS_WRITABLE_REQUIRED フラグが指定されていると、書き込み可能なドメイン コントローラーが返されます。

Windows Server 2008 以降から読み取り専用のドメイン コントローラー(RODC:Read Only Domain Controller)と呼ばれる読み取り専用のドメイン コントローラーが構築できるようになりました。サービスやアプリケーションがドメイン コントローラーへ書き込みを行いたい場合、DsGetDcName 関数の呼び出しの結果として RODC が返されないように、DS_WRITABLE_REQUIRED フラグを指定して書き込み可能なドメイン コントローラーを探せるようにします。

 

探索した DC 情報のキャッシュ

DC ロケーターは探索したドメイン コントローラーの情報を、15 分間キャッシュとして保存します。DsGetDcName 関数を呼び出されたてドメイン コントローラーを探索した後、次に DsGetDcName 関数が呼ばれたら、以下のような動作となります。

  • 15 分以内に DsGetDcName 関数が呼び出されたら、キャッシュを返す
  • 15 分経過して DsGetDcName 関数が呼び出されたら、ドメイン コントローラーを探索する

 

 

DC ロケーターの動作

DsGetDcName 関数に呼び出した時、DC ロケーターがドメイン コントローラーを探す動作について紹介します。ドメイン コントローラーを探す動作の概要は以下の通りです。

  1. DNS サーバーから、コンピューターが所属するサイトのドメイン コントローラーの一覧を問い合わせ
  2. DNS サーバーから返された全てのドメイン コントローラーに対して LDAP Ping を送信
  3. LDAP Ping に最も早く応答したドメイン コントローラーを結果として応答
  4. 全てのドメイン コントローラーから LDAP Ping の応答がなかった場合、再度 DNS サーバーに全てのサイトのドメイン コントローラーの一覧を問い合わせ
  5. DNS サーバーから返された全てのドメイン コントローラーに対して LDAP Ping を送信
  6. LDAP Ping に最も早くドメイン コントローラーを結果として応答

各動作の詳細は以下の通りです。

 

1. キャッシュの参照

DsGetDcName 関数が呼び出された際に探したドメイン コントローラーの有効期間内のキャッシュが存在すれば、そのキャッシュを利用します。ドメイン コントローラーのキャッシュの有効期間は 15 分間です。

DsGetDcName 関数の呼び出しの際に、DS_BACKGROUND_ONLY フラグを指定した場合は、有効期間に関係なくキャッシュの結果を応答します。

また、DsGetDcName 関数の呼び出しの際に、DS_FORCE_REDISCOVERY フラグを指定した場合は、有効期間に関係なく、ドメイン コントローラーを探します。

キャッシュを利用せずに、ドメイン コントローラーを探す場合は次のステップに続きます。

 

2. クライアント端末が所属しているサイトの参照

クライアント端末が所属しているサイトは、以下のレジストリに保存されています。レジストリの値を参照して所属しているサイトの情報の取得します。

キー: HKLM\SYSTEM\CurrentControlSet\services\Netlogon\Parameters
値の名前: DynamicSiteName
クライアント端末が所属するサイトを手動で設定することもできます。手動でサイトを設定する場合には、レジストリ SiteName に定義することができます。SiteName が設定されている場合は、DynamicSiteName の値は無視されて SiteName にあるサイトを参照します。

キー: HKLM\SYSTEM\CurrentControlSet\services\Netlogon\Parameters
値の名前: SiteName

 

3. クライアントが所属するサイトの SRV レコードの名前解決

クライアントが所属しているサイトを指定して、同じサイトに所属するドメイン コントローラーの情報を探索します。具体的には、DNS サーバーに対して以下の SRV レコードの名前解決を行います。

クエリの種類: SRV (Service Locator Resource Record)
クエリ名: _ldap._tcp.<サイト名>._sites.dc._msdcs.<ドメイン名>
 

4. LDAP Ping の送信

SRV レコードの名前解決の結果から得られたドメイン コントローラーの一覧から、順次、LDAP Ping を送信し、最も早く応答したドメイン コントローラーを、DsGetDcName 関数の結果として返します。
LDAP Ping を送信する間隔は、1 台目から 4 台目までは 0.4 秒ごと、5 台目から 9 台目までは 0.2 秒ごと、10 台以上の場合には 0.1 秒ごととなります。
また、LDAP Ping を送信する順番は、SRV レコードに設定されている優先順位や重さを基準にして、ドメイン コントローラーの一覧の並べ替えを行います。並べ替えた順序の通りに、LDAP Ping を送信します。そのため、優先順位や重さが高いドメイン コントローラーの方が優先して選ばれやすくなります。
 

5. ドメイン全体の SRV レコードの解決

LDAP Ping の結果より、サイト内のどのドメイン コントローラーからも応答が得られなかった場合、サイトの指定を行わずにドメイン内すべてのドメイン コントローラーの情報を探索します。具体的には、DNS サーバーに対して以下の SRV レコードの名前解決を行います。
クエリの種類: SRV (Service Locator Resource Record)
クエリ名: _ldap._tcp.dc._msdcs.<ドメイン名>
 

6. LDAP Ping の送信

SRV レコードの名前解決の結果から得られたドメイン コントローラーの一覧から、順次、LDAP Ping を送信します。
もし、クライアント端末に [次に最も近いサイトを試す] ポリシーが適用されておらず、また、DsGetDcName 関数の呼び出しの際に DS_TRY_NEXTCLOSEST_SITE フラグが設定されていない場合、最も応答が早かったドメイン コントローラーをDsGetDcName 関数の結果として返します。どのドメイン コントローラーからも応答が返ってこなかった場合は、ERROR_NO_SUCH_DOMAIN を返します。
一方、クライアント端末に [次に最も近いサイトを試す] ポリシーが適用されている、もしくは、DsGetDcName 関数の呼び出しの際に DS_TRY_NEXTCLOSEST_SITE フラグが設定されている場合、LDAP Ping の応答の内容を確認し、クライアント端末が所属しているサイトに次に近いサイトの名前を確認して、次の手順 7 以降の処理を行います。
 
パス:[コンピューターの構成] – [管理用テンプレート] – [システム] – [Net Logon] – [DC ロケーター DNS レコード]
ポリシー:[次に最も近いサイトを試す]
 
 

7. クライアント端末が所属するサイトから次に近いサイトの SRV レコードの解決

クライアント端末が所属するサイトから次に近いサイトの情報を利用して、サイトに所属するドメイン コントローラーの情報を探索します。具体的には、DNS サーバーに対して以下の SRV レコードの名前解決を行います。
クエリの種類: SRV (Service Locator Resource Record)
クエリ名: _ldap._tcp.<次に近いサイト名>._sites.dc._msdcs.<ドメイン名>
 

8. LDAP Ping の送信

SRV レコードの名前解決の結果から得られたドメイン コントローラーの一覧から、順次、LDAP Ping を送信します。
どのドメイン コントローラーからも応答が返ってこなかった場合は、ERROR_NO_SUCH_DOMAIN を返します。
 

DC の強制的再検出

DsGetDcName 関数が呼び出された時に、DC ロケーターがドメイン コントローラーのキャッシュの結果を返し、同じドメイン コントローラーばかりを利用する状態となることがあります。(この状態を Domain Controller Stickness と呼びます)

DC ロケーターの探索手順の手順 1 の通り、DsGetDcName 関数の呼び出しの際に DS_BACKGROUND_ONLY フラグを指定して探索すると、キャッシュの有効期間が切れていたとしても DC ロケーターはキャッシュの結果を返します。 毎回、関数の呼び出しの際に DS_BACKGROUND_ONLY フラグを指定されている場合、非常に古いキャッシュを返し続ける結果となり、同じドメイン コントローラーが利用され続けてしまいます。

これを防ぐために、一定の間隔(既定は 12 時間)で使用可能なドメイン コントローラーを強制的に再検出する動作にすることができます。この設定を行っている場合、DS_BACKGROUND_ONLY フラグ付きで DsGetDcName 関数を呼んでも、既定の間隔でドメイン コントローラーを再検出することになりますので、ポリシーで設定されている間隔以上の期間が経過したキャッシュが利用されることはありません。

 

パス: [コンピューターの構成] – [管理用テンプレート] – [システム] – [Net Logon] – [DC ロケーター DNS レコード]

ポリシー名: [強制的再検出の間隔]