DNS

DNS(Domain Name System)完全ガイド

はじめに

DNS(Domain Name System)は、人間が理解しやすいドメイン名(例: www.example.com)をコンピュータが通信に使用するIPアドレス(例: 93.184.216.34)に変換する、インターネットの基盤システムである。1983年にPaul MockapetrisによってRFC 882/883として提案され、現在のRFC 1034/1035として標準化された。

DNSは「インターネットの電話帳」とも呼ばれ、Web、メール、VPN、CDNなど、事実上すべてのインターネットサービスが依存している。DNSが停止すると、ドメイン名による通信が不可能になり、インターネット全体に甚大な影響を及ぼす。

本記事では、DNSの基本概念、階層構造、名前解決プロセス、レコードタイプ、サーバー設定、セキュリティ(DNSSEC、DoH/DoT)、パフォーマンス最適化、トラブルシューティングまで、DNSの全容を体系的に解説する。


第1章: DNSの基本概念

1.1 DNSの役割

DNSは以下の主要な機能を提供する:

機能説明
名前解決(正引き)ドメイン名 → IPアドレス(Aレコード、AAAAレコード)
逆引きIPアドレス → ドメイン名(PTRレコード)
メールルーティングドメイン → メールサーバー(MXレコード)
サービス検出サービスの場所とポート(SRVレコード)
テキスト情報SPF、DKIM、DMARCなどのポリシー(TXTレコード)
エイリアスドメインの別名(CNAMEレコード)
権限委譲サブドメインの管理権限の委譲(NSレコード)

1.2 DNSの階層構造

DNSは分散型の階層データベースとして設計されている。

                    . (ルート)
                   /|\
                  / | \
                 /  |  \
               com  net  org  jp  uk  ...  (TLD: トップレベルドメイン)
              /|\        |
             / | \       |
            /  |  \      |
       google amazon example  co  ac  ...  (SLD: セカンドレベルドメイン)
          |              |
         www           yahoo
                         |
                        www

ドメイン名の構造:

www.example.com.
 │     │     │  │
 │     │     │  └─ ルートドメイン(通常省略、末尾のドット)
 │     │     └──── TLD(トップレベルドメイン)
 │     └────────── SLD(セカンドレベルドメイン)
 └──────────────── サブドメイン(ホスト名)

FQDN(完全修飾ドメイン名): www.example.com.(末尾にドットを含む)

1.3 TLD(トップレベルドメイン)の種類

種類説明
gTLD(汎用).com, .net, .org, .info汎用的に使用可能
ccTLD(国別).jp, .uk, .de, .cn国・地域コード
新gTLD.tokyo, .app, .dev, .cloud2012年以降に追加
sTLD(スポンサー付き).edu, .gov, .mil特定組織向け
インフラTLD.arpaインフラ用途(逆引きなど)

1.4 DNSの構成要素

┌─────────────┐    ┌──────────────────┐    ┌──────────────────┐
│   クライアント  │    │  リゾルバ           │    │  権威DNSサーバー    │
│ (スタブリゾルバ)│───>│(フルリゾルバ/       │───>│ (Authoritative)    │
│              │<───│ キャッシュDNS)      │<───│                    │
└─────────────┘    └──────────────────┘    └──────────────────┘
                          │
                          │ キャッシュ
                          ▼
                   ┌──────────────┐
                   │  キャッシュ     │
                   │  (TTLベース)   │
                   └──────────────┘
コンポーネント役割
スタブリゾルバOSの名前解決クライアント/etc/resolv.conf
フルリゾルバ(再帰リゾルバ)クライアントに代わって名前解決を実行8.8.8.8, 1.1.1.1, Unbound
権威DNSサーバーゾーンデータを管理・応答BIND, NSD, PowerDNS
ルートサーバーTLDサーバーへの参照を提供a.root-servers.net〜m.root-servers.net
TLDサーバーSLDサーバーへの参照を提供a.gtld-servers.net等
フォワーダーDNSクエリを上位サーバーに転送企業内DNSなど

1.5 ルートサーバー

DNSの最上位に位置する13のルートサーバーグループ。実際には、Anycastにより数百のノードが世界中に分散配置されている。

サーバー運用組織IPアドレス例
a.root-servers.netVerisign198.41.0.4
b.root-servers.netUSC-ISI199.9.14.201
c.root-servers.netCogent192.33.4.12
d.root-servers.netUniversity of Maryland199.7.91.13
e.root-servers.netNASA192.203.230.10
f.root-servers.netISC192.5.5.241
g.root-servers.netUS DoD192.112.36.4
h.root-servers.netUS Army198.97.190.53
i.root-servers.netNetnod192.36.148.17
j.root-servers.netVerisign192.58.128.30
k.root-servers.netRIPE NCC193.0.14.129
l.root-servers.netICANN199.7.83.42
m.root-servers.netWIDE Project202.12.27.33
# ルートサーバーへの直接問い合わせ
$ dig @a.root-servers.net . NS

# ルートヒントファイルの確認
$ cat /var/named/named.ca  # BIND
$ cat /etc/unbound/root.hints  # Unbound

第2章: DNS名前解決プロセス

2.1 再帰的問い合わせと反復的問い合わせ

再帰的問い合わせ(Recursive Query):
  クライアント → フルリゾルバ: 「www.example.comのIPは?」
  フルリゾルバが完全な回答を返す責任を持つ

