DNSレコードの種類と用途
A・AAAA・CNAME・MX・TXT・SRVの値を用途に沿ってたどります。
説明
DNSにはIPアドレス以外の情報も登録できます。別名、メール配送先、文字列、サービスのポートでは、返る値の型も、その後に必要な参照も違います。
一つのゾーンを名前と型で検索し、CNAMEからA、MXから配送先アドレス、SRVからポートとホストをたどります。TXTは、その文字列を使う側の仕様で意味が決まることも確認します。
1名前と型で取得する情報が変わる
zone.jsonはこの演習のゾーンデータです。app.example.testのAとAAAAを取得します。
python3 -c名前と型でゾーンを参照 'import json; z=json.load(open("zone.json")); print(z["app.example.test"]["A"]); print(z["app.example.test"]["AAAA"])'IPv4とIPv6のレコードAはIPv4、AAAAはIPv6です。同じ名前でもレコード型によって値の形式と用途が異なります。DNSの問い合わせを「名前に対して一つのIPが返るだけ」と考えると、他の型の応答を読み違えます。
2別名の参照先をたどる
www.example.testはCNAMEでapp.example.testを参照しています。
python3 -cCNAMEからAを参照 'import json; z=json.load(open("zone.json")); target=z["www.example.test"]["CNAME"][0]; print(target,z[target]["A"])'別名の行き先CNAMEの値はIPではなく正規名です。その参照先のAを取得して192.0.2.80へ進みます。通常、CNAMEの所有者名にAやMX等の他データを同居させることはできず、別名と実データの配置を分けます。
3メール配送先の優先順位
example.testのMXを優先値順に並べます。
python3 -cMXを優先値順に表示 'import json; z=json.load(open("zone.json")); print(sorted(z["example.test"]["MX"]))'メール配送先の候補10のmail1を20のmail2より優先します。MXの値は配送先ホスト名と優先値で、メールボックスのアドレスやWebサーバーのIPを示すものではありません。小さい数の優先度が高い点を確認します。
4MXのホスト名をIPへ解決する
配送先ホスト名のAを取得します。このゾーンでは二候補ともIPv4を持ちます。
python3 -c配送先名からAを取得 'import json; z=json.load(open("zone.json")); print([(priority,host,z[host]["A"]) for priority,host in sorted(z["example.test"]["MX"])])'MXとアドレスの対応mail1は192.0.2.81、mail2は192.0.2.82です。MX取得と配送先アドレス取得は別の参照で、その後にSMTP接続が必要です。DNSの取得成功だけでメールを届け終わったとは判断できません。
5TXTの文字列の意味
TXTに保存した所有確認用の文字列を取得します。
python3 -cTXTの値を取得 'import json; z=json.load(open("zone.json")); print(z["example.test"]["TXT"])'アプリケーションが解釈する文字列ownership=lab-42はこの例の用途を定めた側が解釈する文字列です。TXTという型だけでSPFや所有確認など一つの用途に決まるわけではなく、名前と内容、利用する仕様を確認します。
6SRVのポートとホスト
_ldap._tcp.example.testのSRVを読みます。値はpriority、weight、port、targetの順です。
python3 -cSRVの四項目とAを取得 'import json; z=json.load(open("zone.json")); priority,weight,port,target=z["_ldap._tcp.example.test"]["SRV"][0]; print(priority,weight,port,target,z[target]["A"])'サービスの接続先priority0、weight10、TCP389、ldap.example.testで、IPは192.0.2.83です。SRVを利用するクライアントはサービスのポートも取得できます。weightは同じpriorityの候補間の選択に使い、MXの優先値や単純な大きい順とは別の意味です。
まとめ
返された値を、IP・ホスト名・優先値・ポート・文字列として読み分けます。
別名や配送先のレコードから、次に必要なアドレス参照へ進みます。
操作履歴と解説を振り返れます。
シェル / PCAPと通信の記録
python3 -c 'import json; z=json.load(open("zone.json")); print(z["app.example.test"]["A"]); print(z["app.example.test"]["AAAA"])'['192.0.2.80'] ['2001:db8::80']
python3 -c 'import json; z=json.load(open("zone.json")); target=z["www.example.test"]["CNAME"][0]; print(target,z[target]["A"])'app.example.test ['192.0.2.80']
python3 -c 'import json; z=json.load(open("zone.json")); print(sorted(z["example.test"]["MX"]))'[[10, 'mail1.example.test'], [20, 'mail2.example.test']]
python3 -c 'import json; z=json.load(open("zone.json")); print([(priority,host,z[host]["A"]) for priority,host in sorted(z["example.test"]["MX"])])'[(10, 'mail1.example.test', ['192.0.2.81']), (20, 'mail2.example.test', ['192.0.2.82'])]
python3 -c 'import json; z=json.load(open("zone.json")); print(z["example.test"]["TXT"])'['ownership=lab-42']
python3 -c 'import json; z=json.load(open("zone.json")); priority,weight,port,target=z["_ldap._tcp.example.test"]["SRV"][0]; print(priority,weight,port,target,z[target]["A"])'0 10 389 ldap.example.test ['192.0.2.83']
演習完了