PowershellWindows

「DNSレコードを入れたのに反映されない」の切り分け【Resolve-DnsNameの4つの落とし穴】

スポンサーラベル
Resolve-DnsNameの応答を4パターンで見分ける。正常はレコード種別が返る、NODATAはSOAだけが返る、ワイルドカードは別のレコードが返る、NXDOMAINは例外になる Powershell

当サイトはアフィリエイト広告を利用しています。

証明書の取得やメールの認証設定で、DNSにレコードを1本足す作業が出てきます。管理画面で保存して、確認のために Resolve-DnsName を叩く。ここで「何か返ってきたから設定できている」と読むと、かなりの確率で間違います。

実際に手元で計測すると、レコードが存在しなくてもエラーにならず、ワイルドカードが設定されていると存在しないサブドメインでもIPアドレスが返ってきます。どちらも「引けた」ように見えます。

Resolve-DnsNameの応答を4パターンで見分ける。正常はレコード種別が返る、NODATAはSOAだけが返る、ワイルドカードは別のレコードが返る、NXDOMAINは例外になる

この記事では、実務で出てくるレコード種別を整理したうえで、実測した4つの落とし穴と確実に切り分けるための手順をまとめます。検証は Windows 11 Pro・PowerShell 7.4.20 で行いました。掲載しているIPアドレスはRFC5737のドキュメント用アドレスに置き換えています。

1. 結論:レコード種別でフィルタして、権威サーバーに直接聞く

先に答えです。