反復的問い合わせ(Iterative Query):
  フルリゾルバ → 権威サーバー: 「www.example.comのIPは?」
  権威サーバーは知っている範囲で回答(参照情報を返す場合もある)

2.2 名前解決の完全なフロー

ユーザーがブラウザで www.example.com にアクセス

① アプリケーション → スタブリゾルバ
   getaddrinfo("www.example.com") を呼び出し

② スタブリゾルバ → ローカルキャッシュ確認
   /etc/hosts ファイル → NSS設定 → DNSリゾルバ

③ スタブリゾルバ → フルリゾルバ(再帰クエリ)
   「www.example.com の A レコードをください」

④ フルリゾルバ → キャッシュ確認
   キャッシュにあれば即座に応答

⑤ フルリゾルバ → ルートサーバー(反復クエリ)
   「www.example.com の A レコードをください」
   ルートサーバー: 「.com は a.gtld-servers.net に聞いてください」

⑥ フルリゾルバ → TLDサーバー(反復クエリ)
   「www.example.com の A レコードをください」
   TLDサーバー: 「example.com は ns1.example.com に聞いてください」

⑦ フルリゾルバ → 権威サーバー(反復クエリ)
   「www.example.com の A レコードをください」
   権威サーバー: 「www.example.com は 93.184.216.34 です」(権威応答)

⑧ フルリゾルバ → スタブリゾルバ
   応答をキャッシュに保存し、クライアントに返答

⑨ スタブリゾルバ → アプリケーション
   IPアドレスを返す
┌──────┐  ①  ┌──────────┐  ③  ┌────────────┐
│ブラウザ│───>│スタブリゾルバ│───>│フルリゾルバ   │
└──────┘  ⑨  └──────────┘  ⑧  └─────┬──────┘
                                     │
                          ⑤│    ⑥│    ⑦│
                           ▼     ▼     ▼
                     ┌─────┐ ┌───┐ ┌────┐
                     │ルート │ │TLD│ │権威 │
                     └─────┘ └───┘ └────┘

2.3 DNSメッセージフォーマット

+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    Header                        |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                   Question                       |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    Answer                        |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                   Authority                      |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                  Additional                      |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

ヘッダフォーマット:

                                1  1  1  1  1  1
  0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                      ID                          |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE     |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    QDCOUNT                        |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    ANCOUNT                        |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    NSCOUNT                        |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    ARCOUNT                        |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
フィールドビット数説明
ID16トランザクション識別子
QR10=クエリ, 1=応答
Opcode40=標準クエリ, 1=逆クエリ, 2=サーバーステータス
AA1権威応答(Authoritative Answer)
TC1切り詰め(Truncation) — UDP応答が512バイトを超えた場合
RD1再帰要求(Recursion Desired)
RA1再帰利用可能(Recursion Available)
RCODE4応答コード

主な応答コード(RCODE):

コード名称説明
0NOERROR正常
1FORMERRフォーマットエラー
2SERVFAILサーバーエラー
3NXDOMAINドメインが存在しない
4NOTIMP未実装
5REFUSED拒否

2.4 DNSトランスポート

プロトコルポート用途
UDP53通常のDNSクエリ(512バイト以下)
TCP53大きなレスポンス、ゾーン転送(AXFR/IXFR)
DoT(DNS over TLS)853暗号化されたDNSクエリ
DoH(DNS over HTTPS)443HTTPS上のDNSクエリ
DoQ(DNS over QUIC)853QUIC上のDNSクエリ
# UDP/TCPの切り替え
# 応答が512バイト(EDNS0では最大4096バイト)を超える場合、
# TC(Truncation)ビットが設定され、クライアントはTCPで再試行する

# EDNS0(Extension Mechanisms for DNS)
$ dig +bufsize=4096 www.example.com
# EDNS0はUDPの最大ペイロードサイズを拡張する

2.5 TTL(Time To Live)とキャッシュ

TTLは、DNSレコードがキャッシュに保持される時間(秒)を指定する。

TTLの設計指針:
  短いTTL(60〜300秒):
    ✅ 変更が迅速に反映される
    ✅ フェイルオーバーが速い
    ❌ DNSクエリ数が増加
    ❌ 権威サーバーへの負荷増大
    用途: CDN、ロードバランシング、フェイルオーバー

  長いTTL(3600〜86400秒):
    ✅ DNSクエリ数が減少
    ✅ 名前解決のレイテンシが低い
    ❌ 変更の反映が遅い
    用途: 安定したサービスのMXレコード、NSレコード
# TTLの確認
$ dig www.example.com
;; ANSWER SECTION:
www.example.com.    300    IN    A    93.184.216.34
#                   ^^^
#                   TTL = 300秒(5分)

# キャッシュのTTL減少を観察
$ dig www.example.com +noall +answer
www.example.com.    287    IN    A    93.184.216.34  # 13秒経過
$ dig www.example.com +noall +answer
www.example.com.    270    IN    A    93.184.216.34  # 30秒経過

2.6 ネガティブキャッシュ

存在しないドメイン(NXDOMAIN)の応答もキャッシュされる。ネガティブキャッシュのTTLはSOAレコードのMINIMUMフィールドで制御される。

