背景
因为业务状况,须要抓取sip数据进行剖析,应用gopacket的pcap库进行抓包时,当有大批量数据时会呈现抓包数据不齐全的状况。
调研状况
参考该文章: https://blog.csdn.net/rong_to...
发现解决该问题能够有两种计划: 1. mmap 2.pf_ring
- pf_ring 该计划须要装置指定的网卡驱动程序,在我这边的业务场景中不实用。
- mmap libcap在1.1版本时默认反对mmap, 然而在调整了各种参数,抓包还是有失落的状况,所以退而求其次,应用afpacket,该包底层应用的unix.mmap,间接应用mmap抓包。afpacket有个问题是抓127.0.0.1地址的包,抓到的数据会是双份的,抓外网ip的包OK。
afPacket应用调优
- 网卡开启混淆模式,抓包应用混淆模式
- 调整snapshot大小最大为65535
- 抓包超时工夫为-1.
具体的代码为:
参数设置:
szFrame, szBlock, numBlocks, err := afpacket.AfpacketComputeSize(1024, 65535, os.Getpagesize()) if err != nil { return err } server.handle, err = afpacket.NewAfpacketHandle("eth0", szFrame, szBlock, numBlocks, false, -1*time.Millisecond) if err != nil { return err }
抓包代码:
source := gopacket.ZeroCopyPacketDataSource(server.handle) dlc := gopacket.DecodingLayerContainer(gopacket.DecodingLayerMap(nil))for {select { case <-ctx.Done():return default: d, _, err := source.ZeroCopyReadPacketData() if err != nil { fmt.Println("ReadPacketData err: ", err) continue } data := make([]byte, len(d)) copy(data, d) var eth layers.Ethernet var ip4 layers.IPv4 var udp layers.UDP dlc = dlc.Put(ð) dlc = dlc.Put(&ip4) dlc = dlc.Put(&udp) dlc = dlc.Put(layers.NewSIP()) decoder := dlc.LayersDecoder(layers.LayerTypeEthernet, gopacket.NilDecodeFeedback) decodedLayers := make([]gopacket.LayerType, 0, 10) _, err = decoder(data, &decodedLayers) if udp.NextLayerType() == gopacket.LayerTypePayload { // udp解决 }else if udp.NextLayerType() == layers.LayerTypeSIP { // sip解决 } }}
这里有几个留神点:
- 如果把 dlc := gopacket.DecodingLayerContainer(gopacket.DecodingLayerMap(nil))
放到default内,每个包都从新生成一下编码对象,会影响数据处理性能,抓包还是会失落。
这里应用的DecodingLayerMap是因为可能更新编码构造体内的对象。 - dlc = dlc.Put(layers.NewSIP()) 如果换成dlc = dlc.Put(&layers.SIP),会报错,起因是sip构造体内的Hearder是map类型,未初始化。
- udp业务解决时要及时,业务解决较慢时会导致抓包阻塞,抓包数据失落。
- ZeroCopyReadPacketData 该构造体返回的后果不平安,要copy一份防止数据被批改。如果换成ReadPacketData, 还是会呈现丢包的状况,目前没找到起因。