美文网首页
Golang 抓包redis

Golang 抓包redis

作者: Vittoria | 来源:发表于2018-09-19 16:37 被阅读101次

    需要用到的包

    gopacket: ``go get -u -v github.com/google/gopacket

    代码演示

    获取 pcap 版本及网卡列表

    import (
        "fmt"
        "github.com/google/gopacket/pcap"
    )
    
    func main() {
        //  获取 libpcap 的版本
        version := pcap.Version()
        fmt.Println(version)
        //  获取网卡列表
        var devices []pcap.Interface
        devices, _ := pcap.FindAllDevs()
            fmt.Println(devices)
    }
    

    pcap.Interface的定义是

    type Interface struct {
        Name        string
        Description    string
        Flags        uint32
        Addresses    []InterfaceAddress
    }
    

    InterfaceAddress的定义是

    type InterfaceAddress struct {
        IP  net.IP
        Netmask net.IPMask
    }
    

    打开网络接口

    这是在线捕获分析

    handle, _ := pcap.OpenLive(
        "eth0", // device
        int32(65535),   //  snapshot length
        false,  //  promiscuous mode?
        -1 * time.Second,   // timeout 负数表示不缓存,直接输出
    )
    defer handle.Close()
    

    打开dump文件

    对于一些抓到的包进行离线分析,可以用文件。

    handle, _ := pcap.OpenOffline("dump.pcap")
    defer handle.Close()
    

    建立 packet source

    packetSource := gopacket.NewPacketSource(
        handle,
        handle.LinkType()
    )
    

    从 packet source 读取抓的包

    一个包

    packet, _ := packetSource.NextPacket()
    fmt.Println(packet)
    

    所有包

    for packet := range packetSource.Packets() {
        fmt.Println(packet)
    }
    

    过滤

    默认是将所有捕获的包返回回来,而很多时候我们需要关注某个特定类型的包,这时候就需要设置过滤器。这里可以用 Berkeley Packet Filter 的语法

    handle.SetBPFFilter("tcp and port 80")
    

    例子

    • 过滤IP: 10.1.1.3
    • 过滤CIDR: 128.3/16
    • 过滤端口: port 53
    • 过滤主机和端口: host 8.8.8.8 and udp port 53
    • 过滤网段和端口: net 199.16.156.0/22 and port
    • 过滤非本机 Web 流量: (port 80 and port 443) and not host 192.168.0.1

    将捕获到的包保存到文件

    dumpFile, _ := os.Create("dump.pcap")
    defer dumpFile.Close()
    //  准备好写入的 Writer
    packetWriter := pcapgo.NewWriter(dumpFile)
    packetWriter.WriteFileHeader(
        65535,  //  Snapshot length
        layers.LinkTypeEthernet,
    )
    //  写入包
    for packet := range packetSource.Packets() {
        packetWriter.WritePacket(
            packet.Metadata().CaptureInfo,
            packet.Data(),
        )
    }
    

    解析包

    列出包的层

    for _, layer := range packet.Layers() {
        fmt.Println(layer.LayerType())
    }
    

    解析 IP 层

    ipLayer := packet.Layer(layers.LayerTypeIPv4)
    if ipLayer != nil {
        ip, _ := ipLayer.(*layers.IPv4)
        fmt.Println(ip.SrcIP, ip.DstIP)
        fmt.Println(ip.Protocol)
    }
    

    解析 TCP 层

    tcpLayer := packet.Layer(layers.LayerTypeTCP)
    if tcpLayer != nil {
        tcp, _ := tcpLayer.(*layers.TCP)
        fmt.Println(tcp.SrcPort)
        fmt.Println(tcp.DstPort)
    }
    

    常见的包层

    • packet.LinkLayer() // 以太网
    • packet.NetworkLayer() // 网络层,通常也就是 IP 层
    • packet.TransportLayer() // 传输层,比如 TCP/UDP
    • packet.ApplicationLayer() // 应用层,比如 HTTP 层。
    • packet.ErrorLayer() // ……出错了

    示例,解析redis tcp/ip数据

    package main
    
    import (
        "encoding/json"
        "fmt"
        "strings"
        "time"
    
        "github.com/google/gopacket"
        "github.com/google/gopacket/layers"
        "github.com/google/gopacket/pcap"
    )
    
    func main() {
        //  获取 libpcap 的版本
        version := pcap.Version()
        fmt.Println(version)
    
        var device string
        if device = findNetName("127."); device == "" {
            panic("not net is prefix 127.")
        }
    
        handle, e := pcap.OpenLive(
            device,         // device
            int32(65535),   //  snapshot length
            false,          //  promiscuous mode?
            -1*time.Second, // timeout 负数表示不缓存,直接输出
        )
        if e != nil {
            panic(e.Error())
        }
        defer handle.Close()
    
        handle.SetBPFFilter("dst port 6379")
        packetSource := gopacket.NewPacketSource(
            handle,
            handle.LinkType(),
        )
    
        for packet := range packetSource.Packets() {
            //  解析 IP 层
            ipLayer := packet.Layer(layers.LayerTypeIPv4)
            if ipLayer != nil {
                //  解析 TCP 层
                tcpLayer := packet.Layer(layers.LayerTypeTCP)
                if tcpLayer != nil {
                    tcp, _ := tcpLayer.(*layers.TCP)
                    if len(tcp.Payload) > 0 {
                        ip, _ := ipLayer.(*layers.IPv4)
                        fmt.Printf("%s:%s->%s:%s\n%s\n",
                            ip.SrcIP, tcp.SrcPort,
                            ip.DstIP, tcp.DstPort,
                            string(tcp.Payload))
                    }
                } else if errLayer := packet.ErrorLayer(); errLayer != nil {
                    fmt.Printf("tcp.err: %v", errLayer)
                }
            } else if errLayer := packet.ErrorLayer(); errLayer != nil {
                fmt.Printf("ip.err: %v", errLayer)
            }
        }
    
        return
    }
    
    func findNetName(prefix string) string {
        //  获取网卡列表
        var devices []pcap.Interface
        devices, _ = pcap.FindAllDevs()
        for _, d := range devices {
            for _, addr := range d.Addresses {
                if ip4 := addr.IP.To4(); ip4 != nil {
                    if strings.HasPrefix(ip4.String(), prefix) {
                        data, _ := json.MarshalIndent(d, "", "  ")
                        fmt.Println(string(data))
                        return d.Name
                    }
                }
            }
        }
        return ""
    }
    

    本机打开redis-server,并bind在6379端口上。

    然后运行 go run main.go

    此时在redis-cli -p 6379set a b & get a

    得到以下输出结果

    libpcap version 1.8.1 -- Apple version 79.20.1
    {
      "Name": "lo0",
      "Description": "",
      "Flags": 7,
      "Addresses": [
        {
          "IP": "127.0.0.1",
          "Netmask": "/wAAAA==",
          "Broadaddr": "",
          "P2P": ""
        },
        {
          "IP": "::1",
          "Netmask": "/////////////////////w==",
          "Broadaddr": "",
          "P2P": ""
        },
        {
          "IP": "fe80::1",
          "Netmask": "//////////8AAAAAAAAAAA==",
          "Broadaddr": "",
          "P2P": ""
        }
      ]
    }
    127.0.0.1:60484->127.0.0.1:6379(redis)
    *3
    $3
    set
    $1
    a
    $1
    b
    
    127.0.0.1:60484->127.0.0.1:6379(redis)
    *2
    $3
    get
    $1
    a
    

    相关文章

      网友评论

          本文标题:Golang 抓包redis

          本文链接:https://www.haomeiwen.com/subject/iuminftx.html