# ネガティブキャッシュの確認
$ dig nonexistent.example.com
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, ...
;; AUTHORITY SECTION:
example.com.    86400    IN    SOA    ns1.example.com. admin.example.com. ...
#                                                          MINIMUM = 3600
# ネガティブキャッシュTTL = min(SOA TTL, SOA MINIMUM) = min(86400, 3600) = 3600秒

第3章: DNSレコードタイプ

3.1 主要なレコードタイプ一覧

タイプ説明RFC
A1IPv4アドレスRFC 1035
AAAA28IPv6アドレスRFC 3596
CNAME5正規名(別名)RFC 1035
MX15メール交換(メールサーバー)RFC 1035
NS2ネームサーバーRFC 1035
PTR12ポインタ(逆引き)RFC 1035
SOA6権威の開始(ゾーン情報)RFC 1035
TXT16テキスト情報RFC 1035
SRV33サービスロケータRFC 2782
CAA257CA認証(証明書発行制限)RFC 8659
DS43委譲署名者(DNSSEC)RFC 4034
DNSKEY48DNS鍵(DNSSEC)RFC 4034
RRSIG46リソースレコード署名(DNSSEC)RFC 4034
NSEC/NSEC347/50不在証明(DNSSEC)RFC 4034/5155
TLSA52TLS認証(DANE)RFC 6698
HTTPS65HTTPSサービスバインディングRFC 9460
SVCB64サービスバインディングRFC 9460

3.2 各レコードタイプの詳細

A レコード(IPv4アドレス)

; ドメインからIPv4アドレスへのマッピング
www.example.com.    300    IN    A    93.184.216.34
example.com.        300    IN    A    93.184.216.34

; 複数のAレコード(ラウンドロビンDNS)
www.example.com.    300    IN    A    10.0.0.1
www.example.com.    300    IN    A    10.0.0.2
www.example.com.    300    IN    A    10.0.0.3
# Aレコードの問い合わせ
$ dig www.example.com A +short
93.184.216.34

# 複数レコードの確認
$ dig www.google.com A +short
142.250.80.4

AAAA レコード(IPv6アドレス)

www.example.com.    300    IN    AAAA    2606:2800:220:1:248:1893:25c8:1946
# AAAAレコードの問い合わせ
$ dig www.example.com AAAA +short
2606:2800:220:1:248:1893:25c8:1946

CNAME レコード(正規名 / エイリアス)

; www.example.com は example.com のエイリアス
www.example.com.    300    IN    CNAME    example.com.

; CDN使用時の典型的な設定
cdn.example.com.    300    IN    CNAME    d1234.cloudfront.net.

CNAMEの制約:

  • CNAMEはそのドメインの唯一のレコードでなければならない
  • ゾーンの頂点(example.com)にはCNAMEを設定できない(MX, NS等と共存不可)
  • 代替: ALIAS/ANAME レコード(一部のDNSプロバイダが提供する独自拡張)

MX レコード(メールサーバー)

; 優先度の低い値が高優先
example.com.    3600    IN    MX    10    mail1.example.com.
example.com.    3600    IN    MX    20    mail2.example.com.
example.com.    3600    IN    MX    30    backup-mail.example.com.
# MXレコードの問い合わせ
$ dig example.com MX +short
10 mail1.example.com.
20 mail2.example.com.

NS レコード(ネームサーバー)

; ドメインの権威ネームサーバー
example.com.    86400    IN    NS    ns1.example.com.
example.com.    86400    IN    NS    ns2.example.com.

; グルーレコード(NSサーバーがゾーン内にある場合に必要)
ns1.example.com.    86400    IN    A    198.51.100.1
ns2.example.com.    86400    IN    A    198.51.100.2

SOA レコード(Start of Authority)

example.com.    86400    IN    SOA    ns1.example.com. admin.example.com. (
                    2024010101  ; シリアル番号(YYYYMMDDNN形式推奨)
                    3600        ; リフレッシュ間隔(1時間)
                    900         ; リトライ間隔(15分)
                    604800      ; 有効期限(7日)
                    3600        ; ネガティブキャッシュTTL(1時間)
)
フィールド説明推奨値
MNAMEプライマリネームサーバーns1.example.com.
RNAME管理者メールアドレス(@を.に置換)admin.example.com.
SERIALシリアル番号(変更ごとにインクリメント)YYYYMMDDNN
REFRESHセカンダリがプライマリに確認する間隔3600 (1h)
RETRYリフレッシュ失敗時のリトライ間隔900 (15m)
EXPIREセカンダリがゾーンデータを無効とする期限604800 (7d)
MINIMUMネガティブキャッシュのTTL3600 (1h)

TXT レコード

; SPF(Sender Policy Framework)
example.com.    300    IN    TXT    "v=spf1 mx ip4:198.51.100.0/24 include:_spf.google.com -all"

; DKIM(DomainKeys Identified Mail)
google._domainkey.example.com.    300    IN    TXT    "v=DKIM1; k=rsa; p=MIIBIj..."

; DMARC(Domain-based Message Authentication)
_dmarc.example.com.    300    IN    TXT    "v=DMARC1; p=reject; rua=mailto:dmarc@example.com"

; ドメイン検証
example.com.    300    IN    TXT    "google-site-verification=abc123..."
example.com.    300    IN    TXT    "MS=ms12345678"

SRV レコード(サービスロケータ)

