1. Qiita
  2. 投稿
  3. Go

GoのnetパッケージにおけるIPアドレスの内部表現

  • 6
    いいね
  • 0
    コメント
に投稿

GoのnetパッケージにおけるIPアドレスの内部表現

https://golang.org/src/net/ip.go

GoにおけるIPアドレスの内部表現については↑のファイルの冒頭に定義と解説がある。以下抜粋。

go/src/net/ip.go
// IP address manipulations                                                                                                                                   
//                                                                                                                                                            
// IPv4 addresses are 4 bytes; IPv6 addresses are 16 bytes.                                                                                                   
// An IPv4 address can be converted to an IPv6 address by                                                                                                     
// adding a canonical prefix (10 zeros, 2 0xFFs).                                                                                                             
// This library accepts either size of byte slice but always                                                                                                  
// returns 16-byte addresses.                                                                                                                                 

package net

// IP address lengths (bytes).                                                                                                                                
const (
        IPv4len = 4
        IPv6len = 16
)

// An IP is a single IP address, a slice of bytes.                                                                                                            
// Functions in this package accept either 4-byte (IPv4)                                                                                                      
// or 16-byte (IPv6) slices as input.                                                                                                                         
//                                                                                                                                                            
// Note that in this documentation, referring to an                                                                                                           
// IP address as an IPv4 address or an IPv6 address                                                                                                           
// is a semantic property of the address, not just the                                                                                                        
// length of the byte slice: a 16-byte slice can still                                                                                                        
// be an IPv4 address.                                                                                                                                        
type IP []byte

// An IP mask is an IP address.                                                                                                                               
type IPMask []byte

// An IPNet represents an IP network.                                                                                                                         
type IPNet struct {
        IP   IP     // network number                                                                                                                         
        Mask IPMask // network mask                                                                                                                           
}

GoではIPv4、IPv6アドレス共にIPという型で表現される。IPv4アドレスは4バイト、IPv6アドレスは16バイトだが、内部的にはIPv4アドレスであっても16バイトのバイト列で扱われる。

ip := net.ParseIP("8.8.8.8")
fmt.Println(len(ip)) // 16

net.ParseIP()はIPアドレスの文字列をIP型に変換する関数で、引数はIPv4、IPv6どちらのアドレスでも良い。GoのIPアドレス関連ユーティリティはこんな感じでIPv4とIPv6どちらのアドレスも一緒くたに扱うことができる。

なお、4バイトで表現されたIPv4アドレスが欲しい場合はTo4()関数を使う。

ip := net.ParseIP("8.8.8.8")
ipv4 := ip.To4()
fmt.Printf("%d.%d.%d.%d\n", ipv4[0], ipv4[1], ipv4[2], ipv4[3]) // 8.8.8.8
fmt.Println(len(ipv4)) // 4

また、16バイト表現によるIPv4アドレスはこんな感じで末尾の4バイトに実際の値が格納される。

go/src/net/ip.go
// IPv4 returns the IP address (in 16-byte form) of the                                                                                                       
// IPv4 address a.b.c.d.                                                                                                                                      
func IPv4(a, b, c, d byte) IP {
        p := make(IP, IPv6len)
        copy(p, v4InV6Prefix)
        p[12] = a
        p[13] = b
        p[14] = c
        p[15] = d
        return p
}

var v4InV6Prefix = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}

CIDRとサブネットマスク

10.0.0.0/24のようなCIDR表記のアドレス表現はIPNet、サブネットマスクはIPMaskで表現される。

go/src/net/ip.go
// An IP mask is an IP address.                                                                                                                               
type IPMask []byte

// An IPNet represents an IP network.                                                                                                                         
type IPNet struct {
        IP   IP     // network number                                                                                                                         
        Mask IPMask // network mask                                                                                                                           
}

CIDR表記の文字列をIPNet型に変換するにはnet.ParseCIDR()を使う。

ip, ipnet, err := net.ParseCIDR("10.0.0.0/24")
if err != nil {
        // error handling
}
fmt.Println(ipnet.IP) // 10.0.0.0
fmt.Println(ipnet.Mask) // ffffff00

これは例えば特定のIPアドレスが同じネットワークに所属しているかを調べるのに利用出来る。

_, ipnet, err := net.ParseCIDR("10.0.0.0/24")
if err != nil {
        // error handling
}
ip1 := net.ParseIP("10.0.0.1")
ip2 := net.ParseIP("10.1.0.1")
fmt.Println(ipnet.Contains(ip1)) // true
fmt.Println(ipnet.Contains(ip2)) // false