[インデックス 16586] ファイルの概要
このコミットは、Go言語のネットワークパッケージにおけるPlan 9オペレーティングシステムでのLookupNS
関数のバグ修正に関するものです。具体的には、Plan 9の/net/dns
ファイルからネームサーバー情報を解決する際に、フィールド数のチェックが誤っていたために発生していた問題を修正しています。
コミット
commit 2af974777d8e771e5c58f172876ac4c6d9fb7256
Author: Nicolas Owens <mischief@offblast.org>
Date: Mon Jun 17 11:38:07 2013 -0700
net: fix LookupNS on Plan 9
use correct field count when resolving nameservers via /net/dns on Plan 9.
we incorrectly check for 4 fields instead of 3 when parsing the result of /net/dns, and get no results
R=golang-dev, ality
CC=golang-dev
https://golang.org/cl/10182044
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/2af974777d8e771e5c58f172876ac4c6d9fb7256
元コミット内容
このコミットは、Go言語のnet
パッケージにおけるPlan 9固有のDNSルックアップ処理、特にLookupNS
関数に関するバグを修正するものです。
コミットメッセージの要約は以下の通りです。
- タイトル:
net: fix LookupNS on Plan 9
(net: Plan 9でのLookupNSを修正) - 詳細: Plan 9上で
/net/dns
を介してネームサーバーを解決する際に、正しいフィールド数を使用するように修正。/net/dns
の結果をパースする際に、誤って3フィールドではなく4フィールドをチェックしていたため、結果が得られなかった問題を解決。
変更の背景
この変更の背景には、Go言語がサポートするオペレーティングシステムの一つであるPlan 9におけるDNS解決の特殊性があります。Goのnet
パッケージは、様々なOSで動作するように設計されており、それぞれのOSのネットワークインターフェースやシステムコールに適応する必要があります。
Plan 9では、DNS情報を含むシステムリソースはファイルシステムを通じて公開されます。具体的には、/net/dns
という特殊なファイルを通じてDNSリゾルバの設定やクエリ結果にアクセスします。Goのnet
パッケージ内のlookup_plan9.go
ファイルは、このPlan 9固有のメカニズムを利用してDNSルックアップを実行します。
問題は、lookupNS
関数が/net/dns
から読み取った行をパースする際に、期待されるフィールド数に関する誤った仮定をしていたことにありました。元のコードでは、各行が少なくとも4つのフィールドを持つことを期待していましたが、実際には3つのフィールドしか持たない場合がありました。この不一致により、有効なネームサーバー情報がパースされず、LookupNS
関数が常に結果を返さないというバグが発生していました。
この修正は、Plan 9環境でのGoアプリケーションが正しくDNSルックアップを実行できるようにするために不可欠でした。
前提知識の解説
Plan 9 from Bell Labs
Plan 9 from Bell Labsは、ベル研究所で開発された分散オペレーティングシステムです。Unixの設計思想をさらに推し進め、すべてのリソース(プロセス、デバイス、ネットワーク接続など)をファイルとして表現し、ファイルシステムを通じてアクセスするという哲学を特徴としています。これにより、システム全体が統一されたファイルシステムとして扱われ、ネットワーク透過性が高く、分散システム構築に適しています。
/net/dns
(Plan 9)
Plan 9では、ネットワーク関連の情報もファイルシステムを通じて提供されます。/net
ディレクトリはネットワークインターフェースやプロトコルに関する情報を提供します。その中でも/net/dns
は、DNS(Domain Name System)リゾルバの設定やクエリ結果を扱うための特殊なファイルです。
/net/dns
ファイルは、DNSクエリを送信したり、DNSサーバーからの応答を読み取ったりするために使用されます。通常、このファイルに書き込むことでクエリを送信し、読み込むことで応答を取得します。応答のフォーマットは、DNSレコードの種類やクエリの内容によって異なりますが、一般的にはスペース区切りのフィールドで構成されます。
例えば、ネームサーバー(NS)レコードの応答は、以下のような形式で提供されることがあります(これは一般的な例であり、実際のPlan 9の出力形式は異なる場合がありますが、フィールドベースであるという点は共通です)。
type domain ttl nameserver_address
このコミットの文脈では、nameserver_address
がネームサーバーのアドレスを示す重要なフィールドであり、これが何番目のフィールドとして提供されるかが問題となっていました。
DNS (Domain Name System)
DNSは、インターネット上のドメイン名(例: example.com
)をIPアドレス(例: 192.0.2.1
)に変換するための分散型階層構造の命名システムです。ユーザーがウェブサイトにアクセスする際、ブラウザはまずDNSを使ってドメイン名に対応するIPアドレスを解決し、そのIPアドレスを使ってサーバーに接続します。
- ネームサーバー (Name Server): ドメイン名とIPアドレスのマッピング情報を管理するサーバーです。
- NSレコード (Name Server Record): 特定のドメインのDNS情報を管理するネームサーバーを指定するDNSレコードです。
LookupNS
関数は、このNSレコードを検索するために使用されます。
Go言語のnet
パッケージ
Go言語の標準ライブラリであるnet
パッケージは、ネットワークI/Oのプリミティブを提供します。TCP/IP、UDP、IP、Unixドメインソケットなどのネットワークプロトコルをサポートし、DNSルックアップ機能も含まれています。このパッケージは、OSに依存しない抽象化レイヤーを提供しつつ、必要に応じて各OSのネイティブなネットワーク機能を利用するように実装されています。
技術的詳細
このコミットの技術的な核心は、Plan 9の/net/dns
ファイルから読み取った行のパースロジックの修正にあります。
Goのnet
パッケージ内のlookup_plan9.go
ファイルには、Plan 9環境でDNSルックアップを実行するためのlookupNS
関数が含まれています。この関数は、指定されたドメイン名のネームサーバー(NS)レコードを検索します。
処理のフローは以下のようになります。
lookupNS
関数は、/net/dns
ファイルを開き、DNSクエリを書き込みます。- その後、
/net/dns
から応答を読み取ります。応答は複数行にわたることがあり、各行はDNSレコードの情報を表します。 - 読み取った各行に対して、
getFields(line)
関数を呼び出して、行をスペースで区切られたフィールドの配列に分割します。 - 分割されたフィールドの配列
f
の長さをチェックし、必要な情報が含まれているかを確認します。
元のコードでは、このフィールド数のチェックがlen(f) < 4
となっていました。これは、ネームサーバーのアドレスが少なくとも4番目のフィールド(インデックス3)に存在することを期待していることを意味します。しかし、Plan 9の/net/dns
の出力形式によっては、ネームサーバーのアドレスが3番目のフィールド(インデックス2)に存在する場合がありました。
例えば、/net/dns
が以下のような形式でNSレコードを返すとします。
ns example.com 192.0.2.1
この場合、getFields
によって分割されると、f
は以下のようになります。
f[0] = "ns"
f[1] = "example.com"
f[2] = "192.0.2.1"
このとき、len(f)
は3です。
元のコードのif len(f) < 4
という条件はif 3 < 4
となり、true
と評価されます。これにより、continue
が実行され、この有効な行がスキップされてしまいます。結果として、ns
スライスにネームサーバーが追加されず、LookupNS
関数はネームサーバーを見つけられないという誤った結果を返していました。
修正は、このチェックをlen(f) < 3
に変更することです。これにより、フィールド数が2以下の場合にのみ行がスキップされ、フィールド数が3以上の有効な行が正しく処理されるようになります。
さらに、ネームサーバーのアドレスを取得するインデックスもf[3]
からf[2]
に変更されています。これは、フィールド数のチェックがlen(f) < 3
になったことと整合性が取れており、ネームサーバーのアドレスが3番目のフィールド(インデックス2)に存在するというPlan 9の/net/dns
の出力形式に合わせたものです。
この修正により、Plan 9環境でGoのnet
パッケージが/net/dns
からネームサーバー情報を正しくパースし、LookupNS
関数が期待通りに動作するようになりました。
コアとなるコードの変更箇所
変更はsrc/pkg/net/lookup_plan9.go
ファイル内のlookupNS
関数に集中しています。
--- a/src/pkg/net/lookup_plan9.go
+++ b/src/pkg/net/lookup_plan9.go
@@ -224,10 +224,10 @@ func lookupNS(name string) (ns []*NS, err error) {
}\n \tfor _, line := range lines {\n \t\tf := getFields(line)\n-\t\tif len(f) < 4 {\n+\t\tif len(f) < 3 {\n \t\t\tcontinue\n \t\t}\n-\t\tns = append(ns, &NS{f[3]})\n+\t\tns = append(ns, &NS{f[2]})\
}\n \treturn\n }\
具体的には、以下の2行が変更されています。
if len(f) < 4 {
がif len(f) < 3 {
に変更。ns = append(ns, &NS{f[3]})
がns = append(ns, &NS{f[2]})
に変更。
コアとなるコードの解説
if len(f) < 3 {
この行は、/net/dns
から読み取った行をgetFields
関数で分割した結果のフィールド数len(f)
が、ネームサーバーのアドレスを含むために必要な最小フィールド数(3)よりも少ない場合に、その行の処理をスキップするための条件です。
元のコードではlen(f) < 4
となっていましたが、これはネームサーバーのアドレスがインデックス3(4番目のフィールド)に存在することを期待していました。しかし、Plan 9の/net/dns
の出力形式によっては、ネームサーバーのアドレスがインデックス2(3番目のフィールド)に存在し、行全体のフィールド数が3である場合がありました。この場合、len(f)
は3となり、3 < 4
は真となるため、有効な行が誤ってスキップされていました。
len(f) < 3
に修正することで、フィールド数が0、1、2の場合にのみスキップされるようになり、フィールド数が3以上の有効な行(ネームサーバーのアドレスがインデックス2に存在する行を含む)が正しく処理されるようになります。
ns = append(ns, &NS{f[2]})
この行は、パースされた行からネームサーバーのアドレスを抽出し、NS
構造体を作成して結果のスライスns
に追加する部分です。
元のコードではf[3]
を使用していましたが、これはインデックス3(4番目のフィールド)の値をネームサーバーのアドレスとして取得しようとしていました。前述の通り、Plan 9の/net/dns
の出力形式によっては、ネームサーバーのアドレスがインデックス2(3番目のフィールド)に存在します。
f[2]
に修正することで、ネームサーバーのアドレスが格納されている正しいインデックスから値を取得できるようになり、LookupNS
関数がPlan 9環境で正しくネームサーバーを解決できるようになります。
これらの変更は、Plan 9の/net/dns
の実際の出力形式とGoのパースロジックとの間の不一致を解消し、Goのnet
パッケージがPlan 9上で正しく機能するようにするために不可欠でした。
関連リンク
- Go言語の
net
パッケージのドキュメント: https://pkg.go.dev/net - Plan 9 from Bell Labs: https://9p.io/plan9/
- Goのコードレビューシステム (Gerrit): https://go-review.googlesource.com/ (コミットメッセージにある
https://golang.org/cl/10182044
はGerritの変更リストへのリンクです)
参考にした情報源リンク
- Plan 9の
/net/dns
に関する情報 (一般的なPlan 9のネットワークファイルシステムに関するドキュメントや議論):- Plan 9のmanページやドキュメント(例:
ndb(4)
やdns(4)
など、DNS関連のファイルやプロトコルについて説明しているもの) - Plan 9のソースコードリポジトリ(
/sys/src/cmd/dns
など、DNSリゾルバの実装を確認できる場所)
- Plan 9のmanページやドキュメント(例:
- Go言語の
net
パッケージのソースコード(特にsrc/pkg/net/lookup_plan9.go
の変更前後のコード) - DNSの基本概念に関する一般的な情報源(RFCなど)
- このコミットのGerritレビューページ(
https://golang.org/cl/10182044
)での議論やコメント(もしあれば)
(注: 上記の参考情報源リンクは、この解説を生成するにあたり、一般的な知識とコミットメッセージから推測される情報源のカテゴリを示しています。具体的なURLは、当時のPlan 9のドキュメントやGoのGerritのアーカイブに依存します。)
```markdown
# [インデックス 16586] ファイルの概要
このコミットは、Go言語のネットワークパッケージにおけるPlan 9オペレーティングシステムでの`LookupNS`関数のバグ修正に関するものです。具体的には、Plan 9の`/net/dns`ファイルからネームサーバー情報を解決する際に、フィールド数のチェックが誤っていたために発生していた問題を修正しています。
## コミット
commit 2af974777d8e771e5c58f172876ac4c6d9fb7256 Author: Nicolas Owens mischief@offblast.org Date: Mon Jun 17 11:38:07 2013 -0700
net: fix LookupNS on Plan 9
use correct field count when resolving nameservers via /net/dns on Plan 9.
we incorrectly check for 4 fields instead of 3 when parsing the result of /net/dns, and get no results
R=golang-dev, ality
CC=golang-dev
https://golang.org/cl/10182044
## GitHub上でのコミットページへのリンク
[https://github.com/golang/go/commit/2af974777d8e771e5c58f172876ac4c6d9fb7256](https://github.com/golang/go/commit/2af974777d8e771e5c58f172876ac4c6d9fb7256)
## 元コミット内容
このコミットは、Go言語の`net`パッケージにおけるPlan 9固有のDNSルックアップ処理、特に`LookupNS`関数に関するバグを修正するものです。
コミットメッセージの要約は以下の通りです。
- **タイトル**: `net: fix LookupNS on Plan 9` (net: Plan 9でのLookupNSを修正)
- **詳細**: Plan 9上で`/net/dns`を介してネームサーバーを解決する際に、正しいフィールド数を使用するように修正。`/net/dns`の結果をパースする際に、誤って3フィールドではなく4フィールドをチェックしていたため、結果が得られなかった問題を解決。
## 変更の背景
この変更の背景には、Go言語がサポートするオペレーティングシステムの一つであるPlan 9におけるDNS解決の特殊性があります。Goの`net`パッケージは、様々なOSで動作するように設計されており、それぞれのOSのネットワークインターフェースやシステムコールに適応する必要があります。
Plan 9では、DNS情報を含むシステムリソースはファイルシステムを通じて公開されます。具体的には、`/net/dns`という特殊なファイルを通じてDNSリゾルバの設定やクエリ結果にアクセスします。Goの`net`パッケージ内の`lookup_plan9.go`ファイルは、このPlan 9固有のメカニズムを利用してDNSルックアップを実行します。
問題は、`lookupNS`関数が`/net/dns`から読み取った行をパースする際に、期待されるフィールド数に関する誤った仮定をしていたことにありました。元のコードでは、各行が少なくとも4つのフィールドを持つことを期待していましたが、実際には3つのフィールドしか持たない場合がありました。この不一致により、有効なネームサーバー情報がパースされず、`LookupNS`関数が常に結果を返さないというバグが発生していました。
この修正は、Plan 9環境でのGoアプリケーションが正しくDNSルックアップを実行できるようにするために不可欠でした。
## 前提知識の解説
### Plan 9 from Bell Labs
Plan 9 from Bell Labsは、ベル研究所で開発された分散オペレーティングシステムです。Unixの設計思想をさらに推し進め、すべてのリソース(プロセス、デバイス、ネットワーク接続など)をファイルとして表現し、ファイルシステムを通じてアクセスするという哲学を特徴としています。これにより、システム全体が統一されたファイルシステムとして扱われ、ネットワーク透過性が高く、分散システム構築に適しています。
### `/net/dns` (Plan 9)
Plan 9では、ネットワーク関連の情報もファイルシステムを通じて提供されます。`/net`ディレクトリはネットワークインターフェースやプロトコルに関する情報を提供します。その中でも`/net/dns`は、DNS(Domain Name System)リゾルバの設定やクエリ結果を扱うための特殊なファイルです。
`/net/dns`ファイルは、DNSクエリを送信したり、DNSサーバーからの応答を読み取ったりするために使用されます。通常、このファイルに書き込むことでクエリを送信し、読み込むことで応答を取得します。応答のフォーマットは、DNSレコードの種類やクエリの内容によって異なりますが、一般的にはスペース区切りのフィールドで構成されます。
例えば、ネームサーバー(NS)レコードの応答は、以下のような形式で提供されることがあります(これは一般的な例であり、実際のPlan 9の出力形式は異なる場合がありますが、フィールドベースであるという点は共通です)。
`type domain ttl nameserver_address`
このコミットの文脈では、`nameserver_address`がネームサーバーのアドレスを示す重要なフィールドであり、これが何番目のフィールドとして提供されるかが問題となっていました。
### DNS (Domain Name System)
DNSは、インターネット上のドメイン名(例: `example.com`)をIPアドレス(例: `192.0.2.1`)に変換するための分散型階層構造の命名システムです。ユーザーがウェブサイトにアクセスする際、ブラウザはまずDNSを使ってドメイン名に対応するIPアドレスを解決し、そのIPアドレスを使ってサーバーに接続します。
- **ネームサーバー (Name Server)**: ドメイン名とIPアドレスのマッピング情報を管理するサーバーです。
- **NSレコード (Name Server Record)**: 特定のドメインのDNS情報を管理するネームサーバーを指定するDNSレコードです。`LookupNS`関数は、このNSレコードを検索するために使用されます。
### Go言語の`net`パッケージ
Go言語の標準ライブラリである`net`パッケージは、ネットワークI/Oのプリミティブを提供します。TCP/IP、UDP、IP、Unixドメインソケットなどのネットワークプロトコルをサポートし、DNSルックアップ機能も含まれています。このパッケージは、OSに依存しない抽象化レイヤーを提供しつつ、必要に応じて各OSのネイティブなネットワーク機能を利用するように実装されています。
## 技術的詳細
このコミットの技術的な核心は、Plan 9の`/net/dns`ファイルから読み取った行のパースロジックの修正にあります。
Goの`net`パッケージ内の`lookup_plan9.go`ファイルには、Plan 9環境でDNSルックアップを実行するための`lookupNS`関数が含まれています。この関数は、指定されたドメイン名のネームサーバー(NS)レコードを検索します。
処理のフローは以下のようになります。
1. `lookupNS`関数は、`/net/dns`ファイルを開き、DNSクエリを書き込みます。
2. その後、`/net/dns`から応答を読み取ります。応答は複数行にわたることがあり、各行はDNSレコードの情報を表します。
3. 読み取った各行に対して、`getFields(line)`関数を呼び出して、行をスペースで区切られたフィールドの配列に分割します。
4. 分割されたフィールドの配列`f`の長さをチェックし、必要な情報が含まれているかを確認します。
元のコードでは、このフィールド数のチェックが`len(f) < 4`となっていました。これは、ネームサーバーのアドレスが少なくとも4番目のフィールド(インデックス3)に存在することを期待していることを意味します。しかし、Plan 9の`/net/dns`の出力形式によっては、ネームサーバーのアドレスが3番目のフィールド(インデックス2)に存在する場合がありました。
例えば、`/net/dns`が以下のような形式でNSレコードを返すとします。
`ns example.com 192.0.2.1`
この場合、`getFields`によって分割されると、`f`は以下のようになります。
`f[0] = "ns"`
`f[1] = "example.com"`
`f[2] = "192.0.2.1"`
このとき、`len(f)`は3です。
元のコードの`if len(f) < 4`という条件は`if 3 < 4`となり、`true`と評価されます。これにより、`continue`が実行され、この有効な行がスキップされてしまいます。結果として、`ns`スライスにネームサーバーが追加されず、`LookupNS`関数はネームサーバーを見つけられないという誤った結果を返していました。
修正は、このチェックを`len(f) < 3`に変更することです。これにより、フィールド数が2以下の場合にのみ行がスキップされ、フィールド数が3以上の有効な行(ネームサーバーのアドレスがインデックス2に存在する行を含む)が正しく処理されるようになります。
さらに、ネームサーバーのアドレスを取得するインデックスも`f[3]`から`f[2]`に変更されています。これは、フィールド数のチェックが`len(f) < 3`になったことと整合性が取れており、ネームサーバーのアドレスが3番目のフィールド(インデックス2)に存在するというPlan 9の`/net/dns`の出力形式に合わせたものです。
この修正により、Plan 9環境でGoの`net`パッケージが`/net/dns`からネームサーバー情報を正しくパースし、`LookupNS`関数が期待通りに動作するようになりました。
## コアとなるコードの変更箇所
変更は`src/pkg/net/lookup_plan9.go`ファイル内の`lookupNS`関数に集中しています。
```diff
--- a/src/pkg/net/lookup_plan9.go
+++ b/src/pkg/net/lookup_plan9.go
@@ -224,10 +224,10 @@ func lookupNS(name string) (ns []*NS, err error) {
}\n \tfor _, line := range lines {\n \t\tf := getFields(line)\n-\t\tif len(f) < 4 {\n+\t\tif len(f) < 3 {\n \t\t\tcontinue\n \t\t}\n-\t\tns = append(ns, &NS{f[3]})\n+\t\tns = append(ns, &NS{f[2]})\
}\n \treturn\n }\
具体的には、以下の2行が変更されています。
if len(f) < 4 {
がif len(f) < 3 {
に変更。ns = append(ns, &NS{f[3]})
がns = append(ns, &NS{f[2]})
に変更。
コアとなるコードの解説
if len(f) < 3 {
この行は、/net/dns
から読み取った行をgetFields
関数で分割した結果のフィールド数len(f)
が、ネームサーバーのアドレスを含むために必要な最小フィールド数(3)よりも少ない場合に、その行の処理をスキップするための条件です。
元のコードではlen(f) < 4
となっていましたが、これはネームサーバーのアドレスがインデックス3(4番目のフィールド)に存在することを期待していました。しかし、Plan 9の/net/dns
の出力形式によっては、ネームサーバーのアドレスがインデックス2(3番目のフィールド)に存在し、行全体のフィールド数が3である場合がありました。この場合、len(f)
は3となり、3 < 4
は真となるため、有効な行が誤ってスキップされていました。
len(f) < 3
に修正することで、フィールド数が0、1、2の場合にのみスキップされるようになり、フィールド数が3以上の有効な行(ネームサーバーのアドレスがインデックス2に存在する行を含む)が正しく処理されるようになります。
ns = append(ns, &NS{f[2]})
この行は、パースされた行からネームサーバーのアドレスを抽出し、NS
構造体を作成して結果のスライスns
に追加する部分です。
元のコードではf[3]
を使用していましたが、これはインデックス3(4番目のフィールド)の値をネームサーバーのアドレスとして取得しようとしていました。前述の通り、Plan 9の/net/dns
の出力形式によっては、ネームサーバーのアドレスがインデックス2(3番目のフィールド)に存在します。
f[2]
に修正することで、ネームサーバーのアドレスが格納されている正しいインデックスから値を取得できるようになり、LookupNS
関数がPlan 9環境で正しくネームサーバーを解決できるようになります。
これらの変更は、Plan 9の/net/dns
の実際の出力形式とGoのパースロジックとの間の不一致を解消し、Goのnet
パッケージがPlan 9上で正しく機能するようにするために不可欠でした。
関連リンク
- Go言語の
net
パッケージのドキュメント: https://pkg.go.dev/net - Plan 9 from Bell Labs: https://9p.io/plan9/
- Goのコードレビューシステム (Gerrit): https://go-review.googlesource.com/ (コミットメッセージにある
https://golang.org/cl/10182044
はGerritの変更リストへのリンクです)
参考にした情報源リンク
- Plan 9の
/net/dns
に関する情報 (一般的なPlan 9のネットワークファイルシステムに関するドキュメントや議論):- Plan 9のmanページやドキュメント(例:
ndb(4)
やdns(4)
など、DNS関連のファイルやプロトコルについて説明しているもの) - Plan 9のソースコードリポジトリ(
/sys/src/cmd/dns
など、DNSリゾルバの実装を確認できる場所)
- Plan 9のmanページやドキュメント(例:
- Go言語の
net
パッケージのソースコード(特にsrc/pkg/net/lookup_plan9.go
の変更前後のコード) - DNSの基本概念に関する一般的な情報源(RFCなど)
- このコミットのGerritレビューページ(
https://golang.org/cl/10182044
)での議論やコメント(もしあれば)
(注: 上記の参考情報源リンクは、この解説を生成するにあたり、一般的な知識とコミットメッセージから推測される情報源のカテゴリを示しています。具体的なURLは、当時のPlan 9のドキュメントやGoのGerritのアーカイブに依存します。)