; 書式: _service._protocol.name TTL class SRV priority weight port target
_sip._tcp.example.com.     300    IN    SRV    10    60    5060    sip1.example.com.
_sip._tcp.example.com.     300    IN    SRV    10    40    5060    sip2.example.com.
_ldap._tcp.example.com.    300    IN    SRV    0     0     389     ldap.example.com.
_kerberos._tcp.example.com. 300   IN    SRV    0     0     88      kdc.example.com.

CAA レコード(CA認証)

; Let's Encryptのみが証明書を発行可能
example.com.    3600    IN    CAA    0    issue    "letsencrypt.org"
example.com.    3600    IN    CAA    0    issuewild    "letsencrypt.org"
example.com.    3600    IN    CAA    0    iodef    "mailto:security@example.com"

PTR レコード(逆引き)

; IPv4逆引き
34.216.184.93.in-addr.arpa.    3600    IN    PTR    www.example.com.

; IPv6逆引き
6.4.9.1.8.c.5.2.3.9.8.1.8.4.2.0.1.0.0.0.0.2.2.0.0.0.8.2.6.0.6.2.ip6.arpa.    3600    IN    PTR    www.example.com.
# 逆引きの確認
$ dig -x 93.184.216.34 +short
$ host 93.184.216.34

HTTPS / SVCB レコード

; HTTPSレコード(RFC 9460)— ECH、ALPN、IPヒントなどを提供
example.com.    300    IN    HTTPS    1    .    alpn="h2,h3" ipv4hint=93.184.216.34 ech="..."

; AliasMode
example.com.    300    IN    HTTPS    0    cdn.example.net.
# HTTPSレコードの確認
$ dig example.com HTTPS

第4章: DNSゾーンとサーバー設定

4.1 ゾーンファイルの構造

; /etc/bind/zones/example.com.zone

$ORIGIN example.com.
$TTL 3600

; SOAレコード
@    IN    SOA    ns1.example.com. admin.example.com. (
            2024010101    ; Serial
            3600          ; Refresh (1h)
            900           ; Retry (15m)
            604800        ; Expire (7d)
            3600          ; Minimum TTL (1h)
)

; NSレコード
@        IN    NS    ns1.example.com.
@        IN    NS    ns2.example.com.

; Aレコード(ネームサーバー自身)
ns1      IN    A     198.51.100.1
ns2      IN    A     198.51.100.2

; Aレコード(Webサーバー)
@        IN    A     93.184.216.34
www      IN    A     93.184.216.34
www      IN    AAAA  2606:2800:220:1:248:1893:25c8:1946

; CNAMEレコード
cdn      IN    CNAME d1234.cloudfront.net.
blog     IN    CNAME example.ghost.io.

; MXレコード
@        IN    MX    10    mail1.example.com.
@        IN    MX    20    mail2.example.com.
mail1    IN    A     198.51.100.10
mail2    IN    A     198.51.100.11

; TXTレコード
@        IN    TXT   "v=spf1 mx ip4:198.51.100.0/24 -all"
_dmarc   IN    TXT   "v=DMARC1; p=reject; rua=mailto:dmarc@example.com"

; SRVレコード
_sip._tcp    IN    SRV    10 60 5060 sip.example.com.

; CAAレコード
@        IN    CAA   0 issue "letsencrypt.org"

4.2 BIND(Berkeley Internet Name Domain)の設定

# /etc/named.conf(BIND 9の主要設定)

options {
    directory "/var/named";
    listen-on port 53 { 127.0.0.1; 198.51.100.1; };
    listen-on-v6 port 53 { ::1; };
    
    allow-query { any; };
    allow-recursion { 10.0.0.0/8; 172.16.0.0/12; 192.168.0.0/16; };
    
    recursion yes;
    
    dnssec-validation auto;
    
    forwarders {
        8.8.8.8;
        8.8.4.4;
    };
    
    rate-limit {
        responses-per-second 10;
        window 5;
    };
    
    version "not disclosed";
};

zone "example.com" IN {
    type master;
    file "zones/example.com.zone";
    allow-transfer { 198.51.100.2; };  # セカンダリサーバーへの転送許可
    also-notify { 198.51.100.2; };
};

zone "100.51.198.in-addr.arpa" IN {
    type master;
    file "zones/198.51.100.rev";
};

4.3 Unbound(リカーシブリゾルバ)の設定

# /etc/unbound/unbound.conf

server:
    interface: 0.0.0.0
    port: 53
    
    access-control: 10.0.0.0/8 allow
    access-control: 172.16.0.0/12 allow
    access-control: 192.168.0.0/16 allow
    access-control: 127.0.0.0/8 allow
    
    # パフォーマンス設定
    num-threads: 4
    msg-cache-size: 128m
    rrset-cache-size: 256m
    key-cache-size: 64m
    neg-cache-size: 16m
    
    # キャッシュ設定
    cache-min-ttl: 60
    cache-max-ttl: 86400
    prefetch: yes          # TTL切れ前にプリフェッチ
    prefetch-key: yes
    serve-expired: yes     # TTL切れのキャッシュを一時的に提供
    serve-expired-ttl: 86400
    
    # DNSSEC
    auto-trust-anchor-file: "/var/lib/unbound/root.key"
    val-clean-additional: yes
    
    # プライバシー
    hide-identity: yes
    hide-version: yes
    qname-minimisation: yes  # QNAME最小化(プライバシー保護)
    
    # セキュリティ
    harden-glue: yes
    harden-dnssec-stripped: yes
    harden-below-nxdomain: yes
    use-caps-for-id: yes    # 0x20エンコーディング
    
    # ログ
    verbosity: 1
    log-queries: no
    log-replies: no

