mrtc0.log

tail -f mrtc0.log

gopacketでpcapを読み込む

Goでパケットを扱うライブラリにgopacketがある。

github.com

ここでは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

参考