関連記事
Goメモ-306 (go-packetメモ-01)(ネットワークインターフェースを表示) - いろいろ備忘録日記
Goメモ-307 (go-packetメモ-02)(流れるパケットをキャプチャする)(OpenLive) - いろいろ備忘録日記
Goメモ-308 (go-packetメモ-03)(pcapファイルを読み込み)(OpenOffline) - いろいろ備忘録日記
Goメモ-309 (go-packetメモ-04)(BPFフィルタを設定)(SetBPFFilter) - いろいろ備忘録日記
Goメモ-310 (go-packetメモ-05)(*pcap.Packetの中身を表示) - いろいろ備忘録日記
Goメモ-311 (go-packetメモ-06)(*layers.Ethernetの情報を表示) - いろいろ備忘録日記
Goメモ-312 (go-packetメモ-07)(*layers.ARPの情報を表示) - いろいろ備忘録日記
Goメモ-313 (go-packetメモ-08)(*layers.ICMPv4の情報を表示) - いろいろ備忘録日記
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 の方に詳しく書かれています。
今回は、実際のインターネットプロトコルレイヤーを表す *layers.IPv4
の中身を見てみます。
最もよく利用されているネットワーク層のプロトコルですね。
(OSI参照モデルではネットワーク層、TCP/IPプロトコル群ではインターネット層)
各レイヤーの取得方法は、大抵同じやり方になってて、以下のようになります。
var p gopacket.Packet XXXXLayer := p.Layer(layers.LayerTypeXXXX) if XXXXLayer != nil { xxxx := XXXXLayer.(*layers.XXXX) }
XXXXの部分を変えればオッケイ。
main.go
// Package main is the example of *layers.IPv4 package main import ( "fmt" "log" "os" "os/signal" "time" "github.com/google/gopacket" "github.com/google/gopacket/layers" "github.com/google/gopacket/pcap" ) var ( appLog = log.New(os.Stderr, "", 0) ) func main() { if err := run(); err != nil { appLog.Panic(err) } } func run() error { const ( device = "eth0" filter = "tcp" snapshotLen = int32(1600) promiscuous = false timeout = 1 * time.Second ) defer func() { appLog.Println("DONE") }() // -------------------------------------- // Open capture handle // -------------------------------------- var ( handle *pcap.Handle err error ) handle, err = pcap.OpenLive(device, snapshotLen, promiscuous, timeout) 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, ok := <-packetCh: if !ok { break LOOP } // Display only the first items if see(p) { break LOOP } } } return nil } func see(p gopacket.Packet) bool { ipv4Layer := p.Layer(layers.LayerTypeIPv4) if ipv4Layer == nil { return false } ipv4 := ipv4Layer.(*layers.IPv4) appLog.Printf("[Version ] %v", ipv4.Version) // Internet Header Length (IHL) // IPv4ヘッダの長さを32ビットワード単位で示す. // IHLは通常、最小値の5(5 * 32ビット = 160ビット = 20バイト)であるが // IPヘッダにオプションが含まれている場合、それより大きくなる. // // IHLが5の場合、IPv4ヘッダは20バイトの長さを持つ. // IHLが6の場合、IPv4ヘッダは24バイトの長さを持ち、そのうち4バイトがオプションフィールドに割り当てられる. // IHLを使用して、IPヘッダの終わりとペイロード(データ)の開始を正確に判断することができる. appLog.Printf("[IHL ] %v words -> %v bits -> %v bytes", ipv4.IHL, ipv4.IHL*32, ipv4.IHL*32/8) // Lengthは IPv4 パケット全体での長さを表す appLog.Printf("[Length ] %v", ipv4.Length) appLog.Printf("[Payload Length] %v", len(ipv4.Payload)) appLog.Printf("[TTL ] %v", ipv4.TTL) appLog.Printf("[Protocol ] %v", ipv4.Protocol) appLog.Printf("[Src IP ] %v", ipv4.SrcIP) appLog.Printf("[Dst IP ] %v", ipv4.DstIP) return true }
Taskfile.yml
タスク定義は以下のような感じ。
layertype-ipv4: desc: See *layers.IPv4 info dir: cmd/layertype/ipv4 cmds: - go build - sudo ./ipv4
以下、Gitpod上で実行してみた結果です。
gitpod /workspace/go-gopacket-example (main) $ task layertype-ipv4 task: [layertype-ipv4] go build task: [layertype-ipv4] sudo ./ipv4 START [Version ] 4 [IHL ] 5 words -> 160 bits -> 20 bytes [Length ] 120 [Payload Length] 100 [TTL ] 111 [Protocol ] TCP [Src IP ] xxx.xxx.xxx.xxx [Dst IP ] xxx.xxx.xxx.xxx DONE
実行すると、流れるIPv4パケットの情報が表示されます。
リポジトリ
上のサンプルなどは、以下のリポジトリでアップしています。ご参考までに。
参考情報
Goのおすすめ書籍
過去の記事については、以下のページからご参照下さい。
サンプルコードは、以下の場所で公開しています。