🙆

Go言語でのIPアドレスの扱い方

2024/10/04に公開

はじめに

このページではGo言語でのIPアドレスの扱い方について記述します。

1. IPアドレスのパースと生成

Go言語では標準ライブラリの net パッケージを使用して、IPアドレスの操作を簡単に行うことができます。

IPアドレスのパース

net.ParseIP 関数を使って、文字列からIPアドレスをパースすることができます。

package main

import (
	"fmt"
	"net"
)

func main() {
	ip := net.ParseIP("192.168.1.1")
	if ip == nil {
		fmt.Println("Invalid IP address")
	} else {
		fmt.Println("Parsed IP:", ip)
	}
}

IPv4だけでなく、IPv6のパースも同様に行うことができます。

ip := net.ParseIP("::1") // IPv6

IPアドレスの生成

生成する場合、net.IP 型を直接使用してIPアドレスを作成できます。例えば、以下のように4バイト配列でIPv4アドレスを生成します。

ip := net.IPv4(192, 168, 1, 1)
fmt.Println("Generated IP:", ip)

2. IPアドレスのチェック

GoではIPアドレスの種類を確認するためのメソッドがいくつか用意されています。

  • IsLoopback(): ループバックアドレスかどうか確認
  • IsPrivate(): プライベートアドレスかどうか確認
  • IsGlobalUnicast(): グローバルユニキャストアドレスかどうか確認
package main

import (
	"fmt"
	"net"
)

func main() {
	ip := net.ParseIP("192.168.1.1")
	if ip.IsPrivate() {
		fmt.Println("This is a private IP address")
	}
}

3. ホスト名からIPアドレスを解決

net.LookupIP を使うことで、ホスト名からIPアドレスを取得することができます。

package main

import (
	"fmt"
	"net"
)

func main() {
	ips, err := net.LookupIP("example.com")
	if err != nil {
		fmt.Println("Failed to lookup IP:", err)
		return
	}
	for _, ip := range ips {
		fmt.Println("IP address:", ip)
	}
}

4. CIDRブロックでのIPアドレスの扱い

CIDR (Classless Inter-Domain Routing) ブロックでIPアドレスを扱う場合、net.IPNet 型を使用します。ParseCIDR 関数を使ってCIDRブロックをパースすることができます。

package main

import (
	"fmt"
	"net"
)

func main() {
	_, ipNet, err := net.ParseCIDR("192.168.0.0/16")
	if err != nil {
		fmt.Println("Invalid CIDR block:", err)
		return
	}
	fmt.Println("CIDR block:", ipNet)
}

CIDRブロック内に特定のIPアドレスが含まれているかを確認するには、Contains メソッドを使用します。

ip := net.ParseIP("192.168.1.1")
if ipNet.Contains(ip) {
	fmt.Println("IP is within the CIDR block")
}

5. IPアドレスの比較

net.IP 型のIPアドレス同士を比較する場合、Goの標準比較演算子 == は使えません。代わりに Equal メソッドを使用します。

package main

import (
	"fmt"
	"net"
)

func main() {
	ip1 := net.ParseIP("192.168.1.1")
	ip2 := net.ParseIP("192.168.1.1")
	if ip1.Equal(ip2) {
		fmt.Println("The IP addresses are equal")
	} else {
		fmt.Println("The IP addresses are not equal")
	}
}

6. IPアドレス制限をかけたAPIの実装例

特定のIPアドレスからのアクセスのみ許可するAPIの例を以下に示します。net.ParseIP を使ってアクセス元のIPアドレスをチェックします。

package main

import (
	"fmt"
	"net"
	"net/http"
)

func main() {
	allowedIP := net.ParseIP("192.168.1.1")

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		ip, _, err := net.SplitHostPort(r.RemoteAddr)
		if err != nil {
			http.Error(w, "Invalid IP address", http.StatusForbidden)
			return
		}

		clientIP := net.ParseIP(ip)
		if clientIP == nil || !clientIP.Equal(allowedIP) {
			http.Error(w, "Forbidden", http.StatusForbidden)
			return
		}

		fmt.Fprintf(w, "Hello, %s", clientIP)
	})

	http.ListenAndServe(":8080", nil)
}

7. CIDRブロックを使ったIP制限

特定のCIDRブロック内のIPアドレスからのみアクセスを許可する例です。

package main

import (
	"fmt"
	"net"
	"net/http"
)

func main() {
	_, allowedCIDR, _ := net.ParseCIDR("192.168.0.0/16")

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		ip, _, err := net.SplitHostPort(r.RemoteAddr)
		if err != nil {
			http.Error(w, "Invalid IP address", http.StatusForbidden)
			return
		}

		clientIP := net.ParseIP(ip)
		if clientIP == nil || !allowedCIDR.Contains(clientIP) {
			http.Error(w, "Forbidden", http.StatusForbidden)
			return
		}

		fmt.Fprintf(w, "Hello, %s", clientIP)
	})

	http.ListenAndServe(":8080", nil)
}

まとめ

Go言語では、net パッケージを使ってIPアドレスの操作やチェック、CIDRブロックでの扱いが簡単に行えます。また、IP制限をかけたAPIの実装も可能です。

Discussion