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

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

このコミットは、Go言語の標準ライブラリである net パッケージにおける IPNet 構造体の Zone フィールドに関する変更を一時的に元に戻すものです。具体的には、IPv6のスコープ付きアドレス(特にリンクローカルアドレスやインターフェースローカルマルチキャストアドレス)に関連する Zone フィールドの設定を削除しています。

コミット

commit ecc174324cd47cac7b1e68ed3e33f1ed674f5da3
Author: Mikio Hara <mikioh.mikioh@gmail.com>
Date:   Sun Mar 17 19:50:01 2013 +0900

    net: revert Zone in IPNet temporally
    
    Update #4501.
    
    R=golang-dev, r
    CC=golang-dev
    https://golang.org/cl/7853047

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

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

元コミット内容

このコミットは、以前の変更を「revert(元に戻す)」するものです。元の変更は、IPNet 構造体に Zone フィールドを追加し、特定のIPv6アドレス(リンクローカルユニキャストアドレス、インターフェースローカルマルチキャストアドレス、リンクローカルマルチキャストアドレス)に対して、そのアドレスが属するネットワークインターフェースの名前を Zone フィールドに設定するというものでした。

具体的には、以下のファイルから ifa.Zone = ifi.Nameifma.Zone = ifi.Name といった行、および IPNet 構造体から Zone string フィールドの定義が削除されています。

  • src/pkg/net/interface_bsd.go
  • src/pkg/net/interface_darwin.go
  • src/pkg/net/interface_freebsd.go
  • src/pkg/net/interface_linux.go
  • src/pkg/net/ip.go

変更の背景

このコミットの背景には、Go言語の net パッケージにおけるIPv6スコープ付きアドレスの扱いの複雑さがあります。コミットメッセージにある「Update #4501」が重要な手がかりとなります。

Go issue #4501は、IPv6のスコープ付きアドレス、特にリンクローカルアドレスの Zone フィールドの扱いに関する問題提起でした。リンクローカルアドレスは、特定のインターフェースにのみ有効なアドレスであり、そのアドレスがどのインターフェースに属するかを示す「ゾーンインデックス」または「スコープID」が必要です。Goの net パッケージでは、このゾーン情報を IPNet 構造体の Zone フィールドで管理しようとしていました。

しかし、この Zone フィールドの設定方法や、それが様々なオペレーティングシステム(BSD系、Darwin、FreeBSD、Linuxなど)でどのように機能するかについて、問題や不整合があったと考えられます。一時的にこの変更を元に戻すことで、より堅牢でクロスプラットフォーム互換性のある解決策を検討するための時間を確保したと推測されます。

「temporally(一時的に)」という言葉は、この変更が最終的な解決策ではなく、問題の根本原因を解決するための暫定的な措置であることを示唆しています。

前提知識の解説

IPv6 スコープ付きアドレス (Scoped Addressing)

IPv6アドレスには「スコープ」という概念があります。これは、アドレスが有効な範囲を示すものです。主なスコープには以下のようなものがあります。

  • ユニキャストアドレス:

    • リンクローカルユニキャストアドレス (Link-Local Unicast Address): fe80::/10 のプレフィックスを持つアドレス。同一リンク(ネットワークセグメント)内でのみ有効であり、ルーターを越えて転送されることはありません。主に近隣探索プロトコル (NDP) や自動設定 (SLAAC) など、リンク内での通信に使用されます。
    • グローバルユニキャストアドレス (Global Unicast Address): インターネット全体でルーティング可能なアドレス。
    • ユニークローカルユニキャストアドレス (Unique Local Unicast Address): fc00::/7 のプレフィックスを持つアドレス。サイト内でのみ有効で、グローバルアドレスのようにルーティングはされませんが、リンクローカルアドレスよりも広い範囲(サイト全体)で有効です。
  • マルチキャストアドレス:

    • インターフェースローカルマルチキャストアドレス (Interface-Local Multicast Address): ff01::/16 のプレフィックスを持つアドレス。特定のインターフェース上でのみ有効。
    • リンクローカルマルチキャストアドレス (Link-Local Multicast Address): ff02::/16 のプレフィックスを持つアドレス。同一リンク内でのみ有効。

