电子工程师技术服务社区
公告
登录
|
注册
首页
技术问答
厂商活动
正点原子
板卡试用
资源库
下载
文章
社区首页
文章
《嵌入式设备端的网络报文在wireshark显示》-- 原理篇
分 享
扫描二维码分享
《嵌入式设备端的网络报文在wireshark显示》-- 原理篇
抓包
WIFI
Rice嵌入式开发
关注
发布时间: 2021-03-01
丨
阅读: 1042
## 背景: 1. 最近在项目中遇到一个问题,追溯WIFI模块是否丢包的问题。因为丢包的环节很多。 2. 我所有用到平台场景:主控(跑LWIP协议栈)+ SDIO wifi。 ![](https://RiceChen0.gitee.io/picture/SP2WS/1.png) - 在上面的场景中可能丢包的情况很多: 1. wifi模块没有接收到网络报文(空中丢包)。 2. wifi模块没有发送网络报文成功(空中丢包)。 3. 主控与wifi数据传输丢掉报文(SDIO传输丢包)。 3. 在设备端如果通过串口打印查看丢包现象是非常麻烦的,网络报文很多,而且无法辨别是否丢包。 4. 通过wireshark抓网络包,虽然可以清晰查看报文,但是无法判别wifi有没有收到网络报文,以及无法知道SDIO是否丢包。 5. 在第3点和第4点中都有缺点,串口可以知道设备端的报文,但无法辨别网络报文。wireshark可以清晰辨别报文,但是无法知道设备端的情况。如果将两者结合,就可以取长补短,便可以实现设备端网络报文清晰化。 6. 上述的操作来源于我的上级--老吴,非常感谢。他把这个思想交给了我,我将这个方法通过python实现完成。 7. 这个抓包工具命名为: SP2WS(serial packet to wireshark)通过串口抓取设备端网络报文,然后显示在wireshark中 - gitee: ## serial packet to wireshark的实现过程: - SP2WS的原理很简单,通过python实现串口抓取设备端的网络报文,然后将网络报文封装成wireshark能识别的数据包,wireshark的命名管道实现捕获,便可以在wireshark查看设备端的报文。如果想进一步了解情况wireshark的命名管道,可以直接到官网查看详细的说明。 - 官网链接:https://wiki.wireshark.org/CaptureSetup/Pipes - 描述实现原理之前,需要了解几个概念: ###### 命名管道 - 对于wireshark的命名管道的实现方法,官方提供了多种实现方法。而我们的SP2WS是采用python来实现的,我们参看如下的例子: ![](https://RiceChen0.gitee.io/picture/SP2WS/2.png) ###### python环境 - 该工具采用python3实现,所以PC端需要安装python3开发环境(记得是python3,python2需要自己修改)。 - 因为SP2WS采用串口抓包,如果你使用我的工具,运行报如下错误: 1. ``` Traceback (most recent call last): File ".\SP2WS.py", line 5, in
import serial ModuleNotFoundError: No module named 'serial' ``` - 解决: ``` pip insatll pyserial ``` 1. ``` Traceback (most recent call last): File ".\SP2WS.py", line 1, in
import win32pipe, win32file ModuleNotFoundError: No module named 'win32pipe' ``` - 解决: ``` pip install pypiwin32 ``` ###### wireshark的包格式 1. wireshark有多种保存文件格式,而pacp是比较简单的格式。我的工具也是采用这个格式捕获。 2. wireshark数据包格式如下,有一个文件头部,然后没有一个报文前面有一个报文头部。 ![](https://RiceChen0.gitee.io/picture/SP2WS/3.png) - pacp header格式: ``` struct pcap_file_header { uint32_t magic_number; /@@* magic number */ uint16_t version_major; /@@* major version number */ uint16_t version_minor; /@@* minor version number */ int32_t thiszone; /@@* GMT to local correction */ uint32_t sigfigs; /@@* accuracy of timestamps */ uint32_t snaplen; /@@* max length of captured packets, in octets */ uint32_t linktype; /@@* data link type */ } ``` | 字段 | 大小(Byte) | 含义 | |------|------|------| | magic_number | 4 | 用来标示文件的开始(值为: 0xA1, 0xB2, 0xC3, 0xD4) | | version_major | 2 | 当前文件主要的版本号(值为:0x00, 0x02) | | version_minor | 2 | 当前文件次要的版本号(值为:0x00, 0x04) | | thiszone | 4 | 当地的标准时间(值为:0) | | sigfigs | 4 | 时间戳的精度(值为:0) | | snaplen | 4 | 捕获数据包的最大长度(值为:0) | | linktype | 4 | 链路类型(值为:1)
0: BSD loopback devices, except for later OpenBSD
1: Ethernet, and Linux loopback devices
6: 802.5 Token Ring
7: ARCnet
8: SLIP
9: PPP
10: FDDI
100: LLC/SNAP-encapsulated ATM
101: "raw IP", with no link
102: BSD/OS SLIP
103: BSD/OS PPP
104: Cisco HDLC
105: 802.11
108: later OpenBSD loopback devices (with the AF_value in network byte order)
113: special Linux "cooked" capture
114: LocalTalk| - pcaprec header格式: ``` struct pcaprec_hdr { uint32_t ts_sec; /@@* timestamp seconds */ uint32_t ts_usec; /@@* timestamp microseconds (nsecs for PCAP_NSEC_MAGIC) */ uint32_t incl_len; /@@* number of octets of packet saved in file*/ uint32_t orig_len; /@@* actual length of packet */ }; ``` | 字段 | 大小(Byte) | 含义 | |------|------|------| | ts_sec | 4 | 时间戳高位,精确到seconds(值是自从January 1, 1970 00:00:00 GMT以来的秒数来记) | | ts_usec | 4 | 时间戳低位,精确到microseconds(数据包被捕获时候的微秒(microseconds)数,是自ts-sec的偏移量) | | incl_len | 4 | 当前数据区的长度,即抓取到的数据帧长度,由此可以得到下一个数据帧的位置。 | | orig_len | 4 | 网络中实际数据帧的长度,一般不大于caplen,多数情况下和Caplen数值相等。 | - packet:网络报文(工具中指的是串口抓到设备端的网络报文) #### 实现: 1. 设备端实现:代码比较简单,只需要网络报文加上头部和尾部。其中入参:buf--设备端接收到的网络报文,len--设备端接收到网络报文长度。 ``` #define PIPE_CAP_HDR_SIZE 3 #define PIPE_CAP_TAIL_SIZE 3 static void pipe_cap_dump(char *buf, int len) { char pipe_hdr[PIPE_CAP_HDR_SIZE] = {114, 116, 116}; char pipe_end[PIPE_CAP_TAIL_SIZE] = {101, 110, 100}; char *pipe_data = (char *)malloc(len + PIPE_CAP_HDR_SIZE + PIPE_CAP_TAIL_SIZE); if(pipe_data != NULL) { memcpy(pipe_data, pipe_hdr, PIPE_CAP_HDR_SIZE); memcpy(&pipe_data[PIPE_CAP_HDR_SIZE], buf, len); memcpy(&pipe_data[PIPE_CAP_HDR_SIZE + len], pipe_end, PIPE_CAP_TAIL_SIZE); uart_send(pipe_data, len + PIPE_CAP_HDR_SIZE + PIPE_CAP_TAIL_SIZE); free(pipe_data); pipe_data = NULL; } } ``` 2. SP2WS工具的实现:主要包含两个类,sp2ws_serial和sp2ws_pipe。 - sp2ws_serial类:主要实现串口的打开,关闭,读,写 ``` class sp2ws_serial(): def __init__(self, port, baudrate): self.port = port self.baudrate = baudrate def open(self): self.ser = serial.Serial(self.port, self.baudrate, timeout = 0.5) def close(self): self.ser.close() def read(self, length): return self.ser.read(length) def write(self, buff): self.ser.write(buff) ``` - sp2ws_pipe类:主要实现pipe的创建,连接(连接成功,会往pipe发送pacp的头部),pipe数据传输(传输报文前加上报文头部)。 ``` class sp2ws_pipe(): def __init__(self, pipe_name): self.magic_num = 0xa1b2c3d4 self.major_ver = 0x02 self.minor_ver = 0x04 self.link_type = 1 self.pipe_name = pipe_name def create_pipe(self): self.pipe = win32pipe.CreateNamedPipe( self.pipe_name, win32pipe.PIPE_ACCESS_OUTBOUND, win32pipe.PIPE_TYPE_MESSAGE | win32pipe.PIPE_WAIT, 1, 65536, 65536, 300, None) def connect_pipe(self): win32pipe.ConnectNamedPipe(self.pipe, None) # 文件头部 global_header = struct.pack('IHHiIII', self.magic_num, # magic number 4 self.major_ver, # major version number 2 self.minor_ver, # minor version number 2 0, # GMT to local correction 4 0, # accuracy of timestamps 4 0, # max length of captured packets, in octets 4 self.link_type # data link type 4 ) win32file.WriteFile(self.pipe, global_header) def write_pipe(self, packet): packet_len = len(packet) if packet_len <= 0: return # 报文头部 packet_header = struct.pack('IIII', int(time.time()), # timestamp seconds datetime.datetime.now().microsecond, # timestamp microseconds packet_len, # number of octets of packet packet_len # actual length of packet ) win32file.WriteFile(self.pipe, packet_header) win32file.WriteFile(self.pipe, packet) ``` - SP2WS工具业务逻辑实现: 1. 创建串口对象。 2. 创建pipe对象。 3. 连接pipe。 4. 读取串口数据,抓取有效网络报文。 5. 将网络报文发送到pipe中。 6. 代码如下: ``` if __name__ == "__main__": if len(sys.argv) < 3: print("SP2WS.py com[port_num] wifi_master [ssid] [pwd]") print("SP2WS.py com[port_num] wifi_slave") print(r'\\.\pipe\wifi_master') print(r'\\.\pipe\wifi_slave') port = sys.argv[1].upper() if sys.argv[2].find("wifi_master") > -1: ssid = sys.argv[3] password = sys.argv[4] wifi_connect = r'wifi join ' + ssid + ' ' + password pipe_name = r'\\.\pipe' + '\\' + sys.argv[2] # 创建串口对象。 sp2ws_serial = sp2ws_serial(port, 115200) sp2ws_serial.open() # 创建pipe对象 sp2ws_pipe = sp2ws_pipe(pipe_name) sp2ws_pipe.create_pipe() print("start connect pipi...") # 连接pipe sp2ws_pipe.connect_pipe() print("pipe connect success!!!") raw_buf = bytearray() start = 0 init = 0 if sys.argv[2].find("wifi_master") > -1: sp2ws_serial.write(bytes(wifi_connect + "\r\n", encoding='utf-8')) sp2ws_serial.write(bytes("pipe_start\r\n", encoding='utf-8')) while True: # 读取串口数据 raw = sp2ws_serial.read(1024) raw_len = len(raw) if raw_len > 0: raw_buf = raw_buf + raw # 抓取有效网络报文 while True: raw_len = len(raw_buf) # find packet header for index in range(raw_len): if (index + 2) < (raw_len - 1): if raw_buf[index] == 114 and raw_buf[index + 1] == 116 and raw_buf[index + 2] == 116: start = index + 3 break start = 0 else: start = 0 break if start == 0: break # find packet tail for index in range(start, raw_len): if (index + 2) < (raw_len - 1): if raw_buf[index] == 101 and raw_buf[index + 1] == 110 and raw_buf[index + 2] == 100: end = index break end = 0 else: end = 0 break if end == 0: break frame = raw_buf[start : end] # 将网络报文发送到pipe中 sp2ws_pipe.write_pipe(frame) end += 3 raw_buf = raw_buf[end : ] ```
关注微信公众号『Rice嵌入式开发技术分享』,后台回复“微信”添加作者微信,备注”入群“,便可邀请进入技术交流群。 ![](https://RiceChen0.gitee.io/picture/logo/logo_.jpg)
原创作品,未经权利人授权禁止转载。详情见
转载须知
。
举报文章
点赞
(
0
)
Rice嵌入式开发
关注
评论
(0)
登录后可评论,请
登录
或
注册
相关文章推荐
MK-米客方德推出工业级存储卡
Beetle ESP32 C3 蓝牙数据收发
Beetle ESP32 C3 wifi联网获取实时天气信息
开箱测评Beetle ESP32-C3 (RISC-V芯片)模块
正点原子数控电源DP100测评
DP100试用评测-----开箱+初体验
Beetle ESP32 C3环境搭建
【花雕体验】16 使用Beetle ESP32 C3控制8X32位WS2812硬屏之二
X
你的打赏是对原创作者最大的认可
请选择打赏IC币的数量,一经提交无法退回 !
100IC币
500IC币
1000IC币
自定义
IC币
确定
X
提交成功 ! 谢谢您的支持
返回
我要举报该内容理由
×
广告及垃圾信息
抄袭或未经授权
其它举报理由
请输入您举报的理由(50字以内)
取消
提交