gopacketでpcapを読み込む
Goでパケットを扱うライブラリにgopacketがある。
ここではgopacketでpcapを読み込んでパケットの内容を表示してみる。
単純に読み込んで表示する
読み込むpcapはhttp.capを使っている。
package main import ( "fmt" "io" "github.com/google/gopacket" "github.com/google/gopacket/pcap" "log" ) var ( pcapFile string = "http.cap" handle *pcap.Handle err error ) func main() { handle, err = pcap.OpenOffline(pcapFile) if err != nil { log.Fatal(err) } defer handle.Close() packetSource := gopacket.NewPacketSource(handle, handle.LinkType()) for { packet, err := packetSource.NextPacket() if err == io.EOF { break } else if err != nil { log.Println("Error:", err) continue } fmt.Println(packet) } }
読み込み箇所は以下の部分。
handle, err = pcap.OpenOffline(pcapFile)
でpcapを読み込み、
packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
でpcapからパケットを取得できる。
https://godoc.org/github.com/google/gopacket#PacketSource
ちなみに、もっと簡単に読み込む方法としてPackets()を使う方法もある。
for packet := range packetSource.Packets() { fmt.Println(packet) }
実行結果
PACKET: 62 bytes, wire length 62 cap length 62 @ 2004-05-13 19:17:07.311224 +0900 JST - Layer 1 (14 bytes) = Ethernet {Contents=[..14..] Payload=[..48..] SrcMAC=00:00:01:00:00:00 DstMAC=fe:ff:20:00:01:00 EthernetType=IPv4 Length=0} - Layer 2 (20 bytes) = IPv4 {Contents=[..20..] Payload=[..28..] Version=4 IHL=5 TOS=0 Length=48 Id=3905 Flags=DF FragOffset=0 TTL=128 Protocol=TCP Checksum=37355 SrcIP=145.254.160.237 DstIP= 65.208.228.223 Options=[] Padding=[]} - Layer 3 (28 bytes) = TCP {Contents=[..28..] Payload=[] SrcPort=3372(tip2) DstPort=80(http) Seq=951057939 Ack=0 DataOffset=7 FIN=false SYN=true RST=false PSH=false ACK=false URG=false ECE= false CWR=false NS=false Window=8760 Checksum=49932 Urgent=0 Options=[TCPOption(2:[5 180]), NOP, NOP, TCPOption(4:[])] Padding=[]} PACKET: 62 bytes, wire length 62 cap length 62 @ 2004-05-13 19:17:08.222534 +0900 JST - Layer 1 (14 bytes) = Ethernet {Contents=[..14..] Payload=[..48..] SrcMAC=fe:ff:20:00:01:00 DstMAC=00:00:01:00:00:00 EthernetType=IPv4 Length=0} - Layer 2 (20 bytes) = IPv4 {Contents=[..20..] Payload=[..28..] Version=4 IHL=5 TOS=0 Length=48 Id=0 Flags=DF FragOffset=0 TTL=47 Protocol=TCP Checksum=61996 SrcIP=65.208.228.223 DstIP=145.2 54.160.237 Options=[] Padding=[]} - Layer 3 (28 bytes) = TCP {Contents=[..28..] Payload=[] SrcPort=80(http) DstPort=3372(tip2) Seq=290218379 Ack=951057940 DataOffset=7 FIN=false SYN=true RST=false PSH=false ACK=true URG=fal se ECE=false CWR=false NS=false Window=5840 Checksum=23516 Urgent=0 Options=[TCPOption(2:[5 100]), NOP, NOP, TCPOption(4:[])] Padding=[]} ...
パケットが持つレイヤを表示する
package main import ( "fmt" "io" "github.com/google/gopacket" "github.com/google/gopacket/layers" "github.com/google/gopacket/pcap" "log" ) var ( pcapFile string = "http.cap" handle *pcap.Handle err error ) func printPacketInfo(packet gopacket.Packet) { for _, layer := range packet.Layers() { fmt.Println(layer.LayerType()) } } func main() { handle, err = pcap.OpenOffline(pcapFile) if err != nil { log.Fatal(err) } defer handle.Close() packetSource := gopacket.NewPacketSource(handle, handle.LinkType()) for { packet, err := packetSource.NextPacket() if err == io.EOF { break } else if err != nil { log.Println("Error:", err) continue } printPacketInfo(packet) } }
Ethernet IPv4 TCP Ethernet IPv4 TCP Ethernet IPv4 TCP Ethernet IPv4 TCP Payload
Ethernet
func printPacketInfo(packet gopacket.Packet) { ethernetLayer := packet.Layer(layers.LayerTypeEthernet) if ethernetLayer != nil { fmt.Println("[*] Ethernet Layer") ethernetPacket, _ := ethernetLayer.(*layers.Ethernet) fmt.Printf("\tSource MAC: %s\n", ethernetPacket.SrcMAC) fmt.Printf("\tDestination MAC: %s\n", ethernetPacket.DstMAC) fmt.Printf("\tEthernet type: %s\n", ethernetPacket.EthernetType) } }
[*] Ethernet Layer Source MAC: 00:00:01:00:00:00 Destination MAC: fe:ff:20:00:01:00 Ethernet type: IPv4 [*] Ethernet Layer Source MAC: 00:00:01:00:00:00 Destination MAC: fe:ff:20:00:01:00 Ethernet type: IPv4 [*] Ethernet Layer Source MAC: fe:ff:20:00:01:00 Destination MAC: 00:00:01:00:00:00 Ethernet type: IPv4
IP
func printPacketInfo(packet gopacket.Packet) { ipLayer := packet.Layer(layers.LayerTypeIPv4) if ipLayer != nil { fmt.Println("[*] IPv4 layer") ip, _ := ipLayer.(*layers.IPv4) fmt.Printf("\t%s -> %s\n", ip.SrcIP, ip.DstIP) fmt.Printf("\tProtocol: %s\n", ip.Protocol) fmt.Printf("\tIHL: %d\n", ip.IHL) fmt.Printf("\tTOS: %d\n", ip.TOS) fmt.Printf("\tLength: %d\n", ip.Length) fmt.Printf("\tId: %d\n", ip.Id) fmt.Printf("\tFlags: %s\n", ip.Flags) fmt.Printf("\tFragOffset: %d\n", ip.FragOffset) fmt.Printf("\tTTL: %d\n", ip.TTL) } }
[*] IPv4 layer 65.208.228.223 -> 145.254.160.237 Protocol: TCP IHL: 5 TOS: 0 Length: 40 Id: 0 Flags: DF FragOffset: 0 TTL: 47 ...
TCP
func printPacketInfo(packet gopacket.Packet) { ipLayer := packet.Layer(layers.LayerTypeIPv4) tcpLayer := packet.Layer(layers.LayerTypeTCP) if tcpLayer != nil { ip, _ := ipLayer.(*layers.IPv4) tcp, _ := tcpLayer.(*layers.TCP) // Bool flags: FIN, SYN, RST, PSH, ACK, URG, ECE, CWR, NS if tcp.SYN { fmt.Println("[*] TCP Layer") fmt.Printf("\t%s:%d -> %s:%d\n", ip.SrcIP, tcp.SrcPort, ip.DstIP, tcp.DstPort) fmt.Printf("\tSeq: %d\n", tcp.Seq) fmt.Printf("\tAck: %d\n", tcp.Ack) fmt.Printf("\tDataOffset: %d\n", tcp.DataOffset) fmt.Printf("\tWindow: %d\n", tcp.Window) fmt.Printf("\tChecksum: %d\n", tcp.Checksum) fmt.Printf("\tUrgent: %d\n", tcp.Urgent) } } }
[*] TCP Layer 145.254.160.237:3372 -> 65.208.228.223:80 Seq: 951057939 Ack: 0 DataOffset: 7 Window: 8760 Checksum: 49932 Urgent: 0 [*] TCP Layer 65.208.228.223:80 -> 145.254.160.237:3372 Seq: 290218379 Ack: 951057940 DataOffset: 7 Window: 5840 Checksum: 23516 Urgent: 0
Application層
func printPacketInfo(packet gopacket.Packet) { applicationLayer := packet.ApplicationLayer() if applicationLayer != nil { fmt.Println("[*] Application Layer") fmt.Printf("\t%s\n", applicationLayer.Payload()) } }
[*] Application Layer GET /download.html HTTP/1.1 Host: www.ethereal.com User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040113 Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,image/jpeg,image/gif;q=0.2,*/*;q=0.1 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive: 300 Connection: keep-alive Referer: http://www.ethereal.com/development.html
UDP
func printPacketInfo(packet gopacket.Packet) { ipLayer := packet.Layer(layers.LayerTypeIPv4) udpLayer := packet.Layer(layers.LayerTypeUDP) if udpLayer != nil { fmt.Println("[*] UDP Layer") ip, _ := ipLayer.(*layers.IPv4) udp, _ := udpLayer.(*layers.UDP) fmt.Printf("\t%s:%d -> %s:%d\n", ip.SrcIP, udp.SrcPort, ip.DstIP, udp.DstPort) fmt.Printf("\tChecksum: %d\n", udp.Checksum) fmt.Printf("\tLength: %d\n", udp.Length) } }
[*] UDP Layer 145.254.160.237:3009 -> 145.253.2.203:53 Checksum: 4271 Length: 55 [*] UDP Layer 145.253.2.203:53 -> 145.254.160.237:3009 Checksum: 12290 Length: 154