Hung up on gopacket

polaris · · 1479 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>I&#39;m new to golang, and as an introduction to the language I have a pet project in which I&#39;m trying to capture packets over the wire for a particular application for deserialization.</p> <p>To accomplish this, I&#39;m making use of <a href="https://github.com/google/gopacket" rel="nofollow">gopacket</a> to receive packets and pass them off to one of two <a href="https://github.com/google/gopacket/blob/master/tcpassembly/assembly.go" rel="nofollow">Assemblers</a> (one for client, one for server source) so I can have all my ducks in a row before splitting the buffer into what I care about.</p> <p>Intercepting packets works great, and feeding packets to an Assembler works great, but when I attempt to do both at the same time it only works some of the time. I&#39;ve spent some time combing over things but I wanted to step away from it for a bit and check with you folks in the interim to see if the issue is more apparent to someone else.</p> <p>Here&#39;s a stripped down version of the pertinent bits:</p> <pre><code>func main() { addrs, _ := net.InterfaceAddrs() for _, a := range addrs { if ipnet, ok := a.(*net.IPNet); ok &amp;&amp; !ipnet.IP.IsLoopback() { if ipnet.IP.To4() != nil { clientIP = ipnet.IP.String() break } } } quit := make(chan bool) fact := &amp;packetutils.MyStream{} pool := tcpassembly.NewStreamPool(fact) clientAssembler = tcpassembly.NewAssembler(pool) serverAssembler = tcpassembly.NewAssembler(pool) go packetutils.TailDevice(quit, &#34;en0&#34;, 1024, true, &#34;tcp and (port 1119 or port 3724)&#34;, assemblePacket) for { // Tail indefinitely } } func assemblePacket(p gopacket.Packet) { iplayer := p.Layer(layers.LayerTypeIPv4) if iplayer != nil { ip := iplayer.(*layers.IPv4) tcplayer := p.Layer(layers.LayerTypeTCP) tcp := tcplayer.(*layers.TCP) who := ip.SrcIP.String() if who == clientIP { fmt.Println(&#34;client sent packet on port &#34;, tcp.SrcPort, &#34; to &#34;, tcp.DstPort) clientAssembler.Assemble(p.NetworkLayer().NetworkFlow(), tcp) } else { fmt.Println(&#34;server sent packet on port &#34;, tcp.SrcPort, &#34; to &#34;, tcp.DstPort) serverAssembler.Assemble(p.NetworkLayer().NetworkFlow(), tcp) } } } // ...From packetutils func TailDevice(quit &lt;-chan bool, device string, snapshotLen int32, promiscuous bool, filter string, handler DevicePacketHandler) { // Open device handle, err := pcap.OpenLive(device, snapshotLen, promiscuous, -1) if err != nil { log.Fatal(err) } defer handle.Close() if filter != &#34;&#34; { err = handle.SetBPFFilter(filter) if err != nil { log.Fatal(err) } } packetSource := gopacket.NewPacketSource(handle, handle.LinkType()) pchan := packetSource.Packets() for { select { case packet, ok := &lt;-pchan: if !ok { fmt.Println(&#34;Channel closed by device&#34;) return } if handler != nil { go handler(packet) } else { fmt.Println(packet) } case &lt;-quit: return } } } </code></pre> <p>Sometimes this works as intended and packets and <code>assemblePacket</code> is called for every packet received/sent. However, more often than not it looks like <code>packetutils.TailDevice()</code> will simply stop executing at a random point. I&#39;ve added logging through the goroutine trying to identify any one specific spot that it&#39;s hanging at, but I&#39;ve found that it will just cut out anywhere. This behavior goes away and all is well if I remove the creation of the assemblers. </p> <p>For now I&#39;m stuck until I have more time to dig into gopacket/tcpassembly to figure out where I&#39;ve gone wrong, but if anyone has ideas or knows what I&#39;ve overlooked please don&#39;t hesitate to educate.</p> <hr/>**评论:**<br/><br/>kjk: <pre><p>Build with -race flag (go build -race, <a href="http://blog.golang.org/race-detector" rel="nofollow">http://blog.golang.org/race-detector</a>). You&#39;re using goroutines so it&#39;s quite possible it&#39;s a multi-threaded corruption. If -race complains, add locking (mutexes).</p></pre>morethantwo: <pre><p>Thanks for introducing me to <code>-race</code>! I hadn&#39;t known of it before and it&#39;ll come in handy in general. Unfortunately, it didn&#39;t raise any warnings.</p></pre>dericofilho: <pre><p>I know I might showering on the wet ground... Do you understand that you need to compile with -race and run the application until the race condition is exposed?</p></pre>morethantwo: <pre><p>No worries, better to be sure, right? :) But yes, I did compile with the race flag and then run the binary. It displayed the random halts in logging as before, but no warnings printed by the race detector. Ran through it several times to both confirm that the stops were still random in behavior and that I wouldn&#39;t be getting anything from the race detector.</p></pre>tgulacsi: <pre><p>Use select {} instead of the infinite for{} loop - or use sync.WaitGroup to wait the exit of the goroutine(s)</p></pre>jn46: <pre><p>The issue may be that every time you call <code>.Assemble()</code>, you&#39;re doing so in a new goroutine (<code>go handler(packet)</code>) and you&#39;re not waiting for it to finish. <code>tcpassembly/assembly.go</code> says:</p> <pre><code>// Assembler handles reassembling TCP streams. It is not safe for // concurrency... after passing a packet in via the Assemble call, the caller // must wait for that call to return before calling Assemble again. Callers can // get around this by creating multiple assemblers that share a StreamPool. In // that case, each individual stream will still be handled serially (each stream // has an individual mutex associated with it), however multiple assemblers can // assemble different connections concurrently. </code></pre> <p>I made a pet project using gopacket and tcpreader as well! It might be more fun to make your project without looking at other code, but if you want to poke around, my code is at <a href="https://github.com/jamessanford/rtmp-debug" rel="nofollow">https://github.com/jamessanford/rtmp-debug</a></p> <p>Regarding <code>-race</code>, a guess is that it built your program with race detection, but tcpassembly was already built without it, so it didn&#39;t show anything.</p></pre>soybean: <pre><p>where did you get that packetutils from?</p></pre>

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

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