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

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

このコミットは、Go言語の標準ライブラリであるnetパッケージ内のipraw_test.goファイルに対する変更です。ipraw_test.goは、IPアドレスの解決や生IPソケットに関連する機能のテストを目的としたファイルです。具体的には、net.ResolveIPAddr関数の挙動を検証するためのテストケースが含まれています。

コミット

このコミットは、net.ResolveIPAddr関数がプロトコル番号を内部情報ベースを使用してルックアップする際のテストを追加します。特に、プロトコル名のケースセンシティブな処理に関するテストケースが追加されています。これにより、ResolveIPAddrがプロトコル名を適切に解釈できることを保証します。

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

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

元コミット内容

commit d3043b7b4ac636fd1c2e43ff5e77e84a08b9a49f
Author: Mikio Hara <mikioh.mikioh@gmail.com>
Date:   Thu Aug 22 12:13:54 2013 +0900

    net: add test for protocol numbers lookup using internal information base
    
    Update #5344
    
    R=alex.brainman
    CC=golang-dev
    https://golang.org/cl/12966046

変更の背景

この変更の背景には、net.ResolveIPAddr関数がプロトコル名を解決する際の堅牢性を高めるという目的があります。ResolveIPAddrは、ネットワークアドレスとプロトコル名を組み合わせてIPアドレスを解決する際に使用されます。例えば、"ip6:ipv6-icmp"のように、ネットワークタイプとプロトコル名をコロンで区切って指定することができます。

既存のテストでは、"ip6:ipv6-icmp"のような小文字のプロトコル名に対するテストは存在しましたが、"ip6:IPv6-ICMP"のように大文字を含むプロトコル名が指定された場合に、ResolveIPAddrが正しくプロトコル番号をルックアップできるかどうかの保証がありませんでした。

このコミットは、この潜在的な問題を解決するために、大文字を含むプロトコル名("ip6:IPv6-ICMP")に対するテストケースを追加し、ResolveIPAddrが内部のプロトコル情報ベースを使用して、プロトコル名をケースインセンシティブに、または少なくとも一般的な大文字・小文字の組み合わせで正しく解決できることを確認することを目的としています。

コミットメッセージにあるUpdate #5344は、Goプロジェクト内の特定の課題(issue)を参照している可能性がありますが、公開されているGoのGitHubリポジトリのissueトラッカーでは直接的な関連が見つかりませんでした。これは、内部的なトラッキング番号であるか、あるいは非常に古いissueであるため、現在の公開データベースからは参照できない可能性があります。しかし、変更内容から推測すると、プロトコル名の解決における堅牢性向上に関する課題であったと考えられます。

前提知識の解説

Go言語のnetパッケージ

netパッケージは、Go言語におけるネットワークI/Oの主要なインターフェースを提供します。TCP/IP、UDP、Unixドメインソケットなど、様々なネットワークプロトコルを扱うための機能が含まれています。ネットワークアドレスの解決、接続の確立、データの送受信など、低レベルから高レベルまでのネットワーク操作をサポートします。

IPAddr構造体

net.IPAddrは、IPアドレスを表す構造体です。以下のフィールドを持ちます。

  • IP net.IP: IPアドレス自体(IPv4またはIPv6)。
  • Zone string: IPv6アドレスのスコープゾーン識別子。リンクローカルアドレスなどで使用されます。

ParseIP関数

net.ParseIP関数は、文字列形式のIPアドレス(例: "192.168.1.1", "::1")をnet.IP型に変換します。無効なIPアドレス文字列が与えられた場合はnilを返します。

ResolveIPAddr関数

net.ResolveIPAddr関数は、ネットワークタイプと文字列形式のアドレス(ホスト名やIPアドレス)を指定して、対応する*net.IPAddrを解決します。

関数のシグネチャは以下の通りです。

func ResolveIPAddr(net, addr string) (*IPAddr, error)
  • net: ネットワークタイプを指定します。例えば、"ip"(任意のIPプロトコル)、"ip4"(IPv4)、"ip6"(IPv6)などがあります。また、"ip6:ipv6-icmp"のように、コロンで区切って特定のプロトコル名を指定することもできます。
  • addr: 解決するアドレス文字列です。IPアドレスの文字列形式やホスト名が含まれます。