# フォワード設定(DoT使用)
forward-zone:
    name: "."
    forward-tls-upstream: yes
    forward-addr: 1.1.1.1@853#cloudflare-dns.com
    forward-addr: 1.0.0.1@853#cloudflare-dns.com
    forward-addr: 8.8.8.8@853#dns.google
    forward-addr: 8.8.4.4@853#dns.google

# ローカルゾーン(内部DNS)
local-zone: "internal.example.com." static
local-data: "app.internal.example.com. 300 IN A 10.0.1.100"
local-data: "db.internal.example.com. 300 IN A 10.0.2.100"

4.4 CoreDNS(Kubernetes向け)

# /etc/coredns/Corefile

.:53 {
    errors
    health {
        lameduck 5s
    }
    ready
    
    # Kubernetesクラスタ内の名前解決
    kubernetes cluster.local in-addr.arpa ip6.arpa {
        pods insecure
        fallthrough in-addr.arpa ip6.arpa
        ttl 30
    }
    
    # 外部ドメインの解決
    forward . /etc/resolv.conf {
        max_concurrent 1000
    }
    
    # キャッシュ
    cache 30
    
    # ループ検出
    loop
    
    # リロード設定
    reload
    
    # ログ
    log
    
    # Prometheusメトリクス
    prometheus :9153
}

4.5 ゾーン転送

AXFR(完全ゾーン転送)

プライマリサーバーからセカンダリサーバーへゾーンデータ全体を転送する。

# AXFRのテスト
$ dig @ns1.example.com example.com AXFR

# BINDでのAXFR許可設定
# zone "example.com" {
#     type master;
#     allow-transfer { 198.51.100.2; };
# };

IXFR(差分ゾーン転送)

変更された差分のみを転送する。シリアル番号の差分に基づく。

# IXFRのテスト
$ dig @ns1.example.com example.com IXFR=2024010100

NOTIFY

プライマリサーバーがゾーン変更をセカンダリに通知するメカニズム。

# BINDでのNOTIFY設定
# zone "example.com" {
#     type master;
#     also-notify { 198.51.100.2; };
#     notify yes;
# };

4.6 動的DNS更新(Dynamic DNS / DDNS)

# nsupdate を使用した動的更新
$ nsupdate -k /etc/bind/keys/update.key <<EOF
server ns1.example.com
zone example.com
update delete test.example.com A
update add test.example.com 300 A 10.0.0.100
send
EOF

# BINDでの動的更新許可
# zone "example.com" {
#     type master;
#     allow-update { key "update-key"; };
# };

第5章: DNSセキュリティ

5.1 DNSに対する主な脅威

攻撃説明対策
DNSキャッシュポイズニング偽のDNS応答をキャッシュに注入DNSSEC, ソースポートランダム化
DNSスプーフィングDNS応答を偽装DNSSEC
DNS増幅攻撃(DDoS)DNSを使用したDDoSリフレクション攻撃RRL, BCP38
DNSトンネリングDNSクエリを使用したデータ窃取クエリ分析, ファイアウォール
DNSハイジャックドメインの不正な移管・設定変更レジストリロック, DNSSEC
NXDOMAINハイジャック不在ドメインの応答を改ざんDNSSEC
ドメインシャドウイング正規ドメインにサブドメインを不正作成アカウント保護, モニタリング

5.2 DNSSEC(DNS Security Extensions)

DNSSECは、DNS応答にデジタル署名を付加し、応答の真正性と完全性を検証する仕組み。

DNSSECの信頼チェーン:

ルートゾーン (.)
  │  DNSKEY(KSK + ZSK)
  │  DS(.comのKSKのハッシュ)
  ▼
.comゾーン
  │  DNSKEY(KSK + ZSK)
  │  DS(example.comのKSKのハッシュ)
  ▼
example.comゾーン
  │  DNSKEY(KSK + ZSK)
  │  RRSIG(各レコードの署名)
  ▼
www.example.com A 93.184.216.34 + RRSIG

DNSSEC関連のレコードタイプ:

レコード説明
DNSKEYゾーンの公開鍵(KSK: 鍵署名鍵、ZSK: ゾーン署名鍵)
RRSIGリソースレコードセットの署名
DS子ゾーンのKSKのハッシュ(親ゾーンに配置)
NSEC/NSEC3不在証明(ドメインが存在しないことの証明)
# DNSSECの検証
$ dig +dnssec www.example.com
# ADフラグ(Authenticated Data)が設定されていればDNSSEC検証済み

# DNSSEC検証の詳細
$ dig +dnssec +cd www.example.com  # CDフラグで検証をスキップ
$ delv www.example.com  # DNSSEC検証ツール

# DNSSECチェーンの確認
$ dig +trace +dnssec www.example.com

# DS レコードの確認
$ dig example.com DS +short

DNSSEC鍵の管理

# KSK(鍵署名鍵)の生成
$ dnssec-keygen -a ECDSAP256SHA256 -f KSK example.com

# ZSK(ゾーン署名鍵)の生成
$ dnssec-keygen -a ECDSAP256SHA256 example.com

