zoukankan      html  css  js  c++  java
  • 使用 gopacket 进行数据包捕获,注入和分析

    原文链接:https://www.devdungeon.com/content/packet-capture-injection-and-analysis-gopacket

    接口文档:https://godoc.org/github.com/google/gopacket

    Demo1(Find devices):

    package main
    
    import (
        "fmt"
        "log"
        "github.com/google/gopacket/pcap"
    )
    
    func main() {
        // Find all devices
        devices, err := pcap.FindAllDevs()
        if err != nil {
            log.Fatal(err)
        }
    
        // Print device information
        fmt.Println("Devices found:")
        for _, device := range devices {
            fmt.Println("
    Name: ", device.Name)
            fmt.Println("Description: ", device.Description)
            fmt.Println("Devices addresses: ", device.Description)
            for _, address := range device.Addresses {
                fmt.Println("- IP address: ", address.IP)
                fmt.Println("- Subnet mask: ", address.Netmask)
            }
        }
    }

    测试结果:

    [root@wangjq device]# go run main.go 
    Devices found:
    
    Name:  br0
    Description:  
    Devices addresses:  
    - IP address:  10.95.149.186
    - Subnet mask:  ffffffc0
    - IP address:  fe80::5422:61ff:fe04:81d3
    - Subnet mask:  ffffffffffffffff0000000000000000
    
    Name:  virbr0
    Description:  
    Devices addresses:  
    - IP address:  192.168.122.1
    - Subnet mask:  ffffff00
    
    Name:  docker0
    Description:  
    Devices addresses:  
    - IP address:  172.17.0.1
    - Subnet mask:  ffff0000
    
    Name:  nflog
    Description:  Linux netfilter log (NFLOG) interface
    Devices addresses:  Linux netfilter log (NFLOG) interface
    
    Name:  nfqueue
    Description:  Linux netfilter queue (NFQUEUE) interface
    Devices addresses:  Linux netfilter queue (NFQUEUE) interface
    
    Name:  usbmon1
    Description:  USB bus number 1
    Devices addresses:  USB bus number 1
    
    Name:  usbmon2
    Description:  USB bus number 2
    Devices addresses:  USB bus number 2
    
    Name:  ens3
    Description:  
    Devices addresses:  
    
    Name:  usbmon3
    Description:  USB bus number 3
    Devices addresses:  USB bus number 3
    
    Name:  ens4
    Description:  
    Devices addresses:  
    - IP address:  fe80::7f29:1f32:6a3:2a59
    - Subnet mask:  ffffffffffffffff0000000000000000
    
    Name:  usbmon4
    Description:  USB bus number 4
    Devices addresses:  USB bus number 4
    
    Name:  any
    Description:  Pseudo-device that captures on all interfaces
    Devices addresses:  Pseudo-device that captures on all interfaces
    
    Name:  lo
    Description:  
    Devices addresses:  
    - IP address:  127.0.0.1
    - Subnet mask:  ff000000
    - IP address:  ::1
    - Subnet mask:  ffffffffffffffffffffffffffffffff

    Demo2(Open Device for Live Capture):

    package main
    
    import (
        "fmt"
        "github.com/google/gopacket"
        "github.com/google/gopacket/pcap"
        "log"
        "time"
    )
    
    var (
        device       string = "eth0"
        snapshot_len int32  = 1024
        promiscuous  bool   = false
        err          error
        timeout      time.Duration = 30 * time.Second
        handle       *pcap.Handle
    )
    
    func main() {
        // Open device
        handle, err = pcap.OpenLive(device, snapshot_len, promiscuous, timeout)
        if err != nil {log.Fatal(err) }
        defer handle.Close()
    
        // Use the handle as a packet source to process all packets
        packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
        for packet := range packetSource.Packets() {
            // Process packet here
            fmt.Println(packet)
        }
    }

    测试结果:

    PACKET: 1024 bytes, truncated, wire length 2974 cap length 1024 @ 2019-10-22 17:43:00.069751 +0800 HKT
    - Layer 1 (14 bytes) = Ethernet {Contents=[..14..] Payload=[..1010..] SrcMAC=52:54:00:3d:78:f1 DstMAC=74:ea:cb:5d:e4:f7 EthernetType=IPv4 Length=0}
    - Layer 2 (20 bytes) = IPv4     {Contents=[..20..] Payload=[..990..] Version=4 IHL=5 TOS=16 Length=2960 Id=10566 Flags=DF FragOffset=0 TTL=64 Protocol=TCP Checksum=35752 SrcIP=10.95.149.186 DstIP=172.24.46.56 Options=[] Padding=[]}
    - Layer 3 (20 bytes) = TCP      {Contents=[..20..] Payload=[..970..] SrcPort=22(ssh) DstPort=65461 Seq=3357288217 Ack=916868378 DataOffset=5 FIN=false SYN=false RST=false PSH=false ACK=true URG=false ECE=false CWR=false NS=false Window=682 Checksum=34284 Urgent=0 Options=[] Padding=[]}
    - Layer 4 (970 bytes) = Payload 970 byte(s)
    
    PACKET: 54 bytes, wire length 54 cap length 54 @ 2019-10-22 17:43:00.069956 +0800 HKT
    - Layer 1 (14 bytes) = Ethernet {Contents=[..14..] Payload=[..40..] SrcMAC=74:ea:cb:5d:e4:f7 DstMAC=52:54:00:3d:78:f1 EthernetType=IPv4 Length=0}
    - Layer 2 (20 bytes) = IPv4     {Contents=[..20..] Payload=[..20..] Version=4 IHL=5 TOS=0 Length=40 Id=31453 Flags=DF FragOffset=0 TTL=123 Protocol=TCP Checksum=2697 SrcIP=172.24.46.56 DstIP=10.95.149.186 Options=[] Padding=[]}
    - Layer 3 (20 bytes) = TCP      {Contents=[..20..] Payload=[] SrcPort=65461 DstPort=22(ssh) Seq=916868378 Ack=3357288217 DataOffset=5 FIN=false SYN=false RST=false PSH=false ACK=true URG=false ECE=false CWR=false NS=false Window=256 Checksum=49576 Urgent=0 Options=[] Padding=[]}

    Demo3(Write Pcap File):

    package main
    
    import (
        "fmt"
        "os"
        "time"
    
        "github.com/google/gopacket"
        "github.com/google/gopacket/layers"
        "github.com/google/gopacket/pcap"
        "github.com/google/gopacket/pcapgo"
    )
    
    var (
        deviceName  string = "eth0"
        snapshotLen int32  = 1024
        promiscuous bool   = false
        err         error
        timeout     time.Duration = -1 * time.Second
        handle      *pcap.Handle
        packetCount int = 0
    )
    
    func main() {
        // Open output pcap file and write header 
        f, _ := os.Create("test.pcap")
        w := pcapgo.NewWriter(f)
        w.WriteFileHeader(snapshotLen, layers.LinkTypeEthernet)
        defer f.Close()
    
        // Open the device for capturing
        handle, err = pcap.OpenLive(deviceName, snapshotLen, promiscuous, timeout)
        if err != nil {
            fmt.Printf("Error opening device %s: %v", deviceName, err)
            os.Exit(1)
        }
        defer handle.Close()
    
        // Start processing packets
        packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
        for packet := range packetSource.Packets() {
            // Process packet here
            fmt.Println(packet)
            w.WritePacket(packet.Metadata().CaptureInfo, packet.Data())
            packetCount++
            
            // Only capture 100 and then stop
            if packetCount > 100 {
                break
            }
        }
    }

    Demo4(Open Pcap File):

    package main
    
    // Use tcpdump to create a test file
    // tcpdump -w test.pcap
    // or use the example above for writing pcap files
    
    import (
        "fmt"
        "github.com/google/gopacket"
        "github.com/google/gopacket/pcap"
        "log"
    )
    
    var (
        pcapFile string = "test.pcap"
        handle   *pcap.Handle
        err      error
    )
    
    func main() {
        // Open file instead of device
        handle, err = pcap.OpenOffline(pcapFile)
        if err != nil { log.Fatal(err) }
        defer handle.Close()
    
        // Loop through packets in file
        packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
        for packet := range packetSource.Packets() {
            fmt.Println(packet)
        }
    }

    Demo5(Setting Filters):

    package main
    
    import (
        "fmt"
        "github.com/google/gopacket"
        "github.com/google/gopacket/pcap"
        "log"
        "time"
    )
    
    var (
        device       string = "eth0"
        snapshot_len int32  = 1024
        promiscuous  bool   = false
        err          error
        timeout      time.Duration = 30 * time.Second
        handle       *pcap.Handle
    )
    
    func main() {
        // Open device
        handle, err = pcap.OpenLive(device, snapshot_len, promiscuous, timeout)
        if err != nil {
            log.Fatal(err)
        }
        defer handle.Close()
    
        // Set filter
        var filter string = "tcp and port 80"
        err = handle.SetBPFFilter(filter)
        if err != nil {
            log.Fatal(err)
        }
        fmt.Println("Only capturing TCP port 80 packets.")
    
        packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
        for packet := range packetSource.Packets() {
            // Do something with a packet here.
            fmt.Println(packet)
        }
    
    }

    Demo6(Decoding Packet Layers):

    package main
    
    import (
        "fmt"
        "github.com/google/gopacket"
        "github.com/google/gopacket/layers"
        "github.com/google/gopacket/pcap"
        "log"
        "strings"
        "time"
    )
    
    var (
        device      string = "eth0"
        snapshotLen int32  = 1024
        promiscuous bool   = false
        err         error
        timeout     time.Duration = 30 * time.Second
        handle      *pcap.Handle
    )
    
    func main() {
        // Open device
        handle, err = pcap.OpenLive(device, snapshotLen, promiscuous, timeout)
        if err != nil {log.Fatal(err) }
        defer handle.Close()
    
        packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
        for packet := range packetSource.Packets() {
            printPacketInfo(packet)
        }
    }
    
    func printPacketInfo(packet gopacket.Packet) {
        // Let's see if the packet is an ethernet packet
        ethernetLayer := packet.Layer(layers.LayerTypeEthernet)
        if ethernetLayer != nil {
            fmt.Println("Ethernet layer detected.")
            ethernetPacket, _ := ethernetLayer.(*layers.Ethernet)
            fmt.Println("Source MAC: ", ethernetPacket.SrcMAC)
            fmt.Println("Destination MAC: ", ethernetPacket.DstMAC)
            // Ethernet type is typically IPv4 but could be ARP or other
            fmt.Println("Ethernet type: ", ethernetPacket.EthernetType)
            fmt.Println()
        }
    
        // Let's see if the packet is IP (even though the ether type told us)
        ipLayer := packet.Layer(layers.LayerTypeIPv4)
        if ipLayer != nil {
            fmt.Println("IPv4 layer detected.")
            ip, _ := ipLayer.(*layers.IPv4)
    
            // IP layer variables:
            // Version (Either 4 or 6)
            // IHL (IP Header Length in 32-bit words)
            // TOS, Length, Id, Flags, FragOffset, TTL, Protocol (TCP?),
            // Checksum, SrcIP, DstIP
            fmt.Printf("From %s to %s
    ", ip.SrcIP, ip.DstIP)
            fmt.Println("Protocol: ", ip.Protocol)
            fmt.Println()
        }
    
        // Let's see if the packet is TCP
        tcpLayer := packet.Layer(layers.LayerTypeTCP)
        if tcpLayer != nil {
            fmt.Println("TCP layer detected.")
            tcp, _ := tcpLayer.(*layers.TCP)
    
            // TCP layer variables:
            // SrcPort, DstPort, Seq, Ack, DataOffset, Window, Checksum, Urgent
            // Bool flags: FIN, SYN, RST, PSH, ACK, URG, ECE, CWR, NS
            fmt.Printf("From port %d to %d
    ", tcp.SrcPort, tcp.DstPort)
            fmt.Println("Sequence number: ", tcp.Seq)
            fmt.Println()
        }
    
        // Iterate over all layers, printing out each layer type
        fmt.Println("All packet layers:")
        for _, layer := range packet.Layers() {
            fmt.Println("- ", layer.LayerType())
        }
    
        // When iterating through packet.Layers() above,
        // if it lists Payload layer then that is the same as
        // this applicationLayer. applicationLayer contains the payload
        applicationLayer := packet.ApplicationLayer()
        if applicationLayer != nil {
            fmt.Println("Application layer/Payload found.")
            fmt.Printf("%s
    ", applicationLayer.Payload())
    
            // Search for a string inside the payload
            if strings.Contains(string(applicationLayer.Payload()), "HTTP") {
                fmt.Println("HTTP found!")
            }
        }
    
        // Check for errors
        if err := packet.ErrorLayer(); err != nil {
            fmt.Println("Error decoding some part of the packet:", err)
        }
    }

     Demo7(Creating and Sending Packets):

    package main
    
    import (
        "github.com/google/gopacket"
        "github.com/google/gopacket/layers"
        "github.com/google/gopacket/pcap"
        "log"
        "net"
        "time"
    )
    
    var (
        device       string = "eth0"
        snapshot_len int32  = 1024
        promiscuous  bool   = false
        err          error
        timeout      time.Duration = 30 * time.Second
        handle       *pcap.Handle
        buffer       gopacket.SerializeBuffer
        options      gopacket.SerializeOptions
    )
    
    func main() {
        // Open device
        handle, err = pcap.OpenLive(device, snapshot_len, promiscuous, timeout)
        if err != nil {log.Fatal(err) }
        defer handle.Close()
    
        // Send raw bytes over wire
        rawBytes := []byte{10, 20, 30}
        err = handle.WritePacketData(rawBytes)
        if err != nil {
            log.Fatal(err)
        }
    
        // Create a properly formed packet, just with
        // empty details. Should fill out MAC addresses,
        // IP addresses, etc.
        buffer = gopacket.NewSerializeBuffer()
        gopacket.SerializeLayers(buffer, options,
            &layers.Ethernet{},
            &layers.IPv4{},
            &layers.TCP{},
            gopacket.Payload(rawBytes),
        )
        outgoingPacket := buffer.Bytes()
        // Send our packet
        err = handle.WritePacketData(outgoingPacket)
        if err != nil {
            log.Fatal(err)
        }
    
        // This time lets fill out some information
        ipLayer := &layers.IPv4{
            SrcIP: net.IP{127, 0, 0, 1},
            DstIP: net.IP{8, 8, 8, 8},
        }
        ethernetLayer := &layers.Ethernet{
            SrcMAC: net.HardwareAddr{0xFF, 0xAA, 0xFA, 0xAA, 0xFF, 0xAA},
            DstMAC: net.HardwareAddr{0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD},
        }
        tcpLayer := &layers.TCP{
            SrcPort: layers.TCPPort(4321),
            DstPort: layers.TCPPort(80),
        }
        // And create the packet with the layers
        buffer = gopacket.NewSerializeBuffer()
        gopacket.SerializeLayers(buffer, options,
            ethernetLayer,
            ipLayer,
            tcpLayer,
            gopacket.Payload(rawBytes),
        )
        outgoingPacket = buffer.Bytes()
    }

    Demo8(More on Creating/Decoding Packets):

    package main
    
    import (
        "fmt"
        "github.com/google/gopacket"
        "github.com/google/gopacket/layers"
    )
    
    func main() {
        // If we don't have a handle to a device or a file, but we have a bunch
        // of raw bytes, we can try to decode them in to packet information
    
        // NewPacket() takes the raw bytes that make up the packet as the first parameter
        // The second parameter is the lowest level layer you want to decode. It will
        // decode that layer and all layers on top of it. The third layer
        // is the type of decoding: default(all at once), lazy(on demand), and NoCopy
        // which will not create a copy of the buffer
    
        // Create an packet with ethernet, IP, TCP, and payload layers
        // We are creating one we know will be decoded properly but
        // your byte source could be anything. If any of the packets
        // come back as nil, that means it could not decode it in to
        // the proper layer (malformed or incorrect packet type)
        payload := []byte{2, 4, 6}
        options := gopacket.SerializeOptions{}
        buffer := gopacket.NewSerializeBuffer()
        gopacket.SerializeLayers(buffer, options,
            &layers.Ethernet{},
            &layers.IPv4{},
            &layers.TCP{},
            gopacket.Payload(payload),
        )
        rawBytes := buffer.Bytes()
    
        // Decode an ethernet packet
        ethPacket :=
            gopacket.NewPacket(
                rawBytes,
                layers.LayerTypeEthernet,
                gopacket.Default,
            )
    
        // with Lazy decoding it will only decode what it needs when it needs it
        // This is not concurrency safe. If using concurrency, use default
        ipPacket :=
            gopacket.NewPacket(
                rawBytes,
                layers.LayerTypeIPv4,
                gopacket.Lazy,
            )
    
        // With the NoCopy option, the underlying slices are referenced
        // directly and not copied. If the underlying bytes change so will
        // the packet
        tcpPacket :=
            gopacket.NewPacket(
                rawBytes,
                layers.LayerTypeTCP,
                gopacket.NoCopy,
            )
    
        fmt.Println(ethPacket)
        fmt.Println(ipPacket)
        fmt.Println(tcpPacket)
    }

    Demo9(Custom Layers):

    package main
    
    import (
        "fmt"
        "github.com/google/gopacket"
    )
    
    // Create custom layer structure
    type CustomLayer struct {
        // This layer just has two bytes at the front
        SomeByte    byte
        AnotherByte byte
        restOfData  []byte
    }
    
    // Register the layer type so we can use it
    // The first argument is an ID. Use negative
    // or 2000+ for custom layers. It must be unique
    var CustomLayerType = gopacket.RegisterLayerType(
        2001,
        gopacket.LayerTypeMetadata{
            "CustomLayerType",
            gopacket.DecodeFunc(decodeCustomLayer),
        },
    )
    
    // When we inquire about the type, what type of layer should
    // we say it is? We want it to return our custom layer type
    func (l CustomLayer) LayerType() gopacket.LayerType {
        return CustomLayerType
    }
    
    // LayerContents returns the information that our layer
    // provides. In this case it is a header layer so
    // we return the header information
    func (l CustomLayer) LayerContents() []byte {
        return []byte{l.SomeByte, l.AnotherByte}
    }
    
    // LayerPayload returns the subsequent layer built
    // on top of our layer or raw payload
    func (l CustomLayer) LayerPayload() []byte {
        return l.restOfData
    }
    
    // Custom decode function. We can name it whatever we want
    // but it should have the same arguments and return value
    // When the layer is registered we tell it to use this decode function
    func decodeCustomLayer(data []byte, p gopacket.PacketBuilder) error {
        // AddLayer appends to the list of layers that the packet has
        p.AddLayer(&CustomLayer{data[0], data[1], data[2:]})
    
        // The return value tells the packet what layer to expect
        // with the rest of the data. It could be another header layer,
        // nothing, or a payload layer.
    
        // nil means this is the last layer. No more decoding
        // return nil
    
        // Returning another layer type tells it to decode
        // the next layer with that layer's decoder function
        // return p.NextDecoder(layers.LayerTypeEthernet)
    
        // Returning payload type means the rest of the data
        // is raw payload. It will set the application layer
        // contents with the payload
        return p.NextDecoder(gopacket.LayerTypePayload)
    }
    
    func main() {
        // If you create your own encoding and decoding you can essentially
        // create your own protocol or implement a protocol that is not
        // already defined in the layers package. In our example we are just
        // wrapping a normal ethernet packet with our own layer.
        // Creating your own protocol is good if you want to create
        // some obfuscated binary data type that was difficult for others
        // to decode
    
        // Finally, decode your packets:
        rawBytes := []byte{0xF0, 0x0F, 65, 65, 66, 67, 68}
        packet := gopacket.NewPacket(
            rawBytes,
            CustomLayerType,
            gopacket.Default,
        )
        fmt.Println("Created packet out of raw bytes.")
        fmt.Println(packet)
    
        // Decode the packet as our custom layer
        customLayer := packet.Layer(CustomLayerType)
        if customLayer != nil {
            fmt.Println("Packet was successfully decoded with custom layer decoder.")
            customLayerContent, _ := customLayer.(*CustomLayer)
            // Now we can access the elements of the custom struct
            fmt.Println("Payload: ", customLayerContent.LayerPayload())
            fmt.Println("SomeByte element:", customLayerContent.SomeByte)
            fmt.Println("AnotherByte element:", customLayerContent.AnotherByte)
        }
    }

    Demo10(Decoding Packets Faster):

    package main
    
    import (
        "fmt"
        "github.com/google/gopacket"
        "github.com/google/gopacket/layers"
        "github.com/google/gopacket/pcap"
        "log"
        "time"
    )
    
    var (
        device       string = "eth0"
        snapshot_len int32  = 1024
        promiscuous  bool   = false
        err          error
        timeout      time.Duration = 30 * time.Second
        handle       *pcap.Handle
        // Will reuse these for each packet
        ethLayer layers.Ethernet
        ipLayer  layers.IPv4
        tcpLayer layers.TCP
    )
    
    func main() {
        // Open device
        handle, err = pcap.OpenLive(device, snapshot_len, promiscuous, timeout)
        if err != nil {
            log.Fatal(err)
        }
        defer handle.Close()
    
        packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
        for packet := range packetSource.Packets() {
            parser := gopacket.NewDecodingLayerParser(
                layers.LayerTypeEthernet,
                &ethLayer,
                &ipLayer,
                &tcpLayer,
            )
            foundLayerTypes := []gopacket.LayerType{}
    
            err := parser.DecodeLayers(packet.Data(), &foundLayerTypes)
            if err != nil {
                fmt.Println("Trouble decoding layers: ", err)
            }
    
            for _, layerType := range foundLayerTypes {
                if layerType == layers.LayerTypeIPv4 {
                    fmt.Println("IPv4: ", ipLayer.SrcIP, "->", ipLayer.DstIP)
                }
                if layerType == layers.LayerTypeTCP {
                    fmt.Println("TCP Port: ", tcpLayer.SrcPort, "->", tcpLayer.DstPort)
                    fmt.Println("TCP SYN:", tcpLayer.SYN, " | ACK:", tcpLayer.ACK)
                }
            }
        }
    }
  • 相关阅读:
    Java中Runnable和Thread的区别
    Callable,Runnable比较及用法
    如何实现视差滚动效果的网页?
    【175】Easy CHM的使用
    【174】C#添加非默认字体
    【173】双显示器随便切换位置
    【172】outlook邮箱设置
    【171】IDL读取HDF文件
    怎样实现二级联动
    Java 23种设计模式详尽分析与实例解析之二--结构型模式
  • 原文地址:https://www.cnblogs.com/wangjq19920210/p/11721281.html
Copyright © 2011-2022 走看看