Golang Go语言中请教一个关于 gopacket 包使用的问题

发布于 1周前 作者 songsunli 来自 Go语言

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 &amp;&amp; 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

2 回复

ReadRequest 不是已经把 buf 读完了吗,ReadResponse 有东西读吗

更多关于Golang Go语言中请教一个关于 gopacket 包使用的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Go语言中,gopacket是一个非常流行的用于网络数据包解析和分析的库。它提供了强大的功能来捕获、解析和处理各种网络协议的数据包。针对你提到的关于gopacket包使用的问题,这里提供一些基本的指导和常见的使用场景:

  1. 安装gopacket: 你可以通过go get命令来安装gopacket

    go get -u github.com/google/gopacket
    
  2. 基本使用

    • 捕获数据包:使用gopacket.Capture接口来捕获网络数据包。
    • 解析数据包gopacket.DecodingLayerParser接口和相关的协议解码器(如layers.Ethernetlayers.IPlayers.TCP等)用于解析捕获的数据包。
    • 处理数据包:通过实现gopacket.PacketSourcegopacket.PacketHandler接口来处理解析后的数据包。
  3. 示例代码: 以下是一个简单的示例,展示如何使用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)
            }
        }
    }
    

希望这些信息对你有所帮助!如果你有更具体的问题或遇到错误,请详细描述。

回到顶部