# ゾーンの署名
$ dnssec-signzone -A -3 $(head -c 1000 /dev/urandom | sha1sum | cut -b 1-16) \
    -N INCREMENT -o example.com -t example.com.zone

# 鍵のローテーション
# ZSK: 30〜90日ごとにローテーション推奨
# KSK: 1〜2年ごとにローテーション推奨

5.3 DNS over TLS(DoT)

DNSクエリをTLSで暗号化して送信する。ポート853を使用。

# DoTでの問い合わせ(kdigを使用)
$ kdig -d @1.1.1.1 +tls-ca +tls-host=cloudflare-dns.com www.example.com

# systemd-resolvedでのDoT設定
# /etc/systemd/resolved.conf
# [Resolve]
# DNS=1.1.1.1#cloudflare-dns.com 1.0.0.1#cloudflare-dns.com
# DNSOverTLS=yes

# UnboundでのDoTフォワード設定
# forward-zone:
#     name: "."
#     forward-tls-upstream: yes
#     forward-addr: 1.1.1.1@853#cloudflare-dns.com

5.4 DNS over HTTPS(DoH)

DNSクエリをHTTPS上で送信する。ポート443を使用し、通常のHTTPSトラフィックと区別がつかない。

# DoHでの問い合わせ(curlを使用)
$ curl -H "accept: application/dns-json" \
    "https://cloudflare-dns.com/dns-query?name=www.example.com&type=A"

# DoHでの問い合わせ(ワイヤーフォーマット)
$ curl -s -H "content-type: application/dns-message" \
    "https://cloudflare-dns.com/dns-query" \
    --data-binary @query.bin | python3 -c "import sys; ..."

主要なDoHプロバイダ:

プロバイダURL
Cloudflarehttps://cloudflare-dns.com/dns-query
Googlehttps://dns.google/dns-query
Quad9https://dns.quad9.net/dns-query

5.5 DNS増幅攻撃の対策

# レスポンスレート制限(RRL)— BINDの設定
# options {
#     rate-limit {
#         responses-per-second 10;
#         window 5;
#         slip 2;
#     };
# };

# オープンリゾルバの確認
$ dig @your-server.com example.com +short
# 外部から応答が返る場合、オープンリゾルバの可能性

# アクセス制御
# allow-recursion { 内部ネットワーク; };
# allow-query-cache { 内部ネットワーク; };

5.6 RPZ(Response Policy Zone)

DNSベースのセキュリティフィルタリング。マルウェアサイトやフィッシングサイトへのアクセスをDNSレベルでブロックする。

# BINDでのRPZ設定
# zone "rpz.example.com" {
#     type master;
#     file "rpz.example.com.zone";
# };
# options {
#     response-policy { zone "rpz.example.com"; };
# };

# RPZゾーンファイル
# malware.example.com    CNAME .         ; NXDOMAINを返す
# phishing.example.com   CNAME .         ; NXDOMAINを返す
# *.bad-site.com         CNAME rpz-passthru. ; 特定のサブドメインを許可

第6章: DNS運用とパフォーマンス

6.1 Anycast DNS

同じIPアドレスを複数の地理的に分散したサーバーに割り当て、BGPルーティングにより最も近いサーバーに自動的にルーティングする技術。

利点:
  - 低レイテンシ(最寄りのサーバーに接続)
  - DDoS耐性(トラフィックが分散)
  - 高可用性(1台が停止しても他がサービス継続)

主要なAnycast DNSプロバイダ:
  - Cloudflare DNS (1.1.1.1)
  - Google Public DNS (8.8.8.8)
  - Amazon Route 53
  - NS1

6.2 GeoDNS(地理的DNS)

クライアントのIPアドレスの地理情報に基づいて異なる応答を返す。CDNで広く使用。

# PowerDNSのGeoIP設定例
# geoip-database-files=/usr/share/GeoIP/GeoLite2-Country.mmdb
# 
# zones:
#   example.com:
#     www:
#       geo:
#         JP: 10.0.1.1   # 日本のユーザー
#         US: 10.0.2.1   # 米国のユーザー
#         default: 10.0.3.1

6.3 DNSロードバランシング

方式1: ラウンドロビンDNS
  www.example.com.    300    IN    A    10.0.0.1
  www.example.com.    300    IN    A    10.0.0.2
  www.example.com.    300    IN    A    10.0.0.3
  → クライアントに返されるIPの順序がランダム化される

方式2: 重み付きDNS(AWS Route 53など)
  www.example.com.    300    IN    A    10.0.0.1    ; Weight: 70
  www.example.com.    300    IN    A    10.0.0.2    ; Weight: 30

方式3: ヘルスチェック付きDNS
  → 死活監視と連動し、障害サーバーを応答から除外

方式4: レイテンシベースルーティング
  → クライアントに最も近いリージョンのIPを返す

6.4 DNSフェイルオーバー

フェイルオーバー設定(AWS Route 53の例):
  プライマリ: www.example.com → 10.0.0.1 (ヘルスチェック: HTTP /health)
  セカンダリ: www.example.com → 10.0.0.2 (フェイルオーバー先)

  プライマリがヘルスチェック失敗
  → Route 53が自動的にセカンダリのIPを返す
  → TTL短縮(60秒など)で迅速なフェイルオーバー

