分享
  1. 首页
  2. 文章

Golang 抓包redis

Vittoria · · 2192 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

需要用到的包

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

有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:Vittoria

查看原文:Golang 抓包redis

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
2192 次点击
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