# 権威サーバーに直接聞き、目的のレコード種別だけを取り出す
$records = Resolve-DnsName '_acme-challenge.example.com' -Type TXT `
    -Server ns1.example-dns.jp -ErrorAction SilentlyContinue |
    Where-Object Type -eq 'TXT'

# 件数で判定する。$records が空なら「まだ入っていない」
"TXT count: " + @($records).Count

押さえるのは3点です。

  • Where-Object Type -eq で目的の種別に絞る(絞らないと別の種別を拾う)
  • -Server で権威サーバーを直接指定する(キャッシュを経由させない)
  • 戻り値の件数で判定する(例外の有無では判定できない)

なぜこの3点なのかを順に見ていきます。

2. 実務で出てくるレコード種別

落とし穴の話に入る前に、出てくるレコードを整理します。まず、そのドメインが持っているレコードを全部見てみます。

# 種別を指定せず、権威サーバーが持っているものを全部取る
Resolve-DnsName example.com -Type ALL -Server ns1.example-dns.jp |
    Select-Object Name, Type, TTL

実測では A / NS / SOA / MX / TXT の5種類・21件が返りました。実務で触るのはこの範囲に、AAAA と CNAME を足したくらいです。

種別引くと返るもの実務で出る場面
AIPv4アドレスWebサーバーの向き先
AAAAIPv6アドレスIPv6対応の確認
CNAME別の名前(別名)CDN、証明書の検証レコード
TXT任意の文字列SPF、DKIM、所有権確認、証明書のDNS-01
MXメールの宛先ホストメール配送先の指定
NSこのゾーンを管理するサーバーネームサーバーの委任先
SOAゾーンの管理情報答えが無いときに返ってくる

この記事で重要なのは最後の SOA です。

2.1 SOAは「答えが無い」ときの返事に使われる

SOA(Start of Authority)は、そのゾーンを誰がどう管理しているかを示す1件だけのレコードです。中身を見ると管理情報が入っています。

Resolve-DnsName example.com -Type SOA -Server ns1.example-dns.jp |
    Where-Object Type -eq 'SOA' |
    Select-Object Name, PrimaryServer, NameAdministrator, SerialNumber
Name              : example.com
PrimaryServer     : ns1.example-dns.jp
NameAdministrator : root.example-dns.jp
SerialNumber      : 0

ここまでは普通の使い方です。問題は、SOAが「そのレコードは持っていません」という返事としても使われることです。

実例として、IPv6アドレスを設定していないドメインに AAAA を要求してみます。

Resolve-DnsName example.com -Type AAAA
types returned: SOA

AAAAを頼んだのにSOAが返りました。 IPv6が設定されていないためです。エラーにはなりません。この挙動が、次章の落とし穴そのものになります。

3. 落とし穴①:レコードが無くてもエラーにならない

存在しないTXTレコードを引いてみます。-ErrorAction Stop を付けているので、無ければ例外になるはずです。

# TXTレコードを設定していない名前を、あえてTXTで引く
Resolve-DnsName '_acme-challenge.example.com' -Type TXT -ErrorAction Stop

実際の結果です。

Name             Type TTL   Section    PrimaryServer      NameAdministrator
----             ---- ---   -------    -------------      -----------------
example.com      SOA  3600  Authority  ns1.example-dns.jp root.example-dns.jp

例外は発生せず、SOAレコードが1件返ってきました。 TXTを要求したのにSOAが返るのは、DNSとしては正しい挙動です。「その名前は存在するが、要求された種別のレコードは持っていない」という応答(NODATA)で、権威サーバーの情報としてSOAが添えられます。

問題は、PowerShell上ではこれが「1件取れた」と見えることです。件数だけを数えると1になります。

# これは誤り。種別を問わず数えているので、SOAを数えてしまう
$r = Resolve-DnsName '_acme-challenge.example.com' -Type TXT -ErrorAction SilentlyContinue
"count: " + @($r).Count          # → 1(TXTは0件なのに)

# 正しい判定。種別で絞ってから数える
"TXT: " + @($r | Where-Object Type -eq 'TXT').Count   # → 0

種別で絞れば0件と分かります。-Type は「要求する種別」であって「返ってくる種別の保証」ではありません。

TXTレコードはSPFやDKIMの設定でも使うので、同じ確認方法がそのまま使えます。設定内容そのものについてはメールセキュリティの基本 DKIM・SPFの仕組みと設定方法にまとめています。

4. 落とし穴②:ワイルドカードがあると、存在しない名前でも引ける

次がより厄介です。適当なサブドメインを、権威サーバーに直接聞いてみます。

# 設定した覚えのない名前を3つ引いてみる
foreach ($n in @('zzz-nonexistent-1.example.com',
                 'aaa-bbb-ccc-999.example.com',
                 '_acme-challenge.example.com')) {
    $r = Resolve-DnsName $n -Type A -Server ns1.example-dns.jp -ErrorAction SilentlyContinue
    $ip = ($r | Where-Object Type -eq 'A' | ForEach-Object { $_.IPAddress }) -join ','
    "  $n -> [$ip]"
}

結果です。

  zzz-nonexistent-1.example.com -> [203.0.113.10]
  aaa-bbb-ccc-999.example.com   -> [203.0.113.10]
  _acme-challenge.example.com   -> [203.0.113.10]

3つとも同じIPアドレスが返りました。 設定していない名前です。原因はワイルドカードレコード(*)で、レンタルサーバーでは既定で入っていることがあります。

比較のため、ワイルドカードが無いドメインで同じことをすると、こうなります。

Resolve-DnsName 'zzz-nonexistent-1.microsoft.com' -Type A -ErrorAction Stop
Resolve-DnsName : zzz-nonexistent-1.microsoft.com : DNS 名がありません。

こちらは Win32Exception として例外になります(NXDOMAIN)。

つまりワイルドカードがあるドメインでは、「名前が引けたこと」は自分の設定が入った証拠になりません。証明書の検証レコードを入れたつもりで確認したら引けた、しかし実際にはワイルドカードが答えていただけ、という取り違えが起きます。

なお、ワイルドカードそのものを照会することはできません。

# ワイルドカードレコード自体は引けない(空が返る)
Resolve-DnsName '*.example.com' -Type A -Server ns1.example-dns.jp

ワイルドカードの有無を知りたいときは、ランダムな名前を引いて答えが返るかどうかで判断します。返ってくるならワイルドカードがあります。

5. 落とし穴③:TTLの残り値では反映を判定できない

「TTLが減っていればキャッシュ、元の値なら新しく取得した」と考えたくなりますが、これも成立しませんでした。

ローカルキャッシュを消してから、12秒の間隔で2回引いた実測です。

Clear-DnsClientCache
$x1 = (Resolve-DnsName example.com -Type A | Where-Object Type -eq 'A').TTL
Start-Sleep -Seconds 12
$x2 = (Resolve-DnsName example.com -Type A | Where-Object Type -eq 'A').TTL
"  TTL: $x1 -> $x2"
  TTL: 3567 -> 3600

減るどころか増えました。 1回目の3567は、ローカルキャッシュを消しても上位のリゾルバ(社内DNSやISPのDNS)にキャッシュが残っていて、その残り時間が返ったためです。12秒後は別の経路で取得したか、キャッシュが更新されて元の3600に戻っています。

Get-DnsClientCache の TimeToLive も同じ値で動きました。

Get-DnsClientCache -Entry example.com | Select-Object Entry,Type,TimeToLive

TTLの数字は「どこのキャッシュを見ているか」で変わるため、反映済みかどうかの判断材料になりません。 判断するには次の項目のとおり権威サーバーに直接聞きます。

6. 落とし穴④:リゾルバ経由では自分の設定を確認できない

Resolve-DnsName は既定で、端末が使っているDNSサーバー(社内DNSやルーター)に問い合わせます。そこにキャッシュが残っていると、古い答えが返り続けます。

権威サーバーを直接指定すれば、キャッシュを飛ばして現在の設定を見られます。

# 権威サーバー(ネームサーバー)を調べる
Resolve-DnsName example.com -Type NS | Where-Object Type -eq 'NS' |
    Select-Object Name,TTL,NameHost

# そのサーバーに直接聞く
Resolve-DnsName example.com -Type A -Server ns1.example-dns.jp |
    Where-Object Type -eq 'A' | Select-Object Name,TTL,IPAddress

権威サーバーに直接聞いた場合、TTLは常に設定値そのまま(この例では3600)が返ります。途中でキャッシュされていないためです。この性質を使えば、「権威では既に新しい値になっているが、社内DNSのキャッシュが切れていないだけ」という状況を切り分けられます。

自分の設定が正しいかを確かめたいときは権威サーバーへ、読者や利用者から見えているかを確かめたいときは既定のリゾルバへ、と使い分けます。

7. CNAMEは多段になる

証明書の検証レコードはCNAMEで指定される場合があります。CNAMEは連鎖するため、1回の照会で複数段が返ります。

Resolve-DnsName www.microsoft.com | Select-Object Name,Type,TTL,NameHost
Name                               Type TTL NameHost
----                               ---- --- --------
www.microsoft.com                 CNAME 409 www.microsoft.com-c-3.edgekey.net
www.microsoft.com-c-3.edgekey.net CNAME 409 e13678.dscb.akamaiedge.net
e13678.dscb.akamaiedge.net         AAAA  57
e13678.dscb.akamaiedge.net          A    47

CNAMEが2段あり、最終的にAとAAAAに解決されています。 自分が設定したCNAMEが正しく向いているかを見るときは、Where-Object Type -eq 'CNAME' で絞り、1段目の Name が自分の設定した名前になっているかを確認します。多段の途中だけを見て判断すると取り違えます。

8. digは標準では使えない

DNSの解説記事では dig が使われますが、Windowsには標準で入っていません。

Get-Command dig -ErrorAction SilentlyContinue   # → 何も返らない

Windows標準で使えるのは nslookup.exe と Resolve-DnsName(DnsClientモジュール)の2つです。nslookup は対話モードがあり手早い一方、出力が文字列なので後処理がしにくいです。スクリプトに組み込むなら Resolve-DnsName を使い、オブジェクトのまま Where-Object で絞るのが確実です。

9. まとめ

DNSの確認で取り違えやすい4点を、実測をもとに整理しました。

  • レコードが無くても例外にならない。 種別の無い応答ではSOAが返るため、件数だけ数えると1件に見える
  • ワイルドカードがあると、設定していない名前でも答えが返る。 「引けたこと」は設定の証拠にならない
  • TTLの残り値は見ているキャッシュ次第で変わる。 反映判定には使えない
  • 既定のリゾルバはキャッシュを返す。 自分の設定は -Server で権威サーバーに直接聞く

切り分けの順番としては、まず権威サーバーを -Type NS で調べ、その権威サーバーに -Server を付けて目的の種別だけを引き、件数で判定するのが確実です。ランダムな名前を1つ引いてワイルドカードの有無を先に確かめておくと、余計な回り道を避けられます。

次回は、この確認方法を使って証明書の検証レコードを実際に通すところを解説します。

PowerShellの学習におすすめの書籍

PowerShell を体系的に学ぶなら、PowerShell Core 以降のクロスプラットフォーム対応をふまえた解説書が分かりやすいです。Windows の自動化にとどまらず、macOS や Linux でも動く現在の PowerShell を、基礎から実務での使い方まで通して押さえられます。

PowerShell実践ガイドブック クロスプラットフォーム対応の次世代シェルを徹底解説

コメント

タイトルとURLをコピーしました