V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
fivestrong
V2EX  ›  Go 编程语言

请教一个关于 gopacket 包使用的问题

  •  
  •   fivestrong · 2018-01-03 17:00:20 +08:00 · 2237 次点击
    这是一个创建于 2526 天前的主题,其中的信息可能已经有所发展或是发生改变。

    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 流重组有关系,说实话源码工作流程没怎么看懂。

    1 条回复    2018-01-04 09:21:26 +08:00
    goofool
        1
    goofool  
       2018-01-04 09:21:26 +08:00
    ReadRequest 不是已经把 buf 读完了吗,ReadResponse 有东西读吗
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1095 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 19:29 · PVG 03:29 · LAX 11:29 · JFK 14:29
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.