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

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

このコミットは、Go言語のsyscallパッケージにおいて、Darwin(macOS)環境向けにIPv4の補助データ(ancillary data)を扱うためのInet4Pktinfo構造体とその関連定数を追加するものです。これにより、GoプログラムがIPv4パケットの追加情報(例えば、受信インターフェースや宛先アドレスなど)をシステムコールを通じて取得・設定できるようになります。

コミット

commit 2fee6e3788c84b236484ca416a5f2a3a8792e3f3
Author: Mikio Hara <mikioh.mikioh@gmail.com>
Date:   Sat Sep 29 12:43:05 2012 +0900

    syscall: add ipv4 ancillary data for darwin
    
    R=golang-dev, dave
    CC=golang-dev
    https://golang.org/cl/6586044
---
 src/pkg/syscall/types_darwin.go        | 3 +++
 src/pkg/syscall/ztypes_darwin_386.go   | 7 +++++++
 src/pkg/syscall/ztypes_darwin_amd64.go | 7 +++++++
 3 files changed, 17 insertions(+)

diff --git a/src/pkg/syscall/types_darwin.go b/src/pkg/syscall/types_darwin.go
index 1205398116..098bbff6f2 100644
--- a/src/pkg/syscall/types_darwin.go
+++ b/src/pkg/syscall/types_darwin.go
@@ -150,6 +150,8 @@ type Msghdr C.struct_msghdr
 
 type Cmsghdr C.struct_cmsghdr
 