6.5 プリフェッチとキャッシュ最適化

# Unboundのプリフェッチ設定
server:
    prefetch: yes
    # TTLの90%経過時に、次のクエリをトリガーとしてバックグラウンドで
    # 権威サーバーに問い合わせ、キャッシュを更新する
    
    prefetch-key: yes
    # DNSSEC鍵もプリフェッチ
    
    serve-expired: yes
    # TTL切れのキャッシュを一時的に提供しつつ、バックグラウンドで更新
    serve-expired-ttl: 86400
    
    # キャッシュサイズ
    msg-cache-size: 128m
    rrset-cache-size: 256m

第7章: DNSトラブルシューティング

7.1 dig(Domain Information Groper)

# 基本的な問い合わせ
$ dig www.example.com

# 特定のレコードタイプ
$ dig www.example.com A
$ dig www.example.com AAAA
$ dig example.com MX
$ dig example.com TXT
$ dig example.com NS
$ dig example.com SOA

# 簡潔な出力
$ dig www.example.com +short
93.184.216.34

# 特定のDNSサーバーに問い合わせ
$ dig @8.8.8.8 www.example.com
$ dig @ns1.example.com www.example.com

# トレース(ルートからの完全な解決パスを表示)
$ dig +trace www.example.com

# 逆引き
$ dig -x 93.184.216.34

# DNSSECの確認
$ dig +dnssec www.example.com

# TCPでの問い合わせ
$ dig +tcp www.example.com

# すべてのレコードタイプ
$ dig example.com ANY

# 詳細出力
$ dig +noall +answer +authority +additional www.example.com

# バッチ処理
$ dig -f domains.txt +short

# 応答時間の確認
$ dig www.example.com | grep "Query time"
;; Query time: 12 msec

7.2 nslookup

# 基本的な問い合わせ
$ nslookup www.example.com

# 特定のDNSサーバーを指定
$ nslookup www.example.com 8.8.8.8

# レコードタイプの指定
$ nslookup -type=MX example.com
$ nslookup -type=TXT example.com
$ nslookup -type=NS example.com

# 逆引き
$ nslookup 93.184.216.34

7.3 host

# 基本的な問い合わせ
$ host www.example.com
www.example.com has address 93.184.216.34

# 逆引き
$ host 93.184.216.34

# 特定のレコードタイプ
$ host -t MX example.com
$ host -t NS example.com

# 詳細出力
$ host -v www.example.com

7.4 一般的な問題と対処法

SERVFAIL

# 原因の調査
$ dig www.example.com +trace
# DNSSEC検証エラーの可能性
$ dig www.example.com +dnssec +cd  # CD(Checking Disabled)フラグで検証をスキップ
# CDフラグで成功する場合はDNSSEC関連の問題

# 権威サーバーの確認
$ dig @ns1.example.com www.example.com

NXDOMAIN(ドメインが存在しない)

# ドメインの存在確認
$ dig example.com NS
# NSレコードが返ればドメインは存在する

# タイプミスの確認
$ dig wwww.example.com  # typo

# ゾーン設定の確認
$ dig @ns1.example.com www.example.com

名前解決が遅い

# 応答時間の確認
$ dig www.example.com | grep "Query time"

# キャッシュの確認(2回目は高速なはず)
$ dig www.example.com  # 1回目: 50ms
$ dig www.example.com  # 2回目: 0ms(キャッシュ)

# DNSサーバーの応答確認
$ dig @8.8.8.8 www.example.com | grep "Query time"
$ dig @1.1.1.1 www.example.com | grep "Query time"

# ネットワーク到達性の確認
$ ping 8.8.8.8
$ traceroute 8.8.8.8

DNSの伝播確認

# 複数のDNSサーバーでの確認
$ for ns in 8.8.8.8 1.1.1.1 9.9.9.9; do
    echo "=== $ns ==="
    dig @$ns www.example.com +short
done

# 権威サーバー全体での確認
$ dig example.com NS +short | while read ns; do
    echo "=== $ns ==="
    dig @$ns www.example.com +short
done

7.5 クライアント側の設定

# /etc/resolv.conf
nameserver 8.8.8.8
nameserver 8.8.4.4
nameserver 1.1.1.1
options timeout:2 attempts:3 rotate

# /etc/hosts(ローカルオーバーライド)
127.0.0.1    localhost
10.0.0.100   app.internal.example.com    app

# /etc/nsswitch.conf(名前解決の順序)
hosts:    files dns myhostname
# files: /etc/hosts を先に確認
# dns: DNSリゾルバに問い合わせ

# macOS
$ scutil --dns  # DNS設定の確認
$ dscacheutil -flushcache  # DNSキャッシュのクリア
$ sudo killall -HUP mDNSResponder

# Linux (systemd-resolved)
$ resolvectl status  # DNS設定の確認
$ resolvectl flush-caches  # キャッシュクリア
$ resolvectl statistics  # キャッシュ統計

# Windows
> ipconfig /displaydns  # DNSキャッシュの表示
> ipconfig /flushdns    # DNSキャッシュのクリア

第8章: 実践シナリオとベストプラクティス

8.1 メールセキュリティのDNS設定

; SPF — 送信元メールサーバーの認証
example.com.    300    IN    TXT    "v=spf1 mx ip4:198.51.100.0/24 include:_spf.google.com -all"

