Golang Go语言中请教一个关于 gopacket 包使用的问题
go 新手,想用 go 语言实现一个简单的 http 抓包工具,按照需求输出 http request 和 response 的结果,类似格式这样:
2018-01-03 16:34:04.511 192.168.0.3 100.72.13.1 > GET safedog.jcloud.com /safeCenter/uai.html?data=GNFltny5lT4wKmP2kV2UN1fuUwbJXlYYVxevSodjDvmkP%2FgC2MWX7XW%2FzkKx420J4C6tz60iDO38TevM1%2FKwz2Eho53wA95naaSa1YehC431nZ3MvKWcQvRNt9Dt%2BGatstbZ1EeAGCqFCAvpwUfdPw%3D%3D HTTP/1.1 - -
2018-01-03 16:34:04.516 100.72.13.1 192.168.0.3 < - - - HTTP/1.1 200 OK
这个 https://github.com/google/gopacket 实现了 libcap 抓包封装,然后官方有个 https://github.com/google/gopacket/tree/master/examples/httpassembly 例子 它在 run 函数里面用了 go 的 net/http.ReadRequest 来解析流量数据,在 BPF 设置为'tcp and dst port 80'过滤是没问题的,但是如果想要同时解析 request,response 会报错。于是我又用了 http.ReadResponse 这个函数,单独测试的时候这个函数解析 response 包是没问题的,但要两个同时使用来解析同一个 tcp 流的数据,单纯的 if else 结构判断会报错或者导致 cpu 占满,代码如下:
func (h *httpStream) run() {
buf := bufio.NewReader(&h.r)
for {
req, err1 := http.ReadRequest(buf)
if (err1 != io.EOF && err1 == nil) {
req.Body.Close()
log.Println("Received request from stream", h.net, h.transport, ":", req.Host)
}
resp, err2 := http.ReadResponse(buf, req)
if (err2 != io.EOF && err2 == nil) {
resp.Body.Close()
log.Println("Received response from stream", h.net, h.transport, ":", resp.Status)
}
}
}
官方的函数是这个:
func (h *httpStream) run() {
buf := bufio.NewReader(&h.r)
for {
req, err := http.ReadRequest(buf)
if err == io.EOF {
// We must read until we see an EOF... very important!
return
} else if err != nil {
log.Println("Error reading stream", h.net, h.transport, ":", err)
} else {
bodyBytes := tcpreader.DiscardBytesToEOF(req.Body)
req.Body.Close()
log.Println("Received request from stream", h.net, h.transport, ":", req, "with", bodyBytes, "bytes in request body")
}
}
}
我试过在 else if err != nil 这个分支进行 response 判断,还是有问题。不是很懂这个逻辑需要怎么弄,希望各位大神指点一二。 还有是不是跟它用到的 github.com/google/gopacket/tcpassembly 这个 tcp 流重组有关系,说实话源码工作流程没怎么看懂。
Golang Go语言中请教一个关于 gopacket 包使用的问题
更多关于Golang Go语言中请教一个关于 gopacket 包使用的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
ReadRequest 不是已经把 buf 读完了吗,ReadResponse 有东西读吗
更多关于Golang Go语言中请教一个关于 gopacket 包使用的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在Go语言中,gopacket
是一个非常流行的用于网络数据包解析和分析的库。它提供了强大的功能来捕获、解析和处理各种网络协议的数据包。针对你提到的关于gopacket
包使用的问题,这里提供一些基本的指导和常见的使用场景:
-
安装gopacket: 你可以通过
go get
命令来安装gopacket
:go get -u github.com/google/gopacket
-
基本使用:
- 捕获数据包:使用
gopacket.Capture
接口来捕获网络数据包。 - 解析数据包:
gopacket.DecodingLayerParser
接口和相关的协议解码器(如layers.Ethernet
、layers.IP
、layers.TCP
等)用于解析捕获的数据包。 - 处理数据包:通过实现
gopacket.PacketSource
或gopacket.PacketHandler
接口来处理解析后的数据包。
- 捕获数据包:使用
-
示例代码: 以下是一个简单的示例,展示如何使用
gopacket
捕获并打印以太网数据包的源和目标MAC地址:package main import ( "fmt" "github.com/google/gopacket" "github.com/google/gopacket/pcap" "log" ) func main() { handle, err := pcap.OpenLive("eth0", 1600, true, pcap.BlockForever) if err != nil { log.Fatal(err) } defer handle.Close() packetSource := gopacket.NewPacketSource(handle, handle.LinkType()) for packet := range packetSource.Packets() { ethLayer := packet.Layer(gopacket.LayerTypeEthernet) if ethLayer != nil { eth, _ := ethLayer.(*gopacket.Ethernet) fmt.Printf("Src MAC: %s, Dst MAC: %s\n", eth.SrcMAC, eth.DstMAC) } } }
希望这些信息对你有所帮助!如果你有更具体的问题或遇到错误,请详细描述。