この関数は、指定されたネットワークタイプとアドレスに基づいて、適切なIPアドレスとゾーン情報を解決し、*net.IPAddr構造体として返します。エラーが発生した場合はerrorを返します。

プロトコル番号とプロトコル名

TCP/IPネットワークでは、各プロトコルは一意のプロトコル番号によって識別されます。例えば、ICMP (Internet Control Message Protocol) はプロトコル番号1、TCP (Transmission Control Protocol) はプロトコル番号6、UDP (User Datagram Protocol) はプロトコル番号17などです。

これらのプロトコル番号には、人間が読みやすいように対応するプロトコル名が割り当てられています。例えば、ICMPは"icmp"、IPv6-ICMPは"ipv6-icmp"といった名前です。オペレーティングシステムは通常、これらのプロトコル名と番号のマッピングを内部的に保持しています(例: Unix系システムでは/etc/protocolsファイル)。

net.ResolveIPAddrのような関数がプロトコル名を引数として受け取る場合、内部的にはこのプロトコル名から対応するプロトコル番号をルックアップし、それを使用してネットワーク操作を行います。このルックアップ処理において、プロトコル名の大文字・小文字を区別するかどうかが問題となることがあります。

技術的詳細

このコミットの技術的な詳細は、net.ResolveIPAddr関数がプロトコル名を解決する際のケースセンシティブな挙動をテストすることにあります。

resolveIPAddrTestsというテストデータスライスに、新しいテストケースが追加されています。

{"ip6:IPv6-ICMP", "::1", &IPAddr{IP: ParseIP("::1")}, nil},

このテストケースは、以下の要素で構成されています。

  • net: "ip6:IPv6-ICMP"
    • ip6: ネットワークタイプとしてIPv6を指定します。
    • IPv6-ICMP: プロトコル名としてIPv6-ICMPを指定します。注目すべきは、既存のテストケースがipv6-icmp(小文字)を使用しているのに対し、この新しいテストケースではIPv6-ICMP(大文字を含む)を使用している点です。
  • litAddr: "::1"
    • ループバックIPv6アドレスです。
  • addr: &IPAddr{IP: ParseIP("::1")}
    • 期待される解決結果のIPAddr構造体です。::1が正しくパースされることを期待します。
  • err: nil
    • エラーが発生しないことを期待します。

このテストケースが追加されることで、ResolveIPAddr関数が"IPv6-ICMP"というプロトコル名を正しくIPv6-ICMPプロトコル番号にマッピングできるかどうかが検証されます。もしResolveIPAddrの内部実装がプロトコル名のルックアップにおいて大文字・小文字を厳密に区別する場合、このテストは失敗するでしょう。テストが成功するということは、ResolveIPAddrがプロトコル名をケースインセンシティブに、または少なくとも一般的な大文字・小文字の組み合わせを許容して解決できることを意味します。

また、テスト失敗時のエラーメッセージの出力方法も変更されています。

-			condFatalf(t, "ResolveIPAddr(%v, %v) failed: %v", tt.net, tt.litAddr, err)
+			t.Fatalf("ResolveIPAddr(%v, %v) failed: %v", tt.net, tt.litAddr, err)

condFatalfからt.Fatalfへの変更は、テストフレームワークの慣用的な使用法への調整と考えられます。t.Fatalfは、テストを失敗としてマークし、指定されたメッセージを出力してテストの実行を停止します。condFatalfは、おそらく特定の条件が満たされた場合にのみt.Fatalfを呼び出すヘルパー関数であったと推測されますが、この変更により、エラー発生時に直接t.Fatalfが呼び出されるようになり、より直接的なエラー報告が行われるようになります。これは機能的な変更というよりは、テストコードの簡素化または標準化の一環である可能性が高いです。

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