ゾーンインデックス / スコープID

リンクローカルアドレスや一部のマルチキャストアドレスは、そのアドレスがどのネットワークインターフェースに属するかを識別するための「ゾーンインデックス」または「スコープID」を必要とします。例えば、複数のネットワークインターフェースを持つホストで fe80::1 というリンクローカルアドレスが複数のインターフェースに割り当てられている場合、通信相手に「どのインターフェースの fe80::1 に送るのか」を明示する必要があります。この情報がゾーンインデックスです。

通常、ゾーンインデックスはアドレスの末尾に %<interface_name> または %<interface_index> の形式で付加されます(例: fe80::1%eth0)。

Go言語の net パッケージ

Go言語の net パッケージは、ネットワークI/Oのプリミティブを提供します。IPアドレス、ネットワークインターフェース、TCP/UDP接続などを扱うための型や関数が含まれています。

  • net.IP: IPアドレスを表すバイトスライス。
  • net.IPNet: IPネットワークを表す構造体。IP (ネットワークアドレス) と Mask (サブネットマスク) を持ちます。このコミットで Zone フィールドが一時的に削除された対象です。
  • net.Interface: ネットワークインターフェースの情報を表す構造体。Name (インターフェース名) や Index (インターフェースインデックス) などを含みます。
  • net.IPAddr: IPアドレスとゾーン情報を保持する構造体。

syscall パッケージ

Go言語の syscall パッケージは、オペレーティングシステムの低レベルなシステムコールへのインターフェースを提供します。ネットワークインターフェースの情報取得やアドレスの設定など、OS固有の機能にアクセスする際に使用されます。

  • syscall.InterfaceAddrMessage: ネットワークインターフェースのアドレス情報を含むメッセージ。
  • syscall.InterfaceMulticastAddrMessage: ネットワークインターフェースのマルチキャストアドレス情報を含むメッセージ。
  • syscall.IfAddrmsg: LinuxカーネルのNetlinkソケットを通じて取得されるインターフェースアドレス情報。
  • syscall.RT_SCOPE_HOST / syscall.RT_SCOPE_LINK: Linuxにおけるルーティングスコープの定数。RT_SCOPE_HOST はホスト自身にのみ有効なルート、RT_SCOPE_LINK はリンクローカルなルートを示します。

技術的詳細

このコミットは、Goの net パッケージ内でIPv6のスコープ付きアドレスの Zone フィールドを扱うロジックを一時的に削除しています。

以前の変更では、net.IPNet 構造体に Zone string フィールドが追加され、net.IPAddr 構造体と同様にIPv6スコープ付きアドレスのゾーン情報を保持するように意図されていました。これは、特にリンクローカルユニキャストアドレス (IsLinkLocalUnicast()) やインターフェース/リンクローカルマルチキャストアドレス (IsInterfaceLocalMulticast(), IsLinkLocalMulticast()) に対して、そのアドレスが属するネットワークインターフェースの名前 (ifi.Name) を Zone フィールドに設定する処理が含まれていました。

しかし、このアプローチにはいくつかの課題があったと考えられます。

  1. クロスプラットフォームの複雑性: 各OS(BSD、Darwin、FreeBSD、Linux)でネットワークインターフェースのアドレス情報を取得する方法や、ゾーン情報を扱う方法が異なるため、一貫した実装が困難であった可能性があります。特にLinuxでは syscall.NetlinkRouteAttrsyscall.IfAddrmsg を介してアドレス情報を取得し、RT_SCOPE_HOSTRT_SCOPE_LINK といったスコープ情報に基づいて Zone を設定するロジックがありました。
  2. IPNetIPAddr の役割: IPNet はネットワークアドレスとマスクを表すのに対し、IPAddr は単一のIPアドレスとゾーン情報を表します。IPNetZone フィールドを持たせることの設計上の妥当性や、その利用シナリオが明確でなかった可能性があります。
  3. 潜在的なバグや不整合: Zone フィールドの設定が不適切であったり、特定の条件下で予期せぬ動作を引き起こしたりするバグが発見された可能性があります。Issue #4501がその具体的な問題を示唆しています。

