関連記事
Goメモ-306 (go-packetメモ-01)(ネットワークインターフェースを表示) - いろいろ備忘録日記
Goメモ-307 (go-packetメモ-02)(流れるパケットをキャプチャする)(OpenLive) - いろいろ備忘録日記
GitHub - devlights/blog-summary: ブログ「いろいろ備忘録日記」のまとめ
概要
以下、自分用のメモです。忘れないうちにメモメモ。。。
GoでWireSharkやtcpdumpのようにパケットを直接見たいときなどに利用できるライブラリに
というのがあります。
今まで使ったこと無かったのですが、使うと面白かったので自分用のメモ代わりにちょこちょこ残しておこうと思います。
Linux (Ubuntu) 上で遊んでいますので、Windowsの場合はWinPcap (WireSharkをインストールするときについでにインストールできたはず)が必要になると思います。
インストール
libpcap
が必要ですので、以下でインストールします。
$ sudo apt install libpcap-dev
あと、tcpdumpが入っていない場合は以下もついでに入れておきます。(これはオプショナルです)
$ sudo apt install tcpdump
試してみる
使い方に関しては、上に挙げている go-packet の godoc の方に詳しく書かれています。
今回は、キャプチャした結果が格納されている pcap ファイルを読み込んで表示してみます。
pcap.OpenOffline
関数を使います。
// Package main is the example of pcap.OpenOffline() package main import ( "fmt" "log" "os" "os/signal" "github.com/google/gopacket" "github.com/google/gopacket/pcap" ) var ( appLog = log.New(os.Stderr, "", 0) ) func main() { if err := run(); err != nil { panic(err) } } func run() error { const ( pcapfile = "example.pcap" filter = "" ) defer func() { appLog.Println("DONE") }() // -------------------------------------- // Open capture handle // -------------------------------------- var ( handle *pcap.Handle err error ) handle, err = pcap.OpenOffline(pcapfile) if err != nil { return fmt.Errorf("error open handle: %w", err) } defer handle.Close() // -------------------------------------- // Apply capture filter (optional) // -------------------------------------- if filter != "" { err = handle.SetBPFFilter(filter) if err != nil { return fmt.Errorf("error apply filter: %w", err) } } // -------------------------------------- // Set signal handler // -------------------------------------- var ( sigCh = make(chan os.Signal, 1) ) signal.Notify(sigCh, os.Interrupt) // -------------------------------------- // Make packet source and display. // -------------------------------------- var ( dataSource gopacket.PacketDataSource = handle decoder gopacket.Decoder = handle.LinkType() packetSource *gopacket.PacketSource = gopacket.NewPacketSource(dataSource, decoder) packetCh <-chan gopacket.Packet = packetSource.Packets() ) appLog.Println("START") LOOP: for { select { case <-sigCh: break LOOP case p := <-packetCh: // Display only the first packet appLog.Println(p) break LOOP } } return nil }
以下、Gitpod上で実行してみた結果です。
gitpod /workspace/go-gopacket-example (main) $ task openoffline task: [openoffline] go build task: [openoffline] sudo timeout 3s tcpdump -i eth0 -w example.pcap 'tcp' tcpdump: listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes 191 packets captured 206 packets received by filter 0 packets dropped by kernel task: [openoffline] sudo ./openoffline START PACKET: 163 bytes, wire length 163 cap length 163 @ 2023-04-14 06:41:02.996639 +0000 UTC - Layer 1 (14 bytes) = Ethernet {Contents=[..14..] Payload=[..149..] SrcMAC=7e:d3:7e:4f:18:db DstMAC=aa:5c:d0:d8:85:62 EthernetType=IPv4 Length=0} - Layer 2 (20 bytes) = IPv4 {Contents=[..20..] Payload=[..129..] Version=4 IHL=5 TOS=0 Length=149 Id=26960 Flags=DF FragOffset=0 TTL=64 Protocol=TCP Checksum=45792 SrcIP=10.0.5.2 DstIP=192.168.78.136 Options=[] Padding=[]} - Layer 3 (32 bytes) = TCP {Contents=[..32..] Payload=[..97..] SrcPort=23000(inovaport1) DstPort=57996 Seq=162170162 Ack=2982792157 DataOffset=8 FIN=false SYN=false RST=false PSH=true ACK=true URG=false ECE=false CWR=false NS=false Window=1479 Checksum=7866 Urgent=0 Options=[TCPOption(NOP:), TCPOption(NOP:), TCPOption(Timestamps:3782026922/108024006 0xe16d26aa067050c6)] Padding=[]} - Layer 4 (97 bytes) = Payload 97 byte(s) DONE
実行すると、最初に3秒間ほど tcpdump コマンドを実行してキャプチャして、pcapファイルを出力します。
その後、それをgo-packetを使って読み込んでパケットを表示しています。
リポジトリ
上のサンプルなどは、以下のリポジトリでアップしています。ご参考までに。
参考情報
Goのおすすめ書籍
過去の記事については、以下のページからご参照下さい。
サンプルコードは、以下の場所で公開しています。