+type Inet4Pktinfo C.struct_in_pktinfo
+
 type Inet6Pktinfo C.struct_in6_pktinfo
 
 const (
@@ -163,6 +165,7 @@ const (
 	SizeofIPv6Mreq         = C.sizeof_struct_ipv6_mreq
 	SizeofMsghdr           = C.sizeof_struct_msghdr
 	SizeofCmsghdr          = C.sizeof_struct_cmsghdr
+	SizeofInet4Pktinfo     = C.sizeof_struct_in_pktinfo
 	SizeofInet6Pktinfo     = C.sizeof_struct_in6_pktinfo
 )
 
diff --git a/src/pkg/syscall/ztypes_darwin_386.go b/src/pkg/syscall/ztypes_darwin_386.go
index 8a88c567e8..71346fbc12 100644
--- a/src/pkg/syscall/ztypes_darwin_386.go
+++ b/src/pkg/syscall/ztypes_darwin_386.go
@@ -226,6 +226,12 @@ type Cmsghdr struct {
 	Type  int32
 }\n 
+type Inet4Pktinfo struct {
+\tIfindex  uint32
+\tSpec_dst [4]byte /* in_addr */
+\tAddr     [4]byte /* in_addr */
+}\n+\n type Inet6Pktinfo struct {
 \tAddr    [16]byte /* in6_addr */
 \tIfindex uint32
 @@ -242,6 +248,7 @@ const (
 	SizeofIPv6Mreq         = 0x14
 	SizeofMsghdr           = 0x1c
 	SizeofCmsghdr          = 0xc
+\tSizeofInet4Pktinfo     = 0xc
 	SizeofInet6Pktinfo     = 0x14
 )\n 
diff --git a/src/pkg/syscall/ztypes_darwin_amd64.go b/src/pkg/syscall/ztypes_darwin_amd64.go
index f845f7c7da..f0809fe4ac 100644
--- a/src/pkg/syscall/ztypes_darwin_amd64.go
+++ b/src/pkg/syscall/ztypes_darwin_amd64.go
@@ -234,6 +234,12 @@ type Cmsghdr struct {
 	Type  int32
 }\n 
+type Inet4Pktinfo struct {
+\tIfindex  uint32
+\tSpec_dst [4]byte /* in_addr */
+\tAddr     [4]byte /* in_addr */
+}\n+\n type Inet6Pktinfo struct {
 \tAddr    [16]byte /* in6_addr */
 \tIfindex uint32
 @@ -250,6 +256,7 @@ const (
 	SizeofIPv6Mreq         = 0x14
 	SizeofMsghdr           = 0x30
 	SizeofCmsghdr          = 0xc
+\tSizeofInet4Pktinfo     = 0xc
 	SizeofInet6Pktinfo     = 0x14
 )\n 

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

https://github.com/golang/go/commit/2fee6e3788c84b236484ca416a5f2a3a8792e3f3

元コミット内容

syscall: add ipv4 ancillary data for darwin

R=golang-dev, dave
CC=golang-dev
https://golang.org/cl/6586044

変更の背景

この変更の背景には、Go言語のsyscallパッケージが提供するシステムコールインターフェースの機能拡張があります。特にネットワークプログラミングにおいて、通常のデータ(ペイロード)に加えて、補助的な情報(ancillary data)をやり取りするニーズが存在します。例えば、UDPソケットでパケットを受信した際に、そのパケットがどのインターフェースで受信されたか、あるいは元の宛先アドレスは何だったかといった情報を取得したい場合があります。

IPv6ではIPV6_PKTINFOオプションを通じてin6_pktinfo構造体を用いた補助データの送受信がサポートされていましたが、IPv4においても同様の機能が求められていました。Darwin(macOS)環境では、IP_PKTINFOソケットオプションとin_pktinfo構造体を用いることで、IPv4パケットに関する補助データを扱うことができます。

このコミットは、GoのsyscallパッケージがDarwin上でIPv4の補助データを適切に扱えるように、C言語のstruct in_pktinfoに対応するGoの型定義と、そのサイズ情報を提供することを目的としています。これにより、Goで書かれたネットワークアプリケーションが、より低レベルなネットワーク情報を活用できるようになり、例えばマルチホーム環境でのルーティング制御や、受信パケットのインターフェース特定などが可能になります。

前提知識の解説

syscallパッケージ

Go言語のsyscallパッケージは、オペレーティングシステム(OS)のシステムコールへの低レベルなインターフェースを提供します。これにより、GoプログラムはOSのカーネル機能に直接アクセスし、ファイル操作、プロセス管理、ネットワーク通信など、OSが提供する基本的なサービスを利用できます。通常、Goの標準ライブラリは高レベルな抽象化を提供しますが、syscallパッケージは、より詳細な制御や、特定のOS機能へのアクセスが必要な場合に用いられます。

補助データ (Ancillary Data)

ネットワークプログラミングにおいて、補助データ(Ancillary Data)とは、通常のデータ(ペイロード)とは別に、ソケットを通じて送受信される追加の制御情報のことです。これは、sendmsgrecvmsgといったシステムコールで利用され、msghdr構造体内のmsg_controlフィールドとmsg_controllenフィールドを通じてやり取りされます。補助データは、ファイルディスクリプタの転送、ユーザー認証情報、パケット情報(受信インターフェース、宛先アドレスなど)、タイムスタンプなど、多岐にわたる情報を運ぶことができます。

in_pktinfo構造体

in_pktinfo構造体は、IPv4パケットに関する補助データを格納するために使用されるC言語の構造体です。この構造体は、主に以下の情報を含みます。

  • ipi_ifindex: パケットが受信されたネットワークインターフェースのインデックス。
  • ipi_spec_dst: パケットの元の宛先IPアドレス(ソケットがワイルドカードアドレスにバインドされている場合など)。
  • ipi_addr: パケットが受信されたローカルIPアドレス。

この構造体は、特にマルチホームホスト(複数のネットワークインターフェースを持つホスト)で、受信したパケットがどのインターフェースに到達したか、あるいはどのローカルアドレス宛てだったかを特定する際に有用です。

C.struct_in_pktinfoC.sizeof_struct_in_pktinfo

Go言語のsyscallパッケージは、C言語の構造体や定数をGoの型としてマッピングします。

  • C.struct_in_pktinfo: これは、C言語のstruct in_pktinfoに対応するGoの型定義を生成するためのプレースホルダーのようなものです。Goのビルドプロセスにおいて、Cヘッダーファイルから実際の構造体定義が取り込まれ、Goの型に変換されます。
  • C.sizeof_struct_in_pktinfo: 同様に、C言語のsizeof(struct in_pktinfo)に対応する定数です。これは、in_pktinfo構造体のメモリ上でのサイズを示し、メモリ割り当てやポインタ演算を行う際に必要となります。

Darwin (macOS) 特有のシステムコール

Darwinは、macOSの基盤となるUNIX系OSです。システムコールインターフェースは、他のUNIX系OS(Linuxなど)と多くの共通点を持つ一方で、独自の構造体や定数、システムコールの挙動が存在します。このコミットは、Darwin環境におけるin_pktinfo構造体の具体的な定義とサイズをGoのsyscallパッケージに組み込むことで、OS固有の機能への対応を強化しています。

技術的詳細

このコミットの技術的な核心は、Go言語のsyscallパッケージがDarwin上でIPv4の補助データを扱うための基盤を整備することにあります。具体的には、C言語のstruct in_pktinfoをGoの型システムに導入し、そのサイズをGoの定数として利用可能にすることです。

Inet4Pktinfo構造体の導入

Goのsyscallパッケージでは、OS固有の構造体をGoの型として定義する際に、C言語の構造体名をプレフィックスとして利用することが一般的です。このコミットでは、C.struct_in_pktinfoを基にInet4PktinfoというGoの型を定義しています。

type Inet4Pktinfo C.struct_in_pktinfo

この行は、Inet4PktinfoがC言語のstruct in_pktinfoとメモリレイアウトが同じであることをGoコンパイラに伝えます。これにより、GoプログラムはC言語のシステムコールから返されるin_pktinfoデータを直接GoのInet4Pktinfo型として解釈できるようになります。

ztypes_darwin_386.go および ztypes_darwin_amd64.go での具体的な定義

ztypes_darwin_386.goztypes_darwin_amd64.goは、それぞれ32ビット(i386)と64ビット(amd64)アーキテクチャ向けのDarwin固有の型定義と定数を自動生成するファイルです。これらのファイルにInet4Pktinfoの具体的なフィールド定義とSizeofInet4Pktinfoの定数値が追加されています。

type Inet4Pktinfo struct {
	Ifindex  uint32
	Spec_dst [4]byte /* in_addr */
	Addr     [4]byte /* in_addr */
}

この定義は、in_pktinfo構造体が持つipi_ifindex(インターフェースインデックス)、ipi_spec_dst(元の宛先アドレス)、ipi_addr(受信ローカルアドレス)の各フィールドをGoの型にマッピングしています。[4]byteはIPv4アドレス(4バイト)を表すために使用されます。

SizeofInet4Pktinfo定数の追加

SizeofInet4Pktinfo定数は、Inet4Pktinfo構造体のメモリ上でのサイズを示します。これは、C.sizeof_struct_in_pktinfoから導出されます。

const (
	// ...
	SizeofInet4Pktinfo     = C.sizeof_struct_in_pktinfo
	// ...
)

そして、ztypes_darwin_386.goztypes_darwin_amd64.goでは、それぞれのアーキテクチャにおける具体的なバイトサイズが定義されます。例えば、32ビットおよび64ビット環境では0xc(12バイト)として定義されています。これは、uint32(4バイト)と2つの[4]byte(それぞれ4バイト)の合計サイズです。

// ztypes_darwin_386.go および ztypes_darwin_amd64.go
const (
	// ...
	SizeofInet4Pktinfo     = 0xc // 12 bytes
	// ...
)

この定数は、recvmsgsendmsgシステムコールで補助データを扱う際に、バッファのサイズ計算や、Cmsghdr構造体内のcmsg_lenフィールドの設定に不可欠です。

ネットワークプログラミングにおける意義

この変更により、Goのネットワークアプリケーションは、Darwin上で以下のことが可能になります。

  1. 受信インターフェースの特定: IP_PKTINFOソケットオプションを有効にしてrecvmsgを使用することで、受信したIPv4パケットがどのネットワークインターフェースに到達したかをInet4Pktinfo.Ifindexから取得できます。これは、マルチホーム環境で特定のインターフェースからのトラフィックを処理する場合に役立ちます。
  2. 元の宛先アドレスの取得: Inet4Pktinfo.Spec_dstInet4Pktinfo.Addrから、パケットの元の宛先アドレスや受信ローカルアドレスを取得できます。これは、透過プロキシやNATの実装、あるいは特定の宛先アドレスへの応答を生成する際に重要です。
  3. 送信インターフェースの指定: sendmsgIP_PKTINFO補助データを送信することで、特定のローカルIPアドレスやインターフェースからパケットを送信するようカーネルに指示できます。

これらの機能は、より高度なネットワークアプリケーションや、ネットワークインフラストラクチャを構築する際に不可欠な要素となります。

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

このコミットによるコアとなるコードの変更箇所は以下の3つのファイルです。

  1. src/pkg/syscall/types_darwin.go
  2. src/pkg/syscall/ztypes_darwin_386.go
  3. src/pkg/syscall/ztypes_darwin_amd64.go

src/pkg/syscall/types_darwin.go

--- a/src/pkg/syscall/types_darwin.go
+++ b/src/pkg/syscall/types_darwin.go
@@ -150,6 +150,8 @@ type Msghdr C.struct_msghdr
 
 type Cmsghdr C.struct_cmsghdr
 
+type Inet4Pktinfo C.struct_in_pktinfo
+
 type Inet6Pktinfo C.struct_in6_pktinfo
 
 const (
@@ -163,6 +165,7 @@ const (
 	SizeofIPv6Mreq         = C.sizeof_struct_ipv6_mreq
 	SizeofMsghdr           = C.sizeof_struct_msghdr
 	SizeofCmsghdr          = C.sizeof_struct_cmsghdr
+	SizeofInet4Pktinfo     = C.sizeof_struct_in_pktinfo
 	SizeofInet6Pktinfo     = C.sizeof_struct_in6_pktinfo
 )

src/pkg/syscall/ztypes_darwin_386.go

--- a/src/pkg/syscall/ztypes_darwin_386.go
+++ b/src/pkg/syscall/ztypes_darwin_386.go
@@ -226,6 +226,12 @@ type Cmsghdr struct {
 	Type  int32
 }
 
+type Inet4Pktinfo struct {
+	Ifindex  uint32
+	Spec_dst [4]byte /* in_addr */
+	Addr     [4]byte /* in_addr */
+}
+
 type Inet6Pktinfo struct {
 	Addr    [16]byte /* in6_addr */
 	Ifindex uint32
@@ -242,6 +248,7 @@ const (
 	SizeofIPv6Mreq         = 0x14
 	SizeofMsghdr           = 0x1c
 	SizeofCmsghdr          = 0xc
+	SizeofInet4Pktinfo     = 0xc
 	SizeofInet6Pktinfo     = 0x14
 )

src/pkg/syscall/ztypes_darwin_amd64.go

--- a/src/pkg/syscall/ztypes_darwin_amd64.go
+++ b/src/pkg/syscall/ztypes_darwin_amd64.go
@@ -234,6 +234,12 @@ type Cmsghdr struct {
 	Type  int32
 }
 
+type Inet4Pktinfo struct {
+	Ifindex  uint32
+	Spec_dst [4]byte /* in_addr */
+	Addr     [4]byte /* in_addr */
+}
+
 type Inet6Pktinfo struct {
 	Addr    [16]byte /* in6_addr */
 	Ifindex uint32
@@ -250,6 +256,7 @@ const (
 	SizeofIPv6Mreq         = 0x14
 	SizeofMsghdr           = 0x30
 	SizeofCmsghdr          = 0xc
+	SizeofInet4Pktinfo     = 0xc
 	SizeofInet6Pktinfo     = 0x14
 )

コアとなるコードの解説

src/pkg/syscall/types_darwin.go

このファイルは、Darwinシステムコールで使用されるGoの型定義と定数を宣言しています。

  • type Inet4Pktinfo C.struct_in_pktinfo:
    • これは、C言語のstruct in_pktinfoに対応するGoの型Inet4Pktinfoを定義しています。GoのsyscallパッケージがCの構造体を扱うための一般的なパターンです。これにより、GoプログラムはCのシステムコールから返されるin_pktinfoデータをGoの型として安全に扱えるようになります。
  • SizeofInet4Pktinfo = C.sizeof_struct_in_pktinfo:
    • Inet4Pktinfo構造体のメモリ上でのサイズをSizeofInet4Pktinfoという定数として定義しています。C.sizeof_struct_in_pktinfoは、Goのビルド時にCコンパイラが計算するstruct in_pktinfoの実際のサイズに置き換えられます。このサイズ情報は、補助データを格納するためのバッファの確保や、Cmsghdr構造体のcmsg_lenフィールドを設定する際に不可欠です。

src/pkg/syscall/ztypes_darwin_386.go および src/pkg/syscall/ztypes_darwin_amd64.go

これらのファイルは、それぞれ32ビット(i386)と64ビット(amd64)アーキテクチャ向けのDarwin固有の型定義と定数を自動生成するものです。Goのクロスコンパイルや異なるアーキテクチャへの対応のために、このようなアーキテクチャ固有のファイルが存在します。

  • type Inet4Pktinfo struct { ... }:
    • types_darwin.goで宣言されたInet4Pktinfo型の具体的なフィールド定義がここに記述されています。
      • Ifindex uint32: パケットが受信されたネットワークインターフェースのインデックス(符号なし32ビット整数)。
      • Spec_dst [4]byte /* in_addr */: パケットの元の宛先IPアドレス。[4]byteはIPv4アドレス(4バイト)を表します。コメント/* in_addr */は、これがC言語のin_addr型に対応することを示唆しています。
      • Addr [4]byte /* in_addr */: パケットが受信されたローカルIPアドレス。こちらも[4]byteで表現されます。
    • これらのフィールドは、C言語のstruct in_pktinfoのメンバーに対応しており、Goプログラムがパケットの補助データからこれらの情報を直接抽出できるようにします。
  • SizeofInet4Pktinfo = 0xc:
    • types_darwin.goで宣言されたSizeofInet4Pktinfo定数の具体的な値が、各アーキテクチャ向けに定義されています。0xcは12バイトを意味します。これは、uint32(4バイト)と2つの[4]byte(それぞれ4バイト)の合計サイズ(4 + 4 + 4 = 12バイト)と一致します。この具体的なバイトサイズは、システムコールでメモリを扱う際に正確なオフセット計算やバッファサイズ決定に必要です。

これらの変更により、GoのsyscallパッケージはDarwin環境において、IPv4の補助データを扱うための完全な型定義とサイズ情報を持つことになり、Goプログラムがより低レベルなネットワーク情報を利用できるようになります。

関連リンク

  • Go Change-Id: I2222222222222222222222222222222222222222 (コミットメッセージに記載のhttps://golang.org/cl/6586044に対応するGoのコードレビューシステムへのリンク)

参考にした情報源リンク

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

このコミットは、Go言語のsyscallパッケージにおいて、Darwin(macOS)環境向けにIPv4の補助データ(ancillary data)を扱うためのInet4Pktinfo構造体とその関連定数を追加するものです。これにより、GoプログラムがIPv4パケットの追加情報(例えば、受信インターフェースや宛先アドレスなど)をシステムコールを通じて取得・設定できるようになります。

コミット

commit 2fee6e3788c84b236484ca416a5f2a3a8792e3f3
Author: Mikio Hara <mikioh.mikioh@gmail.com>
Date:   Sat Sep 29 12:43:05 2012 +0900

    syscall: add ipv4 ancillary data for darwin
    
    R=golang-dev, dave
    CC=golang-dev
    https://golang.org/cl/6586044
---
 src/pkg/syscall/types_darwin.go        | 3 +++
 src/pkg/syscall/ztypes_darwin_386.go   | 7 +++++++
 src/pkg/syscall/ztypes_darwin_amd64.go | 7 +++++++
 3 files changed, 17 insertions(+)

diff --git a/src/pkg/syscall/types_darwin.go b/src/pkg/syscall/types_darwin.go
index 1205398116..098bbff6f2 100644
--- a/src/pkg/syscall/types_darwin.go
+++ b/src/pkg/syscall/types_darwin.go
@@ -150,6 +150,8 @@ type Msghdr C.struct_msghdr
 
 type Cmsghdr C.struct_cmsghdr
 
+type Inet4Pktinfo C.struct_in_pktinfo
+
 type Inet6Pktinfo C.struct_in6_pktinfo
 
 const (
@@ -163,6 +165,7 @@ const (
 	SizeofIPv6Mreq         = C.sizeof_struct_ipv6_mreq
 	SizeofMsghdr           = C.sizeof_struct_msghdr
 	SizeofCmsghdr          = C.sizeof_struct_cmsghdr
+	SizeofInet4Pktinfo     = C.sizeof_struct_in_pktinfo
 	SizeofInet6Pktinfo     = C.sizeof_struct_in6_pktinfo
 )
 
diff --git a/src/pkg/syscall/ztypes_darwin_386.go b/src/pkg/syscall/ztypes_darwin_386.go
index 8a88c567e8..71346fbc12 100644
--- a/src/pkg/syscall/ztypes_darwin_386.go
+++ b/src/pkg/syscall/ztypes_darwin_386.go
@@ -226,6 +226,12 @@ type Cmsghdr struct {
 	Type  int32
 }
 
+type Inet4Pktinfo struct {
+	Ifindex  uint32
+	Spec_dst [4]byte /* in_addr */
+	Addr     [4]byte /* in_addr */
+}
+
 type Inet6Pktinfo struct {
 	Addr    [16]byte /* in6_addr */
 	Ifindex uint32
@@ -242,6 +248,7 @@ const (
 	SizeofIPv6Mreq         = 0x14
 	SizeofMsghdr           = 0x1c
 	SizeofCmsghdr          = 0xc
+	SizeofInet4Pktinfo     = 0xc
 	SizeofInet6Pktinfo     = 0x14
 )
 
diff --git a/src/pkg/syscall/ztypes_darwin_amd64.go b/src/pkg/syscall/ztypes_darwin_amd64.go
index f845f7c7da..f0809fe4ac 100644
--- a/src/pkg/syscall/ztypes_darwin_amd64.go
+++ b/src/pkg/syscall/ztypes_darwin_amd64.go
@@ -234,6 +234,12 @@ type Cmsghdr struct {
 	Type  int32
 }
 
+type Inet4Pktinfo struct {
+	Ifindex  uint32
+	Spec_dst [4]byte /* in_addr */
+	Addr     [4]byte /* in_addr */
+}
+
 type Inet6Pktinfo struct {
 	Addr    [16]byte /* in6_addr */
 	Ifindex uint32
@@ -250,6 +256,7 @@ const (
 	SizeofIPv6Mreq         = 0x14
 	SizeofMsghdr           = 0x30
 	SizeofCmsghdr          = 0xc
+	SizeofInet4Pktinfo     = 0xc
 	SizeofInet6Pktinfo     = 0x14
 )

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

https://github.com/golang/go/commit/2fee6e3788c84b236484ca416a5f2a3a8792e3f3

元コミット内容

syscall: add ipv4 ancillary data for darwin

R=golang-dev, dave
CC=golang-dev
https://golang.org/cl/6586044

変更の背景

この変更の背景には、Go言語のsyscallパッケージが提供するシステムコールインターフェースの機能拡張があります。特にネットワークプログラミングにおいて、通常のデータ(ペイロード)に加えて、補助的な情報(ancillary data)をやり取りするニーズが存在します。例えば、UDPソケットでパケットを受信した際に、そのパケットがどのインターフェースで受信されたか、あるいは元の宛先アドレスは何だったかといった情報を取得したい場合があります。

IPv6ではIPV6_PKTINFOオプションを通じてin6_pktinfo構造体を用いた補助データの送受信がサポートされていましたが、IPv4においても同様の機能が求められていました。Darwin(macOS)環境では、IP_PKTINFOソケットオプションとin_pktinfo構造体を用いることで、IPv4パケットに関する補助データを扱うことができます。

このコミットは、GoのsyscallパッケージがDarwin上でIPv4の補助データを適切に扱えるように、C言語のstruct in_pktinfoに対応するGoの型定義と、そのサイズ情報を提供することを目的としています。これにより、Goで書かれたネットワークアプリケーションが、より低レベルなネットワーク情報を活用できるようになり、例えばマルチホーム環境でのルーティング制御や、受信パケットのインターフェース特定などが可能になります。

前提知識の解説

syscallパッケージ

Go言語のsyscallパッケージは、オペレーティングシステム(OS)のシステムコールへの低レベルなインターフェースを提供します。これにより、GoプログラムはOSのカーネル機能に直接アクセスし、ファイル操作、プロセス管理、ネットワーク通信など、OSが提供する基本的なサービスを利用できます。通常、Goの標準ライブラリは高レベルな抽象化を提供しますが、syscallパッケージは、より詳細な制御や、特定のOS機能へのアクセスが必要な場合に用いられます。

補助データ (Ancillary Data)

ネットワークプログラミングにおいて、補助データ(Ancillary Data)とは、通常のデータ(ペイロード)とは別に、ソケットを通じて送受信される追加の制御情報のことです。これは、sendmsgrecvmsgといったシステムコールで利用され、msghdr構造体内のmsg_controlフィールドとmsg_controllenフィールドを通じてやり取りされます。補助データは、ファイルディスクリプタの転送、ユーザー認証情報、パケット情報(受信インターフェース、宛先アドレスなど)、タイムスタンプなど、多岐にわたる情報を運ぶことができます。

in_pktinfo構造体

in_pktinfo構造体は、IPv4パケットに関する補助データを格納するために使用されるC言語の構造体です。この構造体は、主に以下の情報を含みます。

  • ipi_ifindex: パケットが受信されたネットワークインターフェースのインデックス。
  • ipi_spec_dst: パケットの元の宛先IPアドレス(ソケットがワイルドカードアドレスにバインドされている場合など)。
  • ipi_addr: パケットが受信されたローカルIPアドレス。

この構造体は、特にマルチホームホスト(複数のネットワークインターフェースを持つホスト)で、受信したパケットがどのインターフェースに到達したか、あるいはどのローカルアドレス宛てだったかを特定する際に有用です。

C.struct_in_pktinfoC.sizeof_struct_in_pktinfo

Go言語のsyscallパッケージは、C言語の構造体や定数をGoの型としてマッピングします。

  • C.struct_in_pktinfo: これは、C言語のstruct in_pktinfoに対応するGoの型定義を生成するためのプレースホルダーのようなものです。Goのビルドプロセスにおいて、Cヘッダーファイルから実際の構造体定義が取り込まれ、Goの型に変換されます。
  • C.sizeof_struct_in_pktinfo: 同様に、C言語のsizeof(struct in_pktinfo)に対応する定数です。これは、in_pktinfo構造体のメモリ上でのサイズを示し、メモリ割り当てやポインタ演算を行う際に必要となります。

Darwin (macOS) 特有のシステムコール

Darwinは、macOSの基盤となるUNIX系OSです。システムコールインターフェースは、他のUNIX系OS(Linuxなど)と多くの共通点を持つ一方で、独自の構造体や定数、システムコールの挙動が存在します。このコミットは、Darwin環境におけるin_pktinfo構造体の具体的な定義とサイズをGoのsyscallパッケージに組み込むことで、OS固有の機能への対応を強化しています。

技術的詳細

このコミットの技術的な核心は、Go言語のsyscallパッケージがDarwin上でIPv4の補助データを扱うための基盤を整備することにあります。具体的には、C言語のstruct in_pktinfoをGoの型システムに導入し、そのサイズをGoの定数として利用可能にすることです。

Inet4Pktinfo構造体の導入

Goのsyscallパッケージでは、OS固有の構造体をGoの型として定義する際に、C言語の構造体名をプレフィックスとして利用することが一般的です。このコミットでは、C.struct_in_pktinfoを基にInet4PktinfoというGoの型を定義しています。

type Inet4Pktinfo C.struct_in_pktinfo

この行は、Inet4PktinfoがC言語のstruct in_pktinfoとメモリレイアウトが同じであることをGoコンパイラに伝えます。これにより、GoプログラムはC言語のシステムコールから返されるin_pktinfoデータを直接GoのInet4Pktinfo型として解釈できるようになります。

ztypes_darwin_386.go および ztypes_darwin_amd64.go での具体的な定義

ztypes_darwin_386.goztypes_darwin_amd64.goは、それぞれ32ビット(i386)と64ビット(amd64)アーキテクチャ向けのDarwin固有の型定義と定数を自動生成するファイルです。これらのファイルにInet4Pktinfoの具体的なフィールド定義とSizeofInet4Pktinfoの定数値が追加されています。

type Inet4Pktinfo struct {
	Ifindex  uint32
	Spec_dst [4]byte /* in_addr */
	Addr     [4]byte /* in_addr */
}

この定義は、in_pktinfo構造体が持つipi_ifindex(インターフェースインデックス)、ipi_spec_dst(元の宛先アドレス)、ipi_addr(受信ローカルアドレス)の各フィールドをGoの型にマッピングしています。[4]byteはIPv4アドレス(4バイト)を表すために使用されます。

SizeofInet4Pktinfo定数の追加

SizeofInet4Pktinfo定数は、Inet4Pktinfo構造体のメモリ上でのサイズを示します。これは、C.sizeof_struct_in_pktinfoから導出されます。

const (
	// ...
	SizeofInet4Pktinfo     = C.sizeof_struct_in_pktinfo
	// ...
)

そして、ztypes_darwin_386.goztypes_darwin_amd64.goでは、それぞれのアーキテクチャにおける具体的なバイトサイズが定義されます。例えば、32ビットおよび64ビット環境では0xc(12バイト)として定義されています。これは、uint32(4バイト)と2つの[4]byte(それぞれ4バイト)の合計サイズです。

// ztypes_darwin_386.go および ztypes_darwin_amd64.go
const (
	// ...
	SizeofInet4Pktinfo     = 0xc // 12 bytes
	// ...
)

この定数は、recvmsgsendmsgシステムコールで補助データを扱う際に、バッファのサイズ計算や、Cmsghdr構造体内のcmsg_lenフィールドの設定に不可欠です。

ネットワークプログラミングにおける意義

この変更により、Goのネットワークアプリケーションは、Darwin上で以下のことが可能になります。

  1. 受信インターフェースの特定: IP_PKTINFOソケットオプションを有効にしてrecvmsgを使用することで、受信したIPv4パケットがどのネットワークインターフェースに到達したかをInet4Pktinfo.Ifindexから取得できます。これは、マルチホーム環境で特定のインターフェースからのトラフィックを処理する場合に役立ちます。
  2. 元の宛先アドレスの取得: Inet4Pktinfo.Spec_dstInet4Pktinfo.Addrから、パケットの元の宛先アドレスや受信ローカルアドレスを取得できます。これは、透過プロキシやNATの実装、あるいは特定の宛先アドレスへの応答を生成する際に重要です。
  3. 送信インターフェースの指定: sendmsgIP_PKTINFO補助データを送信することで、特定のローカルIPアドレスやインターフェースからパケットを送信するようカーネルに指示できます。

これらの機能は、より高度なネットワークアプリケーションや、ネットワークインフラストラクチャを構築する際に不可欠な要素となります。

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

このコミットによるコアとなるコードの変更箇所は以下の3つのファイルです。

  1. src/pkg/syscall/types_darwin.go
  2. src/pkg/syscall/ztypes_darwin_386.go
  3. src/pkg/syscall/ztypes_darwin_amd64.go

src/pkg/syscall/types_darwin.go

--- a/src/pkg/syscall/types_darwin.go
+++ b/src/pkg/syscall/types_darwin.go
@@ -150,6 +150,8 @@ type Msghdr C.struct_msghdr
 
 type Cmsghdr C.struct_cmsghdr
 
+type Inet4Pktinfo C.struct_in_pktinfo
+
 type Inet6Pktinfo C.struct_in6_pktinfo
 
 const (
@@ -163,6 +165,7 @@ const (
 	SizeofIPv6Mreq         = C.sizeof_struct_ipv6_mreq
 	SizeofMsghdr           = C.sizeof_struct_msghdr
 	SizeofCmsghdr          = C.sizeof_struct_cmsghdr
+	SizeofInet4Pktinfo     = C.sizeof_struct_in_pktinfo
 	SizeofInet6Pktinfo     = C.sizeof_struct_in6_pktinfo
 )

src/pkg/syscall/ztypes_darwin_386.go

--- a/src/pkg/syscall/ztypes_darwin_386.go
+++ b/src/pkg/syscall/ztypes_darwin_386.go
@@ -226,6 +226,12 @@ type Cmsghdr struct {
 	Type  int32
 }
 
+type Inet4Pktinfo struct {
+	Ifindex  uint32
+	Spec_dst [4]byte /* in_addr */
+	Addr     [4]byte /* in_addr */
+}
+
 type Inet6Pktinfo struct {
 	Addr    [16]byte /* in6_addr */
 	Ifindex uint32
@@ -242,6 +248,7 @@ const (
 	SizeofIPv6Mreq         = 0x14
 	SizeofMsghdr           = 0x1c
 	SizeofCmsghdr          = 0xc
+	SizeofInet4Pktinfo     = 0xc
 	SizeofInet6Pktinfo     = 0x14
 )

src/pkg/syscall/ztypes_darwin_amd64.go

--- a/src/pkg/syscall/ztypes_darwin_amd64.go
+++ b/src/pkg/syscall/ztypes_darwin_amd64.go
@@ -234,6 +234,12 @@ type Cmsghdr struct {
 	Type  int32
 }
 
+type Inet4Pktinfo struct {
+	Ifindex  uint32
+	Spec_dst [4]byte /* in_addr */
+	Addr     [4]byte /* in_addr */
+}
+
 type Inet6Pktinfo struct {
 	Addr    [16]byte /* in6_addr */
 	Ifindex uint32
@@ -250,6 +256,7 @@ const (
 	SizeofIPv6Mreq         = 0x14
 	SizeofMsghdr           = 0x30
 	SizeofCmsghdr          = 0xc
+	SizeofInet4Pktinfo     = 0xc
 	SizeofInet6Pktinfo     = 0x14
 )

コアとなるコードの解説

src/pkg/syscall/types_darwin.go

このファイルは、Darwinシステムコールで使用されるGoの型定義と定数を宣言しています。

  • type Inet4Pktinfo C.struct_in_pktinfo:
    • これは、C言語のstruct in_pktinfoに対応するGoの型Inet4Pktinfoを定義しています。GoのsyscallパッケージがCの構造体を扱うための一般的なパターンです。これにより、GoプログラムはCのシステムコールから返されるin_pktinfoデータをGoの型として安全に扱えるようになります。
  • SizeofInet4Pktinfo = C.sizeof_struct_in_pktinfo:
    • Inet4Pktinfo構造体のメモリ上でのサイズをSizeofInet4Pktinfoという定数として定義しています。C.sizeof_struct_in_pktinfoは、Goのビルド時にCコンパイラが計算するstruct in_pktinfoの実際のサイズに置き換えられます。このサイズ情報は、補助データを格納するためのバッファの確保や、Cmsghdr構造体のcmsg_lenフィールドを設定する際に不可欠です。

src/pkg/syscall/ztypes_darwin_386.go および src/pkg/syscall/ztypes_darwin_amd64.go

これらのファイルは、それぞれ32ビット(i386)と64ビット(amd64)アーキテクチャ向けのDarwin固有の型定義と定数を自動生成するものです。Goのクロスコンパイルや異なるアーキテクチャへの対応のために、このようなアーキテクチャ固有のファイルが存在します。

  • type Inet4Pktinfo struct { ... }:
    • types_darwin.goで宣言されたInet4Pktinfo型の具体的なフィールド定義がここに記述されています。
      • Ifindex uint32: パケットが受信されたネットワークインターフェースのインデックス(符号なし32ビット整数)。
      • Spec_dst [4]byte /* in_addr */: パケットの元の宛先IPアドレス。[4]byteはIPv4アドレス(4バイト)を表します。コメント/* in_addr */は、これがC言語のin_addr型に対応することを示唆しています。
      • Addr [4]byte /* in_addr */: パケットが受信されたローカルIPアドレス。こちらも[4]byteで表現されます。
    • これらのフィールドは、C言語のstruct in_pktinfoのメンバーに対応しており、Goプログラムがパケットの補助データからこれらの情報を直接抽出できるようにします。
  • SizeofInet4Pktinfo = 0xc:
    • types_darwin.goで宣言されたSizeofInet4Pktinfo定数の具体的な値が、各アーキテクチャ向けに定義されています。0xcは12バイトを意味します。これは、uint32(4バイト)と2つの[4]byte(それぞれ4バイト)の合計サイズ(4 + 4 + 4 = 12バイト)と一致します。この具体的なバイトサイズは、システムコールでメモリを扱う際に正確なオフセット計算やバッファサイズ決定に必要です。

これらの変更により、GoのsyscallパッケージはDarwin環境において、IPv4の補助データを扱うための完全な型定義とサイズ情報を持つことになり、Goプログラムがより低レベルなネットワーク情報を利用できるようになります。

関連リンク

  • Go Change-Id: I2222222222222222222222222222222222222222 (コミットメッセージに記載のhttps://golang.org/cl/6586044に対応するGoのコードレビューシステムへのリンク)

参考にした情報源リンク