diff --git a/src/pkg/net/ipraw_test.go b/src/pkg/net/ipraw_test.go
index 4f7d85aac7..fce0830a36 100644
--- a/src/pkg/net/ipraw_test.go
+++ b/src/pkg/net/ipraw_test.go
@@ -29,6 +29,7 @@ var resolveIPAddrTests = []resolveIPAddrTest{
 	{"ip", "::1", &IPAddr{IP: ParseIP("::1")}, nil},
 	{"ip6", "::1", &IPAddr{IP: ParseIP("::1")}, nil},
 	{"ip6:ipv6-icmp", "::1", &IPAddr{IP: ParseIP("::1")}, nil},
+	{"ip6:IPv6-ICMP", "::1", &IPAddr{IP: ParseIP("::1")}, nil},
 
 	{"ip", "::1%en0", &IPAddr{IP: ParseIP("::1"), Zone: "en0"}, nil},
 	{"ip6", "::1%911", &IPAddr{IP: ParseIP("::1"), Zone: "911"}, nil},
@@ -55,7 +56,7 @@ func TestResolveIPAddr(t *testing.T) {
 	for _, tt := range resolveIPAddrTests {
 		addr, err := ResolveIPAddr(tt.net, tt.litAddr)
 		if err != tt.err {
-			condFatalf(t, "ResolveIPAddr(%v, %v) failed: %v", tt.net, tt.litAddr, err)
+			t.Fatalf("ResolveIPAddr(%v, %v) failed: %v", tt.net, tt.litAddr, err)
 		} else if !reflect.DeepEqual(addr, tt.addr) {
 			t.Fatalf("got %#v; expected %#v", addr, tt.addr)
 		}

コアとなるコードの解説

このコミットにおけるコアとなるコードの変更は、src/pkg/net/ipraw_test.goファイル内のresolveIPAddrTestsスライスへの新しいテストケースの追加と、テスト失敗時のエラー報告方法の変更の2点です。

  1. 新しいテストケースの追加:

    {"ip6:IPv6-ICMP", "::1", &IPAddr{IP: ParseIP("::1")}, nil},
    

    この行が追加されたことで、TestResolveIPAddr関数は、net引数に"ip6:IPv6-ICMP"という文字列が与えられた場合に、::1というIPv6アドレスが正しく解決され、エラーが発生しないことを検証するようになります。これは、net.ResolveIPAddrがプロトコル名のルックアップにおいて、大文字・小文字を区別しない、または少なくとも一般的な大文字・小文字の組み合わせを許容する実装になっていることを確認するための重要なテストです。これにより、ユーザーがプロトコル名を記述する際の大文字・小文字の揺れに対応できるよう、関数の堅牢性が向上します。

  2. エラー報告方法の変更:

    -			condFatalf(t, "ResolveIPAddr(%v, %v) failed: %v", tt.net, tt.litAddr, err)
    +			t.Fatalf("ResolveIPAddr(%v, %v) failed: %v", tt.net, tt.litAddr, err)
    

    この変更は、テストが失敗した場合にエラーメッセージを出力し、テストを終了させるための関数呼び出しをcondFatalfからt.Fatalfに直接変更したものです。Goの標準テストパッケージtestingでは、*testing.T型のメソッドであるFatalfがテストの失敗を報告し、テストの実行を停止するために使用されます。condFatalfは、おそらく以前のコードベースで共通のエラー報告ロジックをカプセル化するために使用されていたカスタムヘルパー関数であったと推測されます。この変更は、テストコードをより標準的なGoのテストフレームワークの慣習に合わせるためのリファクタリングであり、機能的な動作に大きな変更はありませんが、コードの可読性と保守性を向上させます。

これらの変更は、net.ResolveIPAddr関数の堅牢性を高め、様々な入力パターン(特にプロトコル名の大文字・小文字のバリエーション)に対して正しく動作することを保証するためのものです。

関連リンク

参考にした情報源リンク

  • Go Code Review: https://golang.org/cl/12966046 (コミットメッセージに記載されているGoのコードレビューシステムへのリンク)
  • Go言語 net パッケージのドキュメント (Goの公式ドキュメントサイト)
  • Go言語 testing パッケージのドキュメント (Goの公式ドキュメントサイト)
  • RFC 2460: Internet Protocol, Version 6 (IPv6) Specification (IPv6に関する一般的な情報)
  • RFC 792: Internet Control Message Protocol (ICMPに関する一般的な情報)
  • RFC 4443: Internet Control Message Protocol (ICMPv6) for the Internet Protocol Version 6 (IPv6) (ICMPv6に関する一般的な情報)
  • /etc/protocols ファイルの一般的な情報 (Unix系システムにおけるプロトコル名と番号のマッピングに関する情報)