Appearance
Appearance
命名管道看起来像一个文件,但它实际上只是用于进程间通信的缓冲区。一个进程可以向其中发送数据,另一个进程可以读取它。创建命名管道主要有两种方式:使用 mkfifo,或使用 bash shell 的特殊语法。
如果你有一个格式正确的捕获文件(来自 Wireshark 或 tcpdump),可以执行以下操作:
$ mkfifo /tmp/sharkfin$ wireshark -k -i /tmp/sharkfin &$ cat capture.cap > /tmp/sharkfin &这应该会从命名管道 /tmp/sharkfin 启动捕获。在你启动最后一个命令后,文件中的数据包列表应该会开始出现在屏幕上。
可以在 Jesús Roncero 的博客中找到一个使用管道进行远程捕获的示例。
你可以使用特殊的 bash/Korn shell 语法执行完全相同的操作:
$ wireshark -k -i <(cat capture.cap)下面这个小型 Python 脚本展示了如何在 Windows 上使用 Python:
# Win32 Wireshark named pipes example# Requires Python for Windows and the Python for Windows Extensions:# http://www.python.org# http://sourceforge.net/projects/pywin32/import win32pipe, win32fileimport timeimport subprocess#open Wireshark, configure pipe interface and start capture (not mandatory, you can also do this manually)wireshark_cmd=['C:\Program Files\Wireshark\Wireshark.exe', r'-i\\.\pipe\wireshark','-k']proc=subprocess.Popen(wireshark_cmd)#create the named pipe \\.\pipe\wiresharkpipe = win32pipe.CreateNamedPipe( r'\\.\pipe\wireshark', win32pipe.PIPE_ACCESS_OUTBOUND, win32pipe.PIPE_TYPE_MESSAGE | win32pipe.PIPE_WAIT, 1, 65536, 65536, 300, None)#connect to pipewin32pipe.ConnectNamedPipe(pipe, None)#open and read an arbitrary pcap file (file must in same folder than script)cf = open(r'pipetest.pcap', 'rb')data = cf.read()#wait 2 second (not mandatory, but this let watching data coming trough the pipe)time.sleep(2)#send pcap data trough the pipewin32file.WriteFile(pipe, data)#then pcap data appears into wireshark相关的有用链接:
注意:此示例没有展示 pcap format header 或 packet data 的编码。在 SourceForge.net 上的 BACnet MS/TP capture utility 中,有一个使用 C 中的命名管道并包含 pcap header 和 packet data 编码的完整示例。
此外,这可能也有用
#include <stdio.h>#include <windows.h>static HANDLE hPipe = NULL; /* pipe handle */static void print_last_error(void){ LPVOID lpMsgBuf; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) & lpMsgBuf, 0, NULL); MessageBox(NULL, lpMsgBuf, "GetLastError", MB_OK | MB_ICONINFORMATION); LocalFree(lpMsgBuf);}static void named_pipe_create(void){ hPipe = CreateNamedPipe( "\\\\.\\pipe\\wireshark", PIPE_ACCESS_OUTBOUND, PIPE_TYPE_MESSAGE | PIPE_WAIT, 1, 65536, 65536, 300, NULL); if (hPipe == INVALID_HANDLE_VALUE) { print_last_error(); return; } ConnectNamedPipe(hPipe, NULL);}DWORD data_write(const void *ptr, size_t size, size_t nitems){ DWORD cbWritten = 0; if (hPipe) { (void)WriteFile(hPipe, ptr, size*nitems, &cbWritten, NULL); } return cbWritten;}void cleanup(void){ if (hPipe) { FlushFileBuffers(hPipe); DisconnectNamedPipe(hPipe); CloseHandle(hPipe); }}int main( int argc, char *argv[]){ FILE *pFile = NULL; char *pFilename = {"c:\\pipetest.pcap"}; char buffer[512] = {""}; size_t num_read = 0; if (argc > 1) { pFilename = argv[1]; } pFile = fopen(pFilename, "rb"); if (pFile) { named_pipe_create(); while ((num_read = fread(buffer,1,sizeof(buffer),pFile)) == sizeof(buffer)) { data_write(buffer, 1, num_read); } /* write remaining stuff */ if (num_read) { data_write(buffer, 1, num_read); } fclose(pFile); } cleanup(); return 0;}在 .NET 上,NamedPipeServerStream 类对于命名管道的使用相当简单。为了生成两个 pcap headers,将 struct 转换为 Byte Array 也并不困难。
由于 NamedPipeServerStream 连接是阻塞的,可以使用后台线程来等待 Wireshark 连接。
请查看附件文件:WiresharkSender.cs
在上述所有情况下,你都不能使用 Wireshark 中的按钮来(重新)启动捕获,因为馈送进程无法知道应该启动新的捕获。此外,在 Wireshark 终止后,馈送进程可能不会被杀死。我认为如果你在关闭 Wireshark 之前停止捕获,它会被杀死,但我不太确定原因。
曾有过一次简短讨论,认为馈送进程可以检测管道未连接,然后在它再次连接后重新启动捕获。因此,如果你相应地编写馈送进程,也许这是可行的。在 Linux 上,可以使用 poll 或 epoll system calls 来完成这一点;当 Wireshark 关闭 FIFO 时,它们会发出 POLLIN/EPOLLIN event。作为示例,请参见这个 capture tool。
还有两个补丁支持从 TCP network connect(它有明确的连接序列)以及从派生的子进程读取。这两个补丁都应该能解决这个特定问题。
当然,这些示例实际上并不实用,因为你完全可以直接读取文件。在真实场景中,馈送进程可以是远程捕获进程、串口 packetizer,或专用应用程序。请注意,命名管道接口期望接收一个 PCAP header,然后是一系列 PCAP packets。
在 bash 语法中,可以使用以下命令进行远程捕获:
> wireshark -k -i <(ssh -l root remote-host "dumpcap -P -w - -f 'not tcp port 22'")主要问题是,你必须从捕获中排除 ssh session 生成的流量。有几个补丁可以做到这一点,但目前排除 port 22 可能是最简单的解决方案。
第二个问题是 ssh 不能在 stdin 上请求密码。你应该设置 ssh-agent,这样就不需要密码;或者配置 x-askpass 打开一个窗口来输入密码。
可以通过将 SSH 与 FIFO 结合来绕过这个问题。
$ mkfifo /tmp/sharkfin$ wireshark -k -i /tmp/sharkfin &$ ssh user@remote-host "dumpcap -P -w - -f 'not tcp port 22'" > /tmp/sharkfin一旦 Wireshark 开始在管道上“监听”,SSH 就会提示输入密码并允许你继续。Wireshark 也可以替换为 tshark,tcpdump 可以用来代替 dumpcap,只需对上述命令做轻微变化。
有时你想显示来自某个网络的流量,而常规捕获工具(如 tshark、tcpdump 和 snoop)无法访问该网络。你可能有自己的应用程序来捕获流量,而 Wireshark 可以读取捕获文件,但如何将它与 Wireshark 对接,以便实时显示跟踪?
管道就是答案。只要你使用事实标准 libpcap format,就应该能够将捕获写入命名管道,并让 Wireshark 从这个管道读取以实时查看数据包。
如 man page 中所述,你可以使用减号作为接口名称,从 stdin 捕获。Stdin 是每个进程预定义的文件描述符,它通常由调用该进程的 shell 连接到匿名管道。因此,通过从 stdin 读取,你应该能够将上面的命令改写为
$ cat capture.cap | wireshark -k -i -cat utility 在到达文件末尾时返回;如果想实现等同于从一个随时间增长的文件进行实时捕获,请改用 tail,传入 follow argument,并让它从开头开始:
$ tail -f -c +0 capture.cap | wireshark -k -i -虽然文档说 Wireshark 应该能够从 stdin(即匿名管道)捕获,但并不清楚它是否总是有效。有些人报告成功,但对我来说它只适用于 tshark,不适用于 wireshark。也许这与下面的 bug 有关?
请注意:此功能并不适用于所有版本的 libiconv,因为它会将 - 符号解释为新参数的开始,请参见:bug #265
XXX - 这是否同时适用于命令行和交互式用法?
Wireshark 也可以使用 -i TCP@<addr>[:port] 选项,连接到一个或多个通过 TCP ports 提供的 libpcap 或 pcapng 格式的流。TCP 区分大小写。
$ wireshark -k -i TCP@127.0.0.1:19000$ wireshark -k -i TCP@192.168.1.123其中,如果省略 port,默认值为 19000。从 wireshark v3.1.1 开始,使用方括号包围由冒号 (😃 分隔的 IPv6 地址,并在后面跟可选的 :port 时,也支持 IPv6 addresses。
$ wireshark -k -i TCP@[::1]:19000$ wireshark -k -i TCP@[2001:db8:a0b:12f0::1]$ wireshark -k -i TCP@[::1]:19000 -i TCP@127.0.0.1:19001TCP stream 会像来自其他管道的数据一样处理,并适用相同限制。每次新连接时,TCP server 必须在任何 packet captures 之前发送 libpcap 或 pcapng 所规定的 header blocks。TCP@ pipes 也可以在 GUI 的 Menu Capture/Options..., Manage Interfaces..., Pipes Tab 中添加,但 Wireshark 不会保存 pipe settings。
导入自 https://wiki.wireshark.org/CaptureSetup/Pipes ,时间为 2020-08-11 23:12:00 UTC