; 説明:
;   mx: ドメインのMXレコードのサーバーからの送信を許可
;   ip4:198.51.100.0/24: このIPレンジからの送信を許可
;   include:_spf.google.com: Google Workspaceの送信サーバーを許可
;   -all: 上記以外はすべて拒否

; DKIM — メールの電子署名
selector1._domainkey.example.com. 300 IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqh..."

; DMARC — SPFとDKIMのポリシー統合
_dmarc.example.com. 300 IN TXT "v=DMARC1; p=reject; sp=reject; rua=mailto:dmarc-reports@example.com; ruf=mailto:dmarc-forensic@example.com; pct=100"

; MTA-STS — メールのTLS強制
_mta-sts.example.com. 300 IN TXT "v=STSv1; id=20240101"

; TLSRPT — TLSレポート
_smtp._tls.example.com. 300 IN TXT "v=TLSRPTv1; rua=mailto:tls-reports@example.com"

8.2 Kubernetes環境のDNS

# CoreDNSのConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: coredns
  namespace: kube-system
data:
  Corefile: |
    .:53 {
        errors
        health {
            lameduck 5s
        }
        ready
        kubernetes cluster.local in-addr.arpa ip6.arpa {
            pods insecure
            fallthrough in-addr.arpa ip6.arpa
            ttl 30
        }
        prometheus :9153
        forward . /etc/resolv.conf {
            max_concurrent 1000
        }
        cache 30
        loop
        reload
        loadbalance
    }
# Kubernetes内のDNS確認
$ kubectl run -it --rm debug --image=busybox -- nslookup kubernetes.default
$ kubectl run -it --rm debug --image=busybox -- nslookup my-service.my-namespace.svc.cluster.local

# Pod内のDNS設定
$ kubectl exec -it my-pod -- cat /etc/resolv.conf
# nameserver 10.96.0.10
# search my-namespace.svc.cluster.local svc.cluster.local cluster.local
# options ndots:5

8.3 CDN統合のDNS設定

; CloudFrontとの統合
cdn.example.com.    300    IN    CNAME    d123456.cloudfront.net.

; Cloudflareとの統合(プロキシモード)
www.example.com.    300    IN    A    104.16.132.229    ; Cloudflare Anycast IP

; AWS Route 53 エイリアスレコード(ALB向け)
; example.com → my-alb-123456.us-east-1.elb.amazonaws.com
; Route 53のALIASレコードはゾーン頂点でも使用可能(CNAMEの代替)

第9章: DNSの最新動向

9.1 DNS over QUIC(DoQ)

QUICプロトコル上でDNSクエリを実行する。DoTの低レイテンシ版として期待されている。

9.2 Oblivious DNS over HTTPS(ODoH)

プロキシを経由してDoHを実行し、DNSサーバーがクライアントのIPアドレスを知ることを防ぐ。

9.3 DDR(Discovery of Designated Resolvers)

暗号化DNS(DoT/DoH)のリゾルバを自動的に発見するメカニズム(RFC 9462)。

9.4 SVCB/HTTPS レコード

サービスの接続パラメータ(ALPN、ECH鍵、IPヒント)をDNSで提供する新しいレコードタイプ(RFC 9460)。


まとめ

DNSはインターネットの基盤であり、その理解はすべてのエンジニアに不可欠である。本記事の要点:

  1. 基本概念: 階層構造、ルートサーバー、TLD、再帰/反復クエリ
  2. 名前解決プロセス: スタブリゾルバ → フルリゾルバ → 権威サーバーの連携
  3. レコードタイプ: A/AAAA、CNAME、MX、NS、SOA、TXT、SRV、CAA、HTTPS
  4. サーバー設定: BIND、Unbound、CoreDNS、ゾーンファイル
  5. セキュリティ: DNSSEC、DoT/DoH、RPZ、キャッシュポイズニング対策
  6. 運用: Anycast、GeoDNS、ロードバランシング、フェイルオーバー
  7. トラブルシューティング: dig、nslookup、一般的な問題と対処
  8. 実践: メールセキュリティ(SPF/DKIM/DMARC)、Kubernetes DNS、CDN統合
  9. 最新動向: DoQ、ODoH、DDR、SVCB/HTTPSレコード

参考文献

  • RFC 1034 - Domain Names - Concepts and Facilities (1987)
  • RFC 1035 - Domain Names - Implementation and Specification (1987)
  • RFC 2782 - A DNS RR for specifying the location of services (SRV) (2000)
  • RFC 4034 - Resource Records for the DNS Security Extensions (2005)
  • RFC 4035 - Protocol Modifications for the DNS Security Extensions (2005)
  • RFC 6698 - The DNS-Based Authentication of Named Entities (DANE) (2012)
  • RFC 7858 - Specification for DNS over Transport Layer Security (DoT) (2016)
  • RFC 8484 - DNS Queries over HTTPS (DoH) (2018)
  • RFC 8659 - DNS Certification Authority Authorization (CAA) (2019)
  • RFC 9460 - Service Binding and Parameter Specification via the DNS (2023)
  • "DNS and BIND" - Cricket Liu, Paul Albitz (O'Reilly)
  • "Pro DNS and BIND 10" - Ron Aitchison (Apress)
  • IANA Root Zone Database: https://www.iana.org/domains/root/db
  • Root Servers: https://root-servers.org/