[インデックス 14171] ファイルの概要
このコミットは、Go言語の標準ライブラリである net
パッケージに、DNSのネームサーバー (NS) レコードをルックアップするための新しい関数 LookupNS(domain string)
を追加するものです。これにより、指定されたドメイン名に関連付けられたネームサーバー情報をプログラムから取得できるようになります。
コミット
commit a5b0c67d5f7d7957ee5fae8a2980f621d95ab719
Author: Stephen McQuay <stephen@mcquay.me>
Date: Thu Oct 18 15:39:04 2012 +0900
net: add LookupNS(domain string)
Fixes #4224.
R=golang-dev, dave, minux.ma, mikioh.mikioh, alex.brainman, rsc, herbert.fischer
CC=golang-dev
https://golang.org/cl/6675043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/a5b0c67d5f7d7957ee5fae8a2980f621d95ab719
元コミット内容
net: add LookupNS(domain string)
Fixes #4224.
このコミットは、Go言語の net
パッケージに LookupNS
関数を追加します。これは、Issue #4224 を修正するためのものです。
変更の背景
この変更の背景には、Go言語の net
パッケージが提供するDNSルックアップ機能の拡充があります。既存の net
パッケージには、Aレコード (IPアドレス)、MXレコード (メールエクスチェンジャー)、TXTレコード (テキスト情報) などのルックアップ機能は存在していましたが、ネームサーバー (NS) レコードを直接ルックアップする機能が欠けていました。
Issue #4224 は、この欠如を指摘し、NSレコードのルックアップ機能の必要性を提起したものです。NSレコードは、ドメインのDNSゾーン情報を管理する権威ネームサーバーを特定するために不可欠な情報であり、ドメインの委任関係を追跡したり、特定のドメインのDNS設定を検証したりする際に利用されます。
このコミットは、この不足を解消し、GoプログラムからNSレコード情報を簡単に取得できるようにすることで、ネットワーク関連のアプリケーション開発における柔軟性と機能性を向上させることを目的としています。
前提知識の解説
DNS (Domain Name System)
DNSは、インターネット上のコンピュータやサービスを識別するための階層的な分散型命名システムです。人間が覚えやすいドメイン名 (例: example.com
) を、コンピュータが理解できるIPアドレス (例: 192.0.2.1
) に変換する役割を担っています。
DNSレコードタイプ
DNSには様々なレコードタイプがあり、それぞれ異なる種類の情報を提供します。
- Aレコード (Address Record): ホスト名とIPv4アドレスのマッピング。
- AAAAレコード (IPv6 Address Record): ホスト名とIPv6アドレスのマッピング。
- MXレコード (Mail Exchange Record): ドメインのメールサーバーを指定。
- TXTレコード (Text Record): ドメインに関連付けられた任意のテキスト情報。SPF (Sender Policy Framework) や DKIM (DomainKeys Identified Mail) などで利用されます。
- NSレコード (Name Server Record): ドメインの権威ネームサーバーを指定します。あるドメインのDNS情報をどこで管理しているかを示す重要なレコードです。例えば、
example.com
のNSレコードは、ns1.example.com
やns2.example.com
のようなネームサーバーを指し、これらのネームサーバーがexample.com
のAレコードやMXレコードなどの詳細な情報を持っています。
Go言語の net
パッケージ
Go言語の net
パッケージは、ネットワークI/Oプリミティブを提供します。これには、TCP/IP、UDP、IP、Unixドメインソケットなどのネットワークプロトコルを扱うための機能や、DNSルックアップ機能が含まれます。net
パッケージは、クロスプラットフォームで動作するように設計されており、各OSのネイティブなDNS解決メカニズムを抽象化して提供します。
プラットフォームごとのDNS解決
DNS解決の具体的な実装は、オペレーティングシステムによって異なります。
- Unix系 (Linux, macOSなど): 通常、
/etc/resolv.conf
に設定されたDNSサーバーを利用し、Cライブラリのgetaddrinfo
やres_query
などの関数を通じてDNSクエリを実行します。 - Plan9: Plan9は独自のネットワークスタックとDNS解決メカニズムを持っています。
queryDNS
のような内部関数を通じてDNSクエリを実行します。 - Windows: Windowsは、
DnsQuery
などのWin32 API関数を使用してDNSクエリを実行します。
このコミットでは、これらのプラットフォームごとの違いを吸収し、統一された LookupNS
インターフェースを提供するために、各プラットフォーム向けの lookupNS
実装が追加されています。
技術的詳細
このコミットは、Go言語の net
パッケージにNSレコードのルックアップ機能を追加するために、以下の主要な変更を導入しています。
-
NS
構造体の定義:src/pkg/net/dnsclient.go
に、DNS NSレコードを表す新しい構造体NS
が定義されました。type NS struct { Host string }
この構造体は、ネームサーバーのホスト名 (
Host
) を保持します。 -
LookupNS
関数の追加:src/pkg/net/lookup.go
に、公開APIとしてLookupNS
関数が追加されました。func LookupNS(name string) (ns []*NS, err error) { return lookupNS(name) }
この関数は、指定されたドメイン名 (
name
) のNSレコードをルックアップし、NS
構造体のスライスとエラーを返します。実際のルックアップ処理は、内部関数lookupNS
に委譲されます。 -
プラットフォームごとの
lookupNS
実装:lookupNS
関数は、Goのビルドタグ (_plan9
,_unix
,_windows
) を利用して、各オペレーティングシステムに特化した実装が提供されます。-
src/pkg/net/lookup_plan9.go
: Plan9システム向けのlookupNS
実装が追加されました。これは、内部のqueryDNS
関数を使用してDNSクエリを実行し、結果をパースしてNS
構造体のスライスを生成します。 -
src/pkg/net/lookup_unix.go
: Unix系システム向けのlookupNS
実装が追加されました。これは、既存のlookup
関数とdnsTypeNS
を利用してNSレコードをクエリし、結果をdnsRR_NS
型にキャストしてNS
構造体に変換します。 -
src/pkg/net/lookup_windows.go
: Windowsシステム向けのlookupNS
実装が追加されました。これは、Windows APIのsyscall.DnsQuery
関数をDNS_TYPE_NS
タイプで呼び出し、返されたDNSレコードリストを処理してNS
構造体のスライスを構築します。特に、syscall.UTF16ToString
を使用してUTF-16エンコードされたホスト名をGoの文字列に変換する処理が含まれています。
-
-
テストケースの追加:
src/pkg/net/lookup_test.go
に、LookupNS
関数の動作を検証するためのテストケースTestGmailNS
が追加されました。このテストは、gmail.com
のNSレコードをルックアップし、結果が空でないことを確認します。testing.Short()
と*testExternal
フラグを使用して、外部ネットワークへのアクセスを伴うテストの実行を制御しています。
これらの変更により、Goの net
パッケージは、クロスプラットフォームでNSレコードのルックアップをサポートするようになり、開発者はOSの違いを意識することなくNSレコード情報を取得できるようになりました。
コアとなるコードの変更箇所
このコミットで変更された主要なファイルと、その変更の概要は以下の通りです。
-
src/pkg/net/dnsclient.go
:NS
構造体が新しく定義されました。これは、DNS NSレコードのホスト名を保持します。
-
src/pkg/net/lookup.go
:LookupNS(name string)
関数が追加されました。これは、外部から呼び出されるNSレコードルックアップの公開インターフェースです。内部的にはプラットフォーム固有のlookupNS
関数を呼び出します。
-
src/pkg/net/lookup_plan9.go
:- Plan9環境向けの
lookupNS
関数が実装されました。queryDNS
を使用してNSレコードを問い合わせ、結果をパースします。
- Plan9環境向けの
-
src/pkg/net/lookup_test.go
:TestGmailNS
という新しいテスト関数が追加されました。これは、LookupNS
関数が正しく動作するかどうかを検証するために、gmail.com
のNSレコードをルックアップします。
-
src/pkg/net/lookup_unix.go
:- Unix系環境向けの
lookupNS
関数が実装されました。既存のlookup
関数とdnsTypeNS
を利用してNSレコードを取得します。
- Unix系環境向けの
-
src/pkg/net/lookup_windows.go
:- Windows環境向けの
lookupNS
関数が実装されました。syscall.DnsQuery
を使用してNSレコードを問い合わせ、結果をNS
構造体に変換します。
- Windows環境向けの
コアとなるコードの解説
src/pkg/net/dnsclient.go
の変更
// An NS represents a single DNS NS record.
type NS struct {
Host string
}
このコードは、DNSのNSレコードを表す NS
構造体を定義しています。Host
フィールドは、ネームサーバーのホスト名(例: ns1.example.com
)を文字列として保持します。これは、LookupNS
関数が返す結果の型となります。
src/pkg/net/lookup.go
の変更
// LookupNS returns the DNS NS records for the given domain name.
func LookupNS(name string) (ns []*NS, err error) {
return lookupNS(name)
}
LookupNS
は、net
パッケージの公開APIとして追加された関数です。ユーザーが指定したドメイン名 (name
) に対応するNSレコードを検索し、NS
構造体のスライスとエラーを返します。実際のDNSクエリ処理は、プラットフォーム固有の内部関数 lookupNS
に委譲されています。この設計により、ユーザーはOSの違いを意識することなくNSレコードをルックアップできます。
src/pkg/net/lookup_plan9.go
の変更
func lookupNS(name string) (ns []*NS, err error) {
lines, err := queryDNS(name, "ns")
if err != nil {
return
}
for _, line := range lines {
f := getFields(line)
if len(f) < 4 {
continue
}
ns = append(ns, &NS{f[3]})
}
return
}
Plan9システム向けの lookupNS
実装です。queryDNS
関数(Plan9固有のDNSクエリメカニズム)を呼び出して、指定されたドメイン名とレコードタイプ "ns" でDNSクエリを実行します。返された各行を getFields
でフィールドに分割し、4番目のフィールド(インデックス3)がネームサーバーのホスト名であると仮定して NS
構造体を作成し、結果のスライスに追加します。
src/pkg/net/lookup_unix.go
の変更
func lookupNS(name string) (ns []*NS, err error) {
_, records, err := lookup(name, dnsTypeNS)
if err != nil {
return
}
ns = make([]*NS, len(records))
for i, r := range records {
r := r.(*dnsRR_NS) // dnsRR_NSはNSレコードの内部表現
ns[i] = &NS{r.Ns}
}
return
}
Unix系システム向けの lookupNS
実装です。既存の汎用DNSルックアップ関数 lookup
を dnsTypeNS
(NSレコードタイプを示す定数) と共に呼び出します。返されたレコードのスライスをイテレートし、各レコードを *dnsRR_NS
型に型アサーション(キャスト)します。dnsRR_NS
構造体の Ns
フィールド(ネームサーバーのホスト名)を抽出し、新しい NS
構造体を作成して結果のスライスに格納します。
src/pkg/net/lookup_windows.go
の変更
func lookupNS(name string) (ns []*NS, err error) {
var r *syscall.DNSRecord
e := syscall.DnsQuery(name, syscall.DNS_TYPE_NS, 0, nil, &r, nil)
if e != nil {
return nil, os.NewSyscallError("LookupNS", e)
}
defer syscall.DnsRecordListFree(r, 1)
ns = make([]*NS, 0, 10)
for p := r; p != nil && p.Type == syscall.DNS_TYPE_NS; p = p.Next {
v := (*syscall.DNSPTRData)(unsafe.Pointer(&p.Data[0]))
ns = append(ns, &NS{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Host))[:]) + "."})
}
return ns, nil
}
Windowsシステム向けの lookupNS
実装です。syscall.DnsQuery
Windows API関数を呼び出してNSレコードをクエリします。エラーが発生した場合は os.NewSyscallError
でGoのエラーに変換します。defer syscall.DnsRecordListFree
を使用して、取得したDNSレコードリストのメモリを解放します。
返されたレコードリストをループ処理し、各レコードがNSタイプであることを確認します。DNSPTRData
型にポインタをキャストし、v.Host
からホスト名を取得します。Windows APIはUTF-16を使用するため、syscall.UTF16ToString
を用いてGoの文字列に変換し、末尾に .
を追加して完全なドメイン名形式にします。
src/pkg/net/lookup_test.go
の変更
func TestGmailNS(t *testing.T) {
if testing.Short() || !*testExternal {
t.Logf("skipping test to avoid external network")
return
}
ns, err := LookupNS("gmail.com")
if err != nil {
t.Errorf("failed: %s", err)
}
if len(ns) == 0 {
t.Errorf("no results")
}
}
LookupNS
関数の動作を検証するためのテストケースです。testing.Short()
フラグが設定されている場合や、testExternal
フラグがfalseの場合(外部ネットワークへのアクセスを避けるため)、テストはスキップされます。テストでは gmail.com
のNSレコードをルックアップし、エラーが発生しないこと、および結果が空でないことを確認します。これにより、LookupNS
関数が期待通りに動作することが保証されます。
関連リンク
- Go Gerrit Change-ID: https://golang.org/cl/6675043
- Go Issue #4224: (このコミットメッセージからは直接リンクされていませんが、
Fixes #4224
とあるため、GoのIssueトラッカーで検索すると詳細が見つかる可能性があります。)
参考にした情報源リンク
- 特になし (コミットメッセージとコード差分から直接情報を抽出しました)