このコミットは、これらの問題を解決するために、一旦 Zone フィールドの設定ロジックを削除し、IPNet 構造体からも Zone フィールド自体を削除することで、以前の状態に戻しています。これにより、net パッケージの安定性を確保しつつ、より適切なゾーン情報の管理方法を再検討する機会を得たと言えます。

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

このコミットでは、以下のファイルから Zone フィールドへの代入処理、および IPNet 構造体からの Zone フィールドの定義が削除されています。

  • src/pkg/net/interface_bsd.go:
    -				if ifa.IP.IsLinkLocalUnicast() {
    -					ifa.Zone = ifi.Name
    -				}
    
  • src/pkg/net/interface_darwin.go:
    -			if ifma.IP.IsInterfaceLocalMulticast() || ifma.IP.IsLinkLocalMulticast() {
    -				ifma.Zone = ifi.Name
    -			}
    
  • src/pkg/net/interface_freebsd.go:
    -			if ifma.IP.IsInterfaceLocalMulticast() || ifma.IP.IsLinkLocalMulticast() {
    -				ifma.Zone = ifi.Name
    -			}
    
  • src/pkg/net/interface_linux.go:
    -			if ifam.Scope == syscall.RT_SCOPE_HOST || ifam.Scope == syscall.RT_SCOPE_LINK {
    -				ifa.Zone = ifi.Name
    -			}
    
    -		if ifma.IP.IsInterfaceLocalMulticast() || ifma.IP.IsLinkLocalMulticast() {
    -			ifma.Zone = ifi.Name
    -		}
    
  • src/pkg/net/ip.go:
    -	Zone string // IPv6 scoped addressing zone
    

コアとなるコードの解説

変更された各ファイルは、Goの net パッケージが様々なオペレーティングシステム(BSD、Darwin、FreeBSD、Linux)上でネットワークインターフェースのアドレス情報をどのように取得し、処理するかを定義しています。

  • interface_bsd.go, interface_darwin.go, interface_freebsd.go: これらのファイルは、それぞれのOSにおける newAddrnewMulticastAddr といった関数内で、取得したIPアドレスがリンクローカルユニキャストアドレスやインターフェース/リンクローカルマルチキャストアドレスである場合に、そのアドレスの Zone フィールドにネットワークインターフェースの名前 (ifi.Name) を設定していました。このコミットでは、これらの設定ロジックが削除されています。
  • interface_linux.go: Linux固有の実装では、newAddr 関数内でNetlinkソケットから取得したアドレス情報 (ifam) のスコープ (ifam.Scope) が syscall.RT_SCOPE_HOST または syscall.RT_SCOPE_LINK である場合に Zone を設定していました。また、parseProcNetIGMP6 関数内でもマルチキャストアドレスの Zone 設定がありました。これらも削除されています。
  • ip.go: このファイルには IPNet 構造体の定義が含まれています。このコミットでは、IPNet 構造体から Zone string // IPv6 scoped addressing zone という行が削除されており、IPNet がゾーン情報を保持しないように変更されています。

これらの変更は、IPNet 構造体からゾーン情報の管理責任を一時的に外し、net パッケージ全体でIPv6スコープ付きアドレスのゾーン情報をどのように扱うべきかについて、再設計または再評価を行うための措置と考えられます。これにより、IPNet の役割をより明確にし、ゾーン情報の扱いは IPAddr など、より適切な構造体に集約される可能性があります。

関連リンク

参考にした情報源リンク