[インデックス 17691] ファイルの概要
このコミットは、Go言語のネットワークパッケージにおけるWindows環境でのRawソケットテストの実行に関する変更を扱っています。具体的には、以前の変更によって無効化されていたRawソケットテストを、ユーザーがRawソケットを作成する権限を持っている場合にのみ実行するように再有効化するものです。
コミット
commit b80ef1ab48b9829e8b974effadc0740d6645cc39
Author: Alex Brainman <alex.brainman@gmail.com>
Date: Tue Sep 24 13:15:49 2013 +1000
net: re-enable raw socket tests on windows
Since CL 38bf89161a72 raw socket tests are not executed
on windows builders. This change re-enable them again.
It will attempt to run raw socket tests only if user
is permitted to create raw socket by OS.
Fixes #6392
R=golang-dev
CC=golang-dev, mikioh.mikioh, rsc
https://golang.org/cl/13422044
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/b80ef1ab48b9829e8b974effadc0740d6645cc39
元コミット内容
net: re-enable raw socket tests on windows
Since CL 38bf89161a72 raw socket tests are not executed
on windows builders. This change re-enable them again.
It will attempt to run raw socket tests only if user
is permitted to create raw socket by OS.
Fixes #6392
R=golang-dev
CC=golang-dev, mikioh.mikioh, rsc
https://golang.org/cl/13422044
変更の背景
このコミットの背景には、Go言語のネットワークパッケージにおけるRawソケット関連のテストが、特定の変更(CL 38bf89161a72
)以降、Windowsビルド環境で実行されなくなっていたという問題があります。Rawソケットは、通常のソケット通信ではアクセスできない低レベルのネットワークプロトコル(例: ICMP)に直接アクセスするために使用されます。しかし、Rawソケットの作成には通常、オペレーティングシステム(OS)レベルでの特別な権限が必要です。
Windows環境では、Rawソケットの作成には管理者権限が要求されます。以前の変更により、Windowsビルド環境でこれらのテストがスキップされるようになっていましたが、これはテストカバレッジの低下を意味します。このコミットの目的は、Windows上でのRawソケットテストを再度有効にすることです。ただし、無条件に有効にするのではなく、テストを実行するユーザーがOSによってRawソケットを作成する権限を持っている場合にのみ実行するように変更することで、テストの安定性と信頼性を確保しています。これにより、権限のない環境でのテスト失敗を防ぎつつ、Rawソケット機能のテストを継続できるようになります。
前提知識の解説
Rawソケット
Rawソケットは、TCPやUDPのような上位プロトコルを介さずに、IP層やそれ以下のデータリンク層のパケットに直接アクセスするためのソケットです。これにより、開発者はカスタムプロトコルを実装したり、ネットワークトラフィックを詳細に分析したり、ICMP(Internet Control Message Protocol)のようなプロトコルを直接操作したりすることができます。
Rawソケットは非常に強力であるため、悪用される可能性もあります(例: パケットの偽装、ネットワークスキャン)。このため、ほとんどのオペレーティングシステムでは、Rawソケットの作成や使用に特別な権限(通常は管理者権限やroot権限)を要求します。
WindowsにおけるRawソケットの権限
Windowsでは、SOCK_RAW
タイプのソケットを使用するには管理者権限が必要です。Microsoftのドキュメント(MSDN)によると、Windows Vista以降ではソケット作成時にアクセス権が強制され、それ以前のバージョンでは他のソケット操作中に強制されます。権限がない場合、WSAEACCES
(Access Denied)エラーが発生します。
Go言語の net
パッケージとテストフレームワーク
Go言語の標準ライブラリには、ネットワーク通信を扱うための net
パッケージが含まれています。このパッケージは、TCP/UDPソケットだけでなく、IPソケットやRawソケットのような低レベルのネットワーク機能もサポートしています。
Goのテストフレームワークは、testing
パッケージによって提供されます。テスト関数は Test
で始まる名前を持ち、*testing.T
型の引数を取ります。テスト内で t.Skip()
を呼び出すことで、特定の条件が満たされない場合にテストをスキップすることができます。これは、特定のOSや環境でのみ実行可能なテスト、または特定の権限が必要なテストでよく使用されます。
syscall
パッケージと os.Getuid()
Go言語の syscall
パッケージは、低レベルのOSプリミティブへのアクセスを提供します。これには、ソケットの作成(syscall.Socket
)やクローズ(syscall.Closesocket
)などの関数が含まれます。
os.Getuid()
関数は、現在のプロセスの実効ユーザーID(UID)を返します。Unix系システムでは、UIDが0であることは通常、プロセスがroot権限で実行されていることを意味します。WindowsにはUIDの概念はありませんが、このコミットではWindows固有の権限チェックメカニズムが導入されています。
技術的詳細
このコミットの主要な技術的変更点は、Rawソケットテストをスキップするかどうかを判断するための新しいヘルパー関数 skipRawSocketTests()
の導入と、既存のテストコードにおけるOSごとの条件分岐の整理です。
skipRawSocketTests()
関数の導入
各OS(Plan 9, Unix, Windows)の net
パッケージの内部ファイル(fd_plan9.go
, fd_unix.go
, fd_windows.go
)に、skipRawSocketTests()
という関数が追加されました。この関数は、Rawソケットテストをスキップすべきかどうか、スキップする場合の理由メッセージ、および発生したエラーを返します。
-
src/pkg/net/fd_plan9.go
: Plan 9ではRawソケットテストを常にスキップするように設定されています。func skipRawSocketTests() (skip bool, skipmsg string, err error) { return true, "skipping test on plan9", nil }
-
src/pkg/net/fd_unix.go
: Unix系システムでは、os.Getuid() != 0
(root権限でない場合)にテストをスキップします。func skipRawSocketTests() (skip bool, skipmsg string, err error) { if os.Getuid() != 0 { return true, "skipping test; must be root", nil } return false, "", nil }
-
src/pkg/net/fd_windows.go
: Windowsでは、実際にRawソケットを作成してみて、syscall.WSAEACCES
エラーが発生するかどうかで権限をチェックします。エラーが発生した場合はスキップし、それ以外のエラーが発生した場合はそのエラーを返します。func skipRawSocketTests() (skip bool, skipmsg string, err error) { // From http://msdn.microsoft.com/en-us/library/windows/desktop/ms740548.aspx: // Note: To use a socket of type SOCK_RAW requires administrative privileges. // Users running Winsock applications that use raw sockets must be a member of // the Administrators group on the local computer, otherwise raw socket calls // will fail with an error code of WSAEACCES. On Windows Vista and later, access // for raw sockets is enforced at socket creation. In earlier versions of Windows, // access for raw sockets is enforced during other socket operations. s, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, 0) if err == syscall.WSAEACCES { return true, "skipping test; no access to raw socket allowed", nil } if err != nil { return true, "", err } defer syscall.Closesocket(s) return false, "", nil }
このWindows固有の実装は、Rawソケットの作成が成功するかどうかを試すことで、実行時の権限を動的にチェックするという賢明なアプローチです。
テストコードの変更
ipraw_test.go
, packetconn_test.go
, protoconn_test.go
など、Rawソケットを使用するテストファイルでは、既存の switch runtime.GOOS
によるOSごとの条件分岐が削除され、新しく導入された skipRawSocketTest(t *testing.T)
ヘルパー関数が使用されるようになりました。
skipRawSocketTest
関数は、skipRawSocketTests()
を呼び出し、エラーが発生した場合は t.Fatal()
でテストを終了させ、スキップすべき場合は t.Skip()
でテストをスキップします。
例: src/pkg/net/ipraw_test.go
の変更
--- a/src/pkg/net/ipraw_test.go
+++ b/src/pkg/net/ipraw_test.go
@@ -59,6 +59,14 @@ func init() {
}
}
+func skipRawSocketTest(t *testing.T) (skip bool, skipmsg string) {
+ skip, skipmsg, err := skipRawSocketTests()
+ if err != nil {
+ t.Fatal(err)
+ }
+ return skip, skipmsg
+}
+
func TestResolveIPAddr(t *testing.T) {
for _, tt := range resolveIPAddrTests {
addr, err := ResolveIPAddr(tt.net, tt.litAddrOrName)
@@ -80,17 +88,8 @@ var icmpEchoTests = []struct {
}
func TestConnICMPEcho(t *testing.T) {
- switch runtime.GOOS {
- case "plan9":
- t.Skipf("skipping test on %q", runtime.GOOS)
- case "windows":
- if testing.Short() || !*testExternal {
- t.Skipf("skipping test on %q to avoid network firewall", runtime.GOOS)
- }
- default:
- if os.Getuid() != 0 {
- t.Skip("skipping test; must be root")
- }
+ if skip, skipmsg := skipRawSocketTest(t); skip {
+ t.Skip(skipmsg)
}
for i, tt := range icmpEchoTests {
この変更により、テストコードがより簡潔になり、OSごとのRawソケット権限チェックロジックが一元化されました。
syscall/ztypes_windows.go
の変更
Windows固有のエラーコード WSAEACCES
が src/pkg/syscall/ztypes_windows.go
に追加されました。これは、WindowsのRawソケット権限チェックで使用されるエラーコードをGoの syscall.Errno
型で認識できるようにするためです。
--- a/src/pkg/syscall/ztypes_windows.go
+++ b/src/pkg/syscall/ztypes_windows.go
@@ -22,6 +22,7 @@ const (
ERROR_OPERATION_ABORTED Errno = 995
ERROR_IO_PENDING Errno = 997
ERROR_NOT_FOUND Errno = 1168
+ WSAEACCES Errno = 10013
)
const (
WSAEACCES
はWinsock APIでアクセス拒否を示すエラーコードであり、値は 10013
です。
コアとなるコードの変更箇所
src/pkg/net/fd_plan9.go
:skipRawSocketTests()
関数の追加src/pkg/net/fd_unix.go
:skipRawSocketTests()
関数の追加src/pkg/net/fd_windows.go
:skipRawSocketTests()
関数の追加src/pkg/net/ipraw_test.go
:skipRawSocketTest()
ヘルパー関数の追加と、既存テストでの利用src/pkg/net/multicast_test.go
: Windowsでのテストスキップ条件の削除src/pkg/net/packetconn_test.go
:packetConnTestData
関数内でのテストスキップ条件の変更src/pkg/net/protoconn_test.go
:TestIPConnSpecificMethods
でのテストスキップ条件の変更src/pkg/syscall/ztypes_windows.go
:WSAEACCES
エラーコードの追加
コアとなるコードの解説
このコミットの核心は、Rawソケットテストの実行を、OSがRawソケットの作成を許可しているかどうかに基づいて動的に判断するメカニズムを導入した点です。
-
skipRawSocketTests()
の導入: この関数は、各OSの特性に合わせてRawソケットの作成権限をチェックします。- Plan 9ではRawソケットがサポートされていないため、常にスキップします。
- Unix系では、
os.Getuid()
を使ってroot権限があるかを確認します。 - Windowsでは、実際に
syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, 0)
を呼び出してRawソケットの作成を試みます。この試行がWSAEACCES
エラー(アクセス拒否)を返した場合、ユーザーにRawソケットを作成する権限がないと判断し、テストをスキップします。これにより、Windows環境でのテスト実行時に、権限不足による不必要な失敗を防ぎつつ、権限がある場合にはテストが実行されるようになります。
-
テストコードの簡素化:
ipraw_test.go
などのテストファイルでは、以前はruntime.GOOS
を使った冗長なOSごとの条件分岐がありました。このコミットでは、skipRawSocketTest(t *testing.T)
という新しいヘルパー関数を導入し、この関数内でskipRawSocketTests()
を呼び出すようにしました。これにより、テストコードはよりクリーンになり、OSごとの権限チェックロジックがskipRawSocketTests()
にカプセル化されました。テスト関数は単にif skip, skipmsg := skipRawSocketTest(t); skip { t.Skip(skipmsg) }
のパターンに従うだけでよくなりました。 -
WSAEACCES
の定義: WindowsのRawソケット権限チェックで必要となるWSAEACCES
エラーコードがsyscall
パッケージに追加されました。これにより、GoプログラムがWindows APIから返されるこの特定のエラーを適切に認識し、処理できるようになります。
これらの変更により、GoのネットワークパッケージにおけるRawソケットテストは、Windows環境においてもより堅牢かつ適切に実行されるようになりました。
関連リンク
- GitHubコミットページ: https://github.com/golang/go/commit/b80ef1ab48b9829e8b974effadc0740d6645cc39
- Go CL: https://golang.org/cl/13422044
CL 38bf89161a72
について: コミットメッセージで言及されているCL 38bf89161a72
は、Goの内部的な変更リストIDである可能性が高く、公開されているGoリポジトリのコミットハッシュとは直接対応しないようです。Web検索では、このハッシュに一致するGoのコミットは確認できませんでした。Fixes #6392
について: Web検索では、Goの公式リポジトリにおけるissue #6392
は確認できませんでした。このイシュー番号は、Goプロジェクトの外部のイシュートラッカーを参照している可能性があります。
参考にした情報源リンク
- MSDN - Raw Sockets: http://msdn.microsoft.com/en-us/library/windows/desktop/ms740548.aspx (コミットコード内のコメントで参照されているリンク)