Go 处理PCAP文件

PCAP文件:一个pcap文件由文件头(pacp header)和 多个 (packet header && packet data) 组成,其中 (packet header && packet data) 的数量 就是pcap文件中包含的packet数量。
在这里插入图片描述

本列子是通过https接口请求api获取二进制数据流 接口响应数据如下
在这里插入图片描述
具体实现代码DEMO如下:

// DownloadDataPackets 下载数据包
func DownloadDataPackets(ctx context.Context, baseURI, user, pass, filter, beginTime, endTime, certPath string) (filaname string, err error) {
	var params = map[string]interface{}{
		//请求接口需要的数据
	}
	// 请求接口判断是否有数据,如果有数据再进行后面数据下载请求
	var respData []byte
	req_times := 0
	for {
		req_times += 1
		respData, err = DownloadDataPacketsRal(baseURI, params)
		if err != nil {
			return "", err
		}
		if dataPacketsIsExist(respData) {
			break
		}
		time.Sleep(time.Duration(1) * time.Second)
		if req_times > 60 {
			return "", nil
		}
	}
	fileName := "./packets.pcap"
	// 创建文件
	file, err := os.Create(fileName)
	if err != nil {
		return "", err
	}
	defer file.Close()
	write := bufio.NewWriter(file)
	// 1.写pacap header
	writePcapHeader(write)
	// 循环判断是否存在句柄
	for {
		// 下载句柄handle 4B
		handle := binary.BigEndian.Uint32(respData[4:8])
		// moreData 是否还有数据 1B
		moreData := respData[8:9][0]
		// 如果存在数据 就继续通过后handle请求获取下一页数据
		params["handle"] = handle
		//处理当前请求的数据包内容
		packetAllDataWritePcap(write, respData)
		if moreData <= 0 || handle <= 0 {
			break
		}
		respData, err = DownloadDataPacketsRal(baseURI, params)
		if err != nil {
			return "", err
		}
	}
	return fileName, nil
}

// packetAllDataWritePcap 获取数据包数据 并写入pcap文件中
func packetAllDataWritePcap(w *bufio.Writer, respData []byte) {
	// 响应数据包头部固定长度
	inteHeaderLen := 9
	// 响应数据长度
	dataLen := len(respData)
	var size int
	size += dataLen
	// 循环判断,并根据数据包下载片段重新定义inteHeaderLen,与响应长度进行比较
	for inteHeaderLen < dataLen {
		realData := respData[inteHeaderLen:]
		// 2.写packet header
		// 响应信息中实际的数据包内容 写入实际数据包内容,该数据长度是capLen
		capLen := writePacketHeader(w, realData)
		// 3.写packet body
		// 数据长度就是capLen个Byte,在此之后是一个新的Packet Header,新的Packet Data,如此循环
		writePacketData(w, realData[17:capLen+17])
		w.Flush()
		inteHeaderLen = inteHeaderLen + 17 + int(capLen)
	}
}

// writePcapHeader 写pacap头文件
func writePcapHeader(w *bufio.Writer) {
	/*
		pcap文件头:24字节(固定)
		Magic(4Byte):标记文件开始,并用来识别文件自己和字节顺序
		Major(2Byte): 当前文件主要的版本号
		Minor(2Byte): 当前文件次要的版本号
		ThisZone(4Byte):当地的标准时间,如果用的是GMT则全零,一般都直接写 0000 0000
		SigFigs(4Byte):时间戳的精度
		SnapLen(4Byte):最大的存储长度
		LinkType(4Byte):链路类型
	*/
	fileHeader := []byte("\xD4\xC3\xB2\xA1\x02\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x01\x00\x00\x00")
	w.Write(fileHeader)
}

// writePacketHeader 写packet头文件
func writePacketHeader(w *bufio.Writer, realData []byte) uint32 {
	/*
		存在多个packet header
		Timestamp(4Byte):被捕获时间的高位,精度为seconds
		Timestamp(4Byte):被捕获时间的低位,精度为microseconds
		Caplen(4Byte):当前数据区的长度,即抓取到的数据帧长度,不包括Packet Header本身的长度,单位是 Byte ,由此可以得到下一个数据帧的位置。
		Len(4Byte):离线数据长度:网络中实际数据帧的长度,一般不大于caplen,多数情况下和Caplen数值相等。
	*/
	var packatHeaderData []byte
	// timeNanosecond 时间戳8个字节(q)- 大端序
	timeNanosecond := binary.BigEndian.Uint64(realData[1:9])
	// pktLen 数据包长度是4字节(I) - 大端序
	pktLen := binary.BigEndian.Uint32(realData[9:23])
	// capLen 捕获长度是4字节(I),网络序 - 大端序
	capLen := binary.BigEndian.Uint32(realData[13:17])
	// 数据包头的秒时间戳
	timeSec := int(timeNanosecond / 1000000000)
	timeMsec := int64((int(timeNanosecond) - timeSec*1000000000) / 1000)
	// 获取高位时间戳
	timeMsec32 := make([]byte, 4)
	binary.LittleEndian.PutUint32(timeMsec32, uint32(timeMsec))
	packatHeaderData = append(packatHeaderData, timeMsec32...)
	packatHeaderData = append(packatHeaderData, timeMsec32...)
	// 数据包长度,表示所抓获的数据包保存在pcap文件中的实际长度
	capLen32 := make([]byte, 4)
	binary.LittleEndian.PutUint32(capLen32, uint32(capLen))
	packatHeaderData = append(packatHeaderData, capLen32...)
	// 数据包实际长度,所抓获的数据包的真实长度,如果文件中保存不是完整的数据包,则这个值可能要比前面的数据包长度值大
	pktLen32 := make([]byte, 4)
	binary.LittleEndian.PutUint32(pktLen32, uint32(pktLen))
	packatHeaderData = append(packatHeaderData, pktLen32...)
	w.Write(packatHeaderData)
	return capLen
}

// writePacketData 写packet文本信息
func writePacketData(w *bufio.Writer, packData []byte) {
	// 写packet data
	w.Write(packData)
}

// dataPacketsIsExist 查询数据包是否有数据
func dataPacketsIsExist(respData []byte) bool {
	if len(respData) == 0 {
		return false
	}
	if len(respData) == 9 && respData[8] != 1 {
		return false
	}
	return true
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值