Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 17414] ファイルの概要

このコミットは、Go言語の net パッケージにおける IPConnReadFrom および ReadFromIP メソッドが、"ip4" ネットワークにおいて完全なIPv4パケットを返さない可能性がある問題に対する修正と、その挙動に関する注意喚起を追加するものです。具体的には、src/pkg/net/iprawsock_posix.goBUG セクションが追加され、src/pkg/net/ipraw_test.go のテストコード内のコメントが更新されています。

コミット

commit a8b4a1e63a55f55bfbb9edc34be841d802444874
Author: Mikio Hara <mikioh.mikioh@gmail.com>
Date:   Wed Aug 28 19:49:17 2013 +0900

    net: BUG section for ReadFrom, ReadFromIP methods of IPConn on "ip4" network
    
    Fixes #3944.
    
    R=golang-dev, r
    CC=golang-dev
    https://golang.org/cl/13263043
---
 src/pkg/net/ipraw_test.go      |  2 +-\
 src/pkg/net/iprawsock_posix.go | 12 ++++++++++++\
 2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/src/pkg/net/ipraw_test.go b/src/pkg/net/ipraw_test.go
index 1abaf885b2..5bee21ad3a 100644
--- a/src/pkg/net/ipraw_test.go
+++ b/src/pkg/net/ipraw_test.go
@@ -202,7 +202,7 @@ func TestPacketConnICMPEcho(t *testing.T) {
 		if _, _, err := c.ReadFrom(rb); err != nil {
 			t.Fatalf("PacketConn.ReadFrom failed: %v", err)
 		}
-		// TODO: fix issue 3944
+		// See BUG section.
 		//if net == "ip4" {
 		//	rb = ipv4Payload(rb)
 		//}
diff --git a/src/pkg/net/iprawsock_posix.go b/src/pkg/net/iprawsock_posix.go
index a73939fe93..401adda867 100644
--- a/src/pkg/net/iprawsock_posix.go
+++ b/src/pkg/net/iprawsock_posix.go
@@ -11,6 +11,18 @@ import (
 	"time"
 )
 
+// BUG(mikio): On every POSIX platform, reads from the "ip4" network
+// using the ReadFrom or ReadFromIP method might not return a complete
+// IPv4 packet, including its header, even if there is space
+// available. This can occur even in cases where Read or ReadMsgIP
+// could return a complete packet. For this reason, it is recommended
+// that you do not uses these methods if it is important to receive a
+// full packet.
+//
+// The Go 1 compatibliity guidelines make it impossible for us to
+// change the behavior of these methods; use Read or ReadMsgIP
+// instead.
+
 func sockaddrToIP(sa syscall.Sockaddr) Addr {
 	switch sa := sa.(type) {
 	case *syscall.SockaddrInet4:

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/a8b4a1e63a55f55bfbb9edc34be841d802444874

元コミット内容

net: BUG section for ReadFrom, ReadFromIP methods of IPConn on "ip4" network

このコミットは、IPConnReadFrom および ReadFromIP メソッドが "ip4" ネットワークで動作する際に、完全なIPv4パケット(ヘッダーを含む)を返さない可能性があるというバグに関する注意喚起(BUG セクション)をコードに追加し、関連するテストコードのコメントを修正するものです。

変更の背景

このコミットの背景には、Go言語の net パッケージにおける IPConn 型の ReadFrom および ReadFromIP メソッドが、"ip4" ネットワーク(IPv4の生IPソケット)を使用した場合に、受信したIPv4パケットのヘッダー部分を含まない、不完全なデータしか返さないという問題がありました。これは、特にネットワークプロトコルを低レベルで扱うアプリケーションにとって重要な問題となります。

コミットメッセージに Fixes #3944 とあるように、この変更はGoのIssue 3944を解決するために行われました。このIssueは、IPConn を使って生IPパケットを受信する際に、期待される完全なIPv4パケット(IPヘッダーを含む)が得られないという報告がなされたものと考えられます。

Go 1の互換性ガイドラインにより、既存のメソッドの挙動を根本的に変更することが困難であったため、開発チームは、この挙動が仕様上の制約であることを明示し、代替となる ReadReadMsgIP メソッドの使用を推奨する形で対応することを選択しました。これにより、ユーザーがこの潜在的な問題を認識し、適切なメソッドを選択できるようになります。

前提知識の解説

1. Go言語の net パッケージ

net パッケージは、Go言語でネットワークプログラミングを行うための基本的な機能を提供します。TCP/IP、UDP、Unixドメインソケットなど、様々なネットワークプロトコルを扱うことができます。

2. IPConn

IPConn は、net パッケージで提供される型の一つで、IPプロトコル(IPv4またはIPv6)の生ソケット(Raw IP Socket)を表します。生ソケットは、TCPやUDPのような上位プロトコルを介さずに、直接IPパケットを送受信するために使用されます。これにより、カスタムプロトコルの実装や、ネットワークの低レベルな解析が可能になります。

3. ReadFromReadFromIP メソッド

IPConn 型には、データを読み込むためのいくつかのメソッドがあります。

  • ReadFrom(b []byte) (n int, addr Addr, err error): データを読み込み、送信元のアドレスも返します。
  • ReadFromIP(b []byte) (n int, addr *IPAddr, err error): ReadFrom と同様ですが、送信元アドレスが *IPAddr 型で返されます。

これらのメソッドは、一般的にUDPのようなデータグラム指向のプロトコルでよく使用されます。

4. ReadReadMsgIP メソッド

  • Read(b []byte) (n int, err error): データを読み込みますが、送信元アドレスは返しません。
  • ReadMsgIP(b, oob []byte) (n, oobn int, flags net.Flags, addr *IPAddr, err error): データを読み込むだけでなく、補助データ(out-of-band data)も読み込むことができます。これには、IPヘッダーやその他のソケットオプションに関する情報が含まれる場合があります。

5. Raw IP Socket と IPv4 パケットヘッダー

Raw IP Socket を使用すると、アプリケーションはIP層のデータに直接アクセスできます。IPv4パケットは、データ部分(ペイロード)の前に、送信元IPアドレス、宛先IPアドレス、プロトコルタイプ、TTL(Time To Live)などの情報を含むヘッダーを持っています。低レベルなネットワークプログラミングでは、このIPヘッダーを解析したり、自分で構築したりすることが重要になります。

6. Go 1 互換性ガイドライン

Go言語は、バージョン1.0以降、互換性に関する厳格なガイドラインを設けています。これは、既存のGoプログラムが新しいバージョンのGoでも問題なく動作することを保証するためのものです。このガイドラインにより、公開されたAPIの挙動を後方互換性を損なう形で変更することは、非常に慎重に行われます。

技術的詳細

このコミットが対処している技術的な問題は、POSIXプラットフォーム上のGo言語において、IPConnReadFrom および ReadFromIP メソッドが "ip4" ネットワーク(Raw IPv4ソケット)からデータを読み込む際に、完全なIPv4パケット(IPヘッダーを含む)を返さない可能性があるというものです。

通常、Raw IPソケットでIPパケットを受信する場合、アプリケーションはIPヘッダーを含む完全なパケットデータを受け取ることを期待します。しかし、特定の条件下では、ReadFromReadFromIP がIPヘッダーを剥がしてしまい、ペイロード部分のみを返す挙動を示すことがありました。これは、これらのメソッドが元々、UDPのような上位プロトコルのデータグラムを扱うことを想定して設計されており、Raw IPソケットの特性を完全に考慮していなかったためと考えられます。

コミットで追加された BUG コメントは、この挙動がGoの設計上の制約であり、Go 1の互換性ガイドラインのために変更できないことを明確にしています。つまり、この「不完全なパケットを返す」という挙動は、バグとして認識されているものの、既存のコードへの影響を最小限に抑えるために、APIの挙動を変更するのではなく、ドキュメントで注意喚起を行うというアプローチが取られました。

代わりに、Read または ReadMsgIP メソッドを使用することが推奨されています。

  • Read: このメソッドは、送信元アドレスを返さないため、ソケットがIPヘッダーを剥がすかどうかの挙動が ReadFromReadFromIP とは異なる可能性があります。Raw IPソケットの場合、多くの場合、Read はIPヘッダーを含む完全なパケットを返します。
  • ReadMsgIP: このメソッドは、補助データ(out-of-band data)を読み込む機能を持っており、これを通じてIPヘッダーなどの追加情報にアクセスできる場合があります。これは、完全なIPパケットを確実に取得するためのより堅牢な方法となります。

この問題は、特にICMP(Internet Control Message Protocol)のようなIP層で動作するプロトコルを実装する際に顕著になります。ICMPメッセージはIPヘッダーの直後に配置されるため、IPヘッダーが欠落すると、メッセージの解析が不可能になります。

このコミットは、コードの挙動そのものを変更するのではなく、その挙動に関する重要な情報を開発者に提供することで、潜在的な問題を回避し、適切なAPIの使用を促すことを目的としています。

コアとなるコードの変更箇所

このコミットでは、以下の2つのファイルが変更されています。

  1. src/pkg/net/ipraw_test.go

    • TestPacketConnICMPEcho 関数内のコメントが変更されました。
    • 変更前: // TODO: fix issue 3944
    • 変更後: // See BUG section.
  2. src/pkg/net/iprawsock_posix.go

    • import 文の直後に、新しい BUG コメントブロックが追加されました。

コアとなるコードの解説

src/pkg/net/ipraw_test.go の変更

src/pkg/net/ipraw_test.go は、net パッケージのIP生ソケット関連のテストコードです。TestPacketConnICMPEcho 関数は、ICMPエコー(ping)の送受信をテストしているものと推測されます。

元のコードには // TODO: fix issue 3944 というコメントがありました。これは、このテストがIssue 3944に関連する未解決の問題を抱えていることを示していました。この問題は、ReadFrom メソッドが完全なIPv4パケットを返さないことに関連していると考えられます。

今回のコミットでは、この TODO コメントが // See BUG section. に変更されました。これは、Issue 3944がコードの挙動変更ではなく、BUG セクションの追加によって「解決済み」と見なされたことを意味します。つまり、この挙動はバグとして認識されているものの、Go 1の互換性ガイドラインにより修正できないため、ドキュメントで注意喚起を行うという方針が取られたことを示唆しています。

src/pkg/net/iprawsock_posix.go の変更

src/pkg/net/iprawsock_posix.go は、POSIXシステム(Linux, macOSなど)におけるIP生ソケットの実装に関連するコードです。

このファイルに追加された BUG コメントブロックは、このコミットの最も重要な変更点です。

// BUG(mikio): On every POSIX platform, reads from the "ip4" network
// using the ReadFrom or ReadFromIP method might not return a complete
// IPv4 packet, including its header, even if there is space
// available. This can occur even in cases where Read or ReadMsgIP
// could return a complete packet. For this reason, it is recommended
// that you do not uses these methods if it is important to receive a
// full packet.
//
// The Go 1 compatibliity guidelines make it impossible for us to
// change the behavior of these methods; use Read or ReadMsgIP
// instead.

このコメントは以下の重要な情報を含んでいます。

  1. 問題の特定: POSIXプラットフォーム上の "ip4" ネットワークにおいて、ReadFrom または ReadFromIP メソッドを使用すると、完全なIPv4パケット(ヘッダーを含む)が返されない可能性があること。
  2. 条件: バッファに十分なスペースがある場合でも発生し、ReadReadMsgIP では完全なパケットが返される場合でも発生しうること。
  3. 推奨事項: 完全なパケットを受信することが重要な場合は、これらのメソッドを使用しないこと。
  4. 理由: Go 1の互換性ガイドラインにより、これらのメソッドの挙動を変更することができないため。
  5. 代替手段: 代わりに Read または ReadMsgIP を使用すること。

この BUG コメントは、Goのドキュメンテーションツールによって自動的に抽出され、Goの公式ドキュメント(go doc net IPConn などで表示される)に表示されるため、開発者がこの潜在的な問題と推奨される解決策を容易に知ることができます。これは、コードの挙動を変更せずに、ユーザーへの情報提供を強化する効果的な方法です。

関連リンク

参考にした情報源リンク

  • Go言語の net パッケージに関する公式ドキュメント (Goのバージョンによって内容は異なりますが、IPConn や関連メソッドのドキュメントを参照しました)
  • Go 1 互換性ガイドラインに関する情報 (Goの公式ブログやドキュメントを参照しました)
  • Raw IPソケットに関する一般的なネットワークプログラミングの知識