開発で利用しているUbuntu環境のIPアドレスとMacアドレスを取得したいと思い、Go言語は書いたことがないので、ChatGPTに聞きながら実装してみた記録です。
ということでChatGPTにこんな質問をしてみました。
Go言語でローカルのネットワークインターフェースの情報を取得したい。
取得したい情報は、外部ネットワークと通信可能なIPアドレスとMacアドレスです。
有線LANが利用可能だがLANケーブルが接続されていない場合や、無線WiFiが利用可能だが無効化されている場合には取得対象とはしない。
なお、有線LANや無線WiFiのネットワークインターフェースが複数存在する場合にも対応したい。
以下の回答が得られました。
Go言語で指定された条件に合うネットワークインターフェースの情報を取得するには、標準ライブラリの
net
パッケージを使用して実装できます。以下のコードは、外部ネットワークに接続可能なインターフェースのIPアドレスとMACアドレスを取得する方法を示しています。
実装例
package main
import (
"fmt"
"net"
)
func main() {
interfaces, err := net.Interfaces()
if err != nil {
fmt.Println("Error fetching interfaces:", err)
return
}
for _, iface := range interfaces {
// インターフェースが無効か、ループバックである場合はスキップ
if iface.Flags&net.FlagUp == 0 || iface.Flags&net.FlagLoopback != 0 {
continue
}
// IPアドレス情報を取得
addrs, err := iface.Addrs()
if err != nil {
fmt.Printf("Error fetching addresses for interface %s: %v\n", iface.Name, err)
continue
}
for _, addr := range addrs {
var ip net.IP
switch v := addr.(type) {
case *net.IPNet:
ip = v.IP
case *net.IPAddr:
ip = v.IP
}
// IPv4のみを対象
if ip == nil || ip.IsLoopback() || !ip.IsGlobalUnicast() || ip.To4() == nil {
continue
}
fmt.Printf("Interface: %s\n", iface.Name)
fmt.Printf(" IP Address: %s\n", ip.String())
fmt.Printf(" MAC Address: %s\n", iface.HardwareAddr.String())
}
}
}
提示されたコードを実行してみると、なんかたくさん表示されました。
利用しているUbuntu環境では有線LANと無線WiFiが利用可能な状態ですが、LANケーブルを接続していない有線LANは表示されておらず、無線WiFiの情報が表示されているところまでは意図通りな動作ですが、関係なさそうなインターフェースが大量に表示されています。
$ go run main.go
Interface: wlp44s0
IP Address: 192.168.XXX.XXX
MAC Address: 4c:d5:XX:XX:XX:XX
Interface: br-XXXXXXXXXXXX
IP Address: 172.21.XXX.XXX
MAC Address: 02:42:XX:XX:XX:XX
Interface: br-XXXXXXXXXXXX
IP Address: 172.23.XXX.XXX
MAC Address: 02:42:XX:XX:XX:XX
Interface: br-XXXXXXXXXXXX
IP Address: 172.27.XXX.XXX
MAC Address: 02:42:XX:XX:XX:XX
Interface: br-XXXXXXXXXXXX
IP Address: 172.26.XXX.XXX
MAC Address: 02:42:XX:XX:XX:XX
Interface: docker0
IP Address: 172.17.XXX.XXX
MAC Address: 02:42:XX:XX:XX:XX
Interface: br-XXXXXXXXXXXX
IP Address: 172.29.XXX.XXX
MAC Address: 02:42:XX:XX:XX:XX
Interface: br-XXXXXXXXXXXX
IP Address: 172.22.XXX.XXX
MAC Address: 02:42:XX:XX:XX:XX
Interface: br-XXXXXXXXXXXX
IP Address: 172.28.XXX.XXX
MAC Address: 02:42:XX:XX:XX:XX
Interface: br-XXXXXXXXXXXX
IP Address: 172.20.XXX.XXX
MAC Address: 02:42:XX:XX:XX:XX
Interface: br-XXXXXXXXXXXX
IP Address: 172.24.XXX.XXX
MAC Address: 02:42:XX:XX:XX:XX
Interface: br-XXXXXXXXXXXX
IP Address: 172.18.XXX.XXX
MAC Address: 02:42:XX:XX:XX:XX
Interface: br-XXXXXXXXXXXX
IP Address: 172.19.XXX.XXX
MAC Address: 02:42:XX:XX:XX:XX
Interface: br-XXXXXXXXXXXX
IP Address: 192.168.XXX.XXX
MAC Address: 02:42:XX:XX:XX:XX
Interface: br-XXXXXXXXXXXX
IP Address: 172.25.XXX.XXX
MAC Address: 02:42:XX:XX:XX:XX
関係なさそうなインターフェースは、恐らくDockerで利用しているものでは?と予想できたので、こんな風に返信しました。
Dockerで利用しているネットワークインターフェースは除外したいです。
以下の回答が得られました。
Dockerのネットワークインターフェースを除外するためには、
net.Interface
構造体のName
フィールドを使用してインターフェース名に基づくフィルタリングを追加するのが簡単です。通常、Dockerで使用されるインターフェース名はdocker0
やbr-*
(ブリッジネットワーク)などのパターンです。以下に、Dockerのネットワークインターフェースを除外するコードを示します。
改良版コード
package main
import (
"fmt"
"net"
"strings"
)
func main() {
interfaces, err := net.Interfaces()
if err != nil {
fmt.Println("Error fetching interfaces:", err)
return
}
for _, iface := range interfaces {
// インターフェースが無効か、ループバック、またはDocker関連の場合はスキップ
if iface.Flags&net.FlagUp == 0 || iface.Flags&net.FlagLoopback != 0 || isDockerInterface(iface.Name) {
continue
}
// IPアドレス情報を取得
addrs, err := iface.Addrs()
if err != nil {
fmt.Printf("Error fetching addresses for interface %s: %v\n", iface.Name, err)
continue
}
for _, addr := range addrs {
var ip net.IP
switch v := addr.(type) {
case *net.IPNet:
ip = v.IP
case *net.IPAddr:
ip = v.IP
}
// IPv4のみを対象
if ip == nil || ip.IsLoopback() || !ip.IsGlobalUnicast() || ip.To4() == nil {
continue
}
fmt.Printf("Interface: %s\n", iface.Name)
fmt.Printf(" IP Address: %s\n", ip.String())
fmt.Printf(" MAC Address: %s\n", iface.HardwareAddr.String())
}
}
}
// Docker関連のインターフェース名を判定するヘルパー関数
func isDockerInterface(name string) bool {
// Dockerで使われる典型的なインターフェース名
dockerPrefixes := []string{"docker", "br-", "veth", "tunl", "flannel"}
for _, prefix := range dockerPrefixes {
if strings.HasPrefix(name, prefix) {
return true
}
}
return false
}
実行してみると、意図通り無線WiFiのネットワークインターフェースのみが表示されるようになりました。
$ go run main.go
Interface: wlp44s0
IP Address: 192.168.XXX.XXX
MAC Address: 4c:d5:XX:XX:XX:XX