Prechádzať zdrojové kódy

tcpdump first version

neverxie 7 rokov pred
rodič
commit
c3efe4a661
4 zmenil súbory, kde vykonal 1058 pridanie a 0 odobranie
  1. 2 0
      README.md
  2. 305 0
      tcpdump/README.md
  3. 16 0
      tcpdump/SConscript
  4. 735 0
      tcpdump/tcpdump.c

+ 2 - 0
README.md

@@ -22,3 +22,5 @@
 |[NetIO](netio/README.md)|性能测试|测试网络的吞吐量的工具|[点击查看](netio/README.md)|
 |[NTP](ntp/README.md)|时间同步|网络时间协议|[点击查看](ntp/README.md)|
 |[Telnet](telnet/README.md)|远程访问|可以远程登录到 RT-Thread 的 Finsh/MSH Shell|[点击查看](telnet/README.md)|
+|[tcpdump](tcpdump/README.md)|网络调试|tcpdump 是 RT-Thread 基于 lwip 的网络抓包工具|[点击查看](tcpdump/README.md)|
+

+ 305 - 0
tcpdump/README.md

@@ -0,0 +1,305 @@
+# tcpdump
+
+## 1、介绍
+这是一个基于 RT-Thread 的捕获IP报文的小工具, 抓包的数据可以通过文件系统保存,或者通过 rdb 工具导入PC,利用 wireshark 软件解析。
+
+
+
+### 1.1、依赖
+
+- 依赖 [optparse](https://github.com/liu2guang/optparse) 软件包 
+- 依赖 [dfs](https://www.rt-thread.org/document/site/rtthread-development-guide/rtthread-manual-doc/zh/1chapters/12-chapter_filesystem/) 文件系统
+- 依赖 [env](https://www.rt-thread.org/document/site/rtthread-development-guide/rtthread-tool-manual/env/env-user-manual/) 工具
+- RT-Thread 3.0+,对 bsp 无依赖
+
+### 1.2、获取方式
+- 使用 menuconfig 使能 tcpdump,详情如下: 
+
+```
+  RT-Thread online packages --->
+      IOT internet of things --->
+          [*] netutils: Networking utilities for RT-Thread  --->
+          [*]   Enable tcpdump tool
+          [ ]     Enable tcpdump data to print on the console
+          [*]     Enable tcpdump debug log output
+```
+保存 menuconfig 配置后使用 `pkgs --update` 命令下载软件包
+
+> 注:调试信息建议不关闭
+
+
+
+## 2、使用
+
+### 2.1、tcpdump命令含义
+
+```
+-i: 指定监听的网络接口
+-m: 选择保存模式(文件系统 或 rdb)
+-w: 用户指定的文件名 xx.pcap
+-p: 停止抓包
+-h: 帮助信息
+```
+
+### 2.2、命令详情
+```
+msh />tcpdump -h
+
+|>------------------------- help -------------------------<|
+| tcpdump [-p] [-h] [-i interface] [-m mode] [-w file]     |
+|                                                          |
+| -h: help                                                 |
+| -i: specify the network interface for listening          |
+| -m: choose what mode(file-system or rdb) to save the file|
+| -w: write the captured packets into an xx.pcap file      |
+| -p: stop capturing packets                               |
+|                                                          |
+| e.g.:                                                    |
+| specify network interface and select save mode \         |
+| and specify filename                                     |
+| tcpdump -ie0 -mfile -wtext.pcap                          |
+| tcpdump -ie0 -mrdb -wtext.pcap                           |
+|                                                          |
+| -m: file-system mode                                     |
+| tcpdump -mfile                                           |
+|                                                          |
+| -m: rdb mode                                             |
+| tcpdump -mrdb                                            |
+|                                                          |
+| -w: file                                                 |
+| tcpdump -wtext.pcap                                      |
+|                                                          |
+| -p: stop                                                 |
+| tcpdump -p                                               |
+|                                                          |
+| -h: help                                                 |
+| tcpdump -h                                               |
+|                                                          |
+| write commands but no arguments are illegal!!            |
+| e.g.: tcpdump -i / -i -mfile  / -i -mfile -wtext.pcap    |
+|>------------------------- help -------------------------<|
+
+msh />
+```
+
+
+
+## 3、使用文件系统保存抓包的数据
+
+> 我们这里是把 sd-card 挂载文件系统
+
+### 3.1、抓包前准备
+
+开发板上电前,插入 sd-card
+
+- 挂载成功,则提示:
+
+```
+SD card capacity 31023104 KB
+probe mmcsd block device!
+found part[0], begin: 10485760, size: 29.580GB
+File System initialized!
+```
+
+- 挂载失败,则提示:
+
+```
+sdcard init fail or timeout: -2!
+```
+
+- 挂载成功,输入 `list_device` 可以看到 `sd0` 设备,详情如下:
+
+```
+msh />list_device
+device         type         ref count
+------ -------------------- ---------
+sd0    Block Device         1       
+e0     Network Interface    0             
+usbd   USB Slave Device     0                   
+rtc    RTC                  1       
+spi4   SPI Bus              0       
+pin    Miscellaneous Device 0       
+uart1  Character Device     3       
+msh />
+```
+
+### 3.2、抓包前检查
+
+> 抓包前请确认板子的 IP 地址
+
+
+- msh />里,输入 `ifconfig` 查看,详情如下:
+
+```
+msh />
+network interface: e0 (Default)
+MTU: 1500
+MAC: 00 04 9f 05 44 e5 
+FLAGS: UP LINK_UP ETHARP BROADCAST
+ip address: 192.168.1.137
+gw address: 192.168.1.1
+net mask  : 255.255.255.0
+dns server #0: 192.168.1.1
+dns server #1: 0.0.0.0
+msh />
+```
+
+### 3.3、开始抓包
+
+- msh />里,输入 `tcpdump -ie0 -mfile -wtext.pcap`,详情如下:
+
+```
+msh />tcpdump -ie0 -msd -wtext.pcap
+[TCPDUMP]select  [e0] network card device
+[TCPDUMP]select  [file-system] mode
+[TCPDUMP]save in [text.pcap]
+[TCPDUMP]tcpdump start!
+msh />
+```
+
+- 使用抓包命令会创建一个线程,线程的优先级是12。
+- 输入 `list_thread` 命令查看运行中的线程,线程名字是 `tdth`,详情如下:
+
+```
+thread   pri  status      sp     stack size max used left tick  error
+-------- ---  ------- ---------- ----------  ------  ---------- ---
+tdth      12  suspend 0x000000ac 0x00000800    08%   0x0000000a 000
+tshell    20  ready   0x00000070 0x00001000    22%   0x00000003 000
+rp80       8  suspend 0x0000009c 0x00000400    15%   0x0000000a 000
+phy       30  suspend 0x00000070 0x00000200    28%   0x00000001 000
+usbd       8  suspend 0x00000098 0x00001000    03%   0x00000014 000
+tcpip     10  suspend 0x000000b4 0x00000400    39%   0x00000014 000
+etx       12  suspend 0x00000084 0x00000400    12%   0x00000010 000
+erx       12  suspend 0x00000084 0x00000400    34%   0x00000010 000
+mmcsd_de  22  suspend 0x0000008c 0x00000400    49%   0x00000013 000
+tidle     31  ready   0x00000054 0x00000100    32%   0x0000001a 000
+main      10  suspend 0x00000064 0x00000800    35%   0x00000010 000
+msh />
+```
+
+
+### 3.4、抓包测试
+
+> 使用 [ping ](https://github.com/RT-Thread-packages/netutils/blob/master/ping/README.md) 命令来进行抓包测试,`ping` 命令需要在 menuconfig 配置使能,详情如下:
+
+```
+  RT-Thread online packages --->
+      IOT internet of things --->
+          [*] Enable Ping utility
+```
+保存 menuconfig 配置后使用 `pkgs --update` 命令下载软件包
+
+#### 3.4.1、ping 域名
+
+- msh />里输入 `ping rt-thread.org`,详情如下:
+
+```
+msh />ping rt-thread.org
+60 bytes from 116.62.244.242 icmp_seq=0 ttl=49 time=11 ticks
+60 bytes from 116.62.244.242 icmp_seq=1 ttl=49 time=10 ticks
+60 bytes from 116.62.244.242 icmp_seq=2 ttl=49 time=12 ticks
+60 bytes from 116.62.244.242 icmp_seq=3 ttl=49 time=10 ticks
+msh />
+```
+
+#### 3.4.2、ping IP
+
+- msh />里输入 `ping 192.168.1.121`,详情如下: 
+
+```
+msh />ping 192.168.1.121
+60 bytes from 192.168.10.121 icmp_seq=0 ttl=64 time=5 ticks
+60 bytes from 192.168.10.121 icmp_seq=1 ttl=64 time=1 ticks
+60 bytes from 192.168.10.121 icmp_seq=2 ttl=64 time=2 ticks
+60 bytes from 192.168.10.121 icmp_seq=3 ttl=64 time=3 ticks
+msh />
+```
+
+### 3.5、停止抓包
+
+- msh />里,输入 `tcpdump -p`,详情如下:
+
+```
+msh />tcpdump -p
+[TCPDUMP]tcpdump stop and tcpdump thread exit!
+msh />
+```
+
+### 3.6、查看结果
+
+- msh />里,输入 `ls` 查看保存结果,详情如下:
+
+```
+msh />ls
+Directory /:
+System Volume Information<DIR>                    
+text.pcap         1012                     
+msh />
+```
+
+### 3.7、抓包后处理
+
+使用读卡器将保存在 sd-card 里的 xx.pcap 文件拷贝到 PC,使用抓包软件 wireshark 直接进行网络流的分析
+
+
+
+## 4、抓包文件通过 rdb 工具导入PC
+
+### 4.1、开启抓包
+
+- msh />里,输入 `tcpdump -ie0 -mrdb -wtext.pcap`,详情如下:
+
+```
+msh />tcpdump -ie0 -mrdb -wtext.pcap
+[TCPDUMP]select  [e0] network card device
+[TCPDUMP]select  [rdb] mode
+[TCPDUMP]save in [text.pcap]
+[TCPDUMP]tcpdump start!
+msh />
+```
+
+### 4.2、抓包测试
+
+- 请参考 3.4 的操作
+
+### 4.3、停止抓包
+
+- msh />里,输入 `tcpdump -p`,详情如下:
+
+```
+msh />tcpdump -p
+[TCPDUMP]tcpdump stop and tcpdump thread exit!
+msh />
+```
+
+### 4.4、查看结果
+
+- msh />里,输入 `ls` 查看保存结果,详情如下:
+
+```
+msh />ls
+Directory /:
+System Volume Information<DIR>                    
+text.pcap         1012                     
+msh />
+```
+
+### 4.5、抓包后处理
+
+使用 rdb 工具将 xx.pcap 文件导入到PC,使用抓包软件 wireshark 直接进行网络流的分析
+
+
+
+## 5、注意事项
+
+- tcpdump 工具是需要开启 lwip 的 发送、接收线程的
+- 抓包结束或者不想抓包了,请输入 `tcpdump -p` 结束抓包
+
+
+
+## 6、联系方式 & 感谢
+
+* 感谢:[liu2guang](https://github.com/liu2guang) 制作了 optprase 软件包
+* 感谢:[uestczyh222](https://github.com/uestczyh222) 制作了 rdb 工具 & rdb 上位机
+* 维护:[never](https://github.com/neverxie)
+* 主页:https://github.com/RT-Thread-packages/netutils

+ 16 - 0
tcpdump/SConscript

@@ -0,0 +1,16 @@
+from building import *
+import rtconfig
+
+cwd  = GetCurrentDir()
+
+src         = []
+CPPPATH     = []
+LIBS        = []
+LIBPATH     = []
+
+#src
+src += Glob('*.c')
+
+group = DefineGroup('tcpdump', src, depend = ['PKG_NETUTILS_TCPDUMP'], CPPPATH = CPPPATH, LIBS = LIBS, LIBPATH = LIBPATH)
+
+Return('group')

+ 735 - 0
tcpdump/tcpdump.c

@@ -0,0 +1,735 @@
+/*
+ * File      : tcpdump.c
+ * This is file that captures the IP message based on the RT-Thread
+ * and saves in the file system.
+ * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-07-13     never        the first version
+ */
+
+#include <rtthread.h>
+#include <dfs_posix.h>
+#include <rtdef.h>
+#include "netif/ethernetif.h"
+#include "optparse.h"
+
+#ifdef PKG_NETUTILS_TCPDUMP_DBG
+    #define DBG_ENABLE
+
+    #define DBG_SECTION_NAME  "TCPDUMP"
+    #define DBG_LEVEL         DBG_INFO
+    #define DBG_COLOR
+#else
+    #undef  DBG_ENABLE
+#endif
+#include <rtdbg.h>
+
+#define TCPDUMP_PIPE_DEVICE         ("urdbd")           /* rdb pipe */
+
+#define TCPDUMP_DEFAULT_NANE        ("sample.pcap")
+
+#define TCPDUMP_MAX_MSG             (10)
+#define PCAP_FILE_HEADER_SIZE       (24)
+#define PCAP_PKTHDR_SIZE            (16)
+
+#define PCAP_FILE_ID                (0xA1B2C3D4)
+#define PCAP_VERSION_MAJOR          (0x200)
+#define PCAP_VERSION_MINOR          (0x400)
+#define GREENWICH_MEAN_TIME         (0)
+#define PRECISION_OF_TIME_STAMP     (0)
+#define MAX_LENTH_OF_CAPTURE_PKG    (0xFFFF)
+
+#define LINKTYPE_NULL               (0)
+#define LINKTYPE_ETHERNET           (1)                 /* also for 100Mb and up */
+#define LINKTYPE_EXP_ETHERNET       (2)                 /* 3Mb experimental Ethernet */
+#define LINKTYPE_AX25               (3)
+#define LINKTYPE_PRONET             (4)
+#define LINKTYPE_CHAOS              (5)
+#define LINKTYPE_TOKEN_RING         (6)                 /* DLT_IEEE802 is used for Token Ring */
+#define LINKTYPE_ARCNET             (7)
+#define LINKTYPE_SLIP               (8)
+#define LINKTYPE_PPP                (9)
+#define LINKTYPE_FDDI               (10)
+#define LINKTYPE_PPP_HDLC           (50)                /* PPP in HDLC-like framing */
+#define LINKTYPE_PPP_ETHER          (51)                /* NetBSD PPP-over-Ethernet */
+#define LINKTYPE_ATM_RFC1483        (100)               /* LLC/SNAP-encapsulated ATM */
+#define LINKTYPE_RAW                (101)               /* raw IP */
+#define LINKTYPE_SLIP_BSDOS         (102)               /* BSD/OS SLIP BPF header */
+#define LINKTYPE_PPP_BSDOS          (103)               /* BSD/OS PPP BPF header */
+#define LINKTYPE_C_HDLC             (104)               /* Cisco HDLC */
+#define LINKTYPE_IEEE802_11         (105)               /* IEEE 802.11 (wireless) */
+#define LINKTYPE_ATM_CLIP           (106)               /* Linux Classical IP over ATM */
+#define LINKTYPE_LOOP               (108)               /* OpenBSD loopback */
+#define LINKTYPE_LINUX_SLL          (113)               /* Linux cooked socket capture */
+#define LINKTYPE_LTALK              (114)               /* Apple LocalTalk hardware */
+#define LINKTYPE_ECONET             (115)               /* Acorn Econet */
+#define LINKTYPE_CISCO_IOS          (118)               /* For Cisco-internal use */
+#define LINKTYPE_PRISM_HEADER       (119)               /* 802.11+Prism II monitor mode */
+#define LINKTYPE_AIRONET_HEADER     (120)               /* FreeBSD Aironet driver stuff */
+
+#define MSH_CMD ("phi::m::w::")                         /* [-p] [-h] [-i] [-m] [-w] */
+#define STRCMP(a, R, b)   (rt_strcmp((a), (b)) R 0)
+
+#define PACP_FILE_HEADER_CREATE(_head)                          \
+do {                                                            \
+    (_head)->magic = PCAP_FILE_ID;                              \
+    (_head)->version_major = PCAP_VERSION_MAJOR;                \
+    (_head)->version_minor = PCAP_VERSION_MINOR;                \
+    (_head)->thiszone = GREENWICH_MEAN_TIME;                    \
+    (_head)->sigfigs = PRECISION_OF_TIME_STAMP;                 \
+    (_head)->snaplen = MAX_LENTH_OF_CAPTURE_PKG;                \
+    (_head)->linktype = LINKTYPE_ETHERNET;                      \
+} while (0)
+
+#define PACP_PKTHDR_CREATE(_head, _p)                           \
+do{                                                             \
+    (_head)->ts.tv_sec = rt_tick_get() / RT_TICK_PER_SECOND;    \
+    (_head)->ts.tv_msec = rt_tick_get() % RT_TICK_PER_SECOND;   \
+    (_head)->caplen = _p->tot_len;                              \
+    (_head)->len = _p->tot_len;                                 \
+} while (0)
+
+struct rt_pcap_file_header
+{
+    rt_uint32_t magic;
+    rt_uint16_t version_major;
+    rt_uint16_t version_minor;
+    rt_int32_t thiszone;
+    rt_uint32_t sigfigs;
+    rt_uint32_t snaplen;
+    rt_uint32_t linktype;
+};
+
+struct rt_timeval
+{
+    rt_uint32_t tv_sec;
+    rt_uint32_t tv_msec;
+};
+
+struct rt_pcap_pkthdr
+{
+    struct rt_timeval ts;
+    rt_uint32_t caplen;
+    rt_uint32_t len;
+};
+
+enum rt_tcpdump_return_param
+{
+    STOP = -2,
+    HELP = -3,
+};
+
+static struct rt_device *tcpdump_pipe;
+static struct rt_mailbox *tcpdump_mb;
+
+static struct netif *netif;
+static netif_linkoutput_fn link_output;
+static netif_input_fn input;
+
+static const char *name;
+static char *filename;
+static const char *eth;
+static char *ethname;
+static const char *mode;
+static int fd = -1;
+
+static void rt_tcpdump_filename_del(void);
+static void rt_tcpdump_ethname_del(void);
+static void rt_tcpdump_error_info_deal(void);
+static void rt_tcpdump_init_indicate(void);
+static rt_err_t rt_tcpdump_pcap_file_save(const void *buf, int len);
+
+static rt_err_t (*tcpdump_write)(const void *buf, int len);
+
+#ifdef  PKG_NETUTILS_TCPDUMP_PRINT
+#define __is_print(ch) ((unsigned int)((ch) - ' ') < 127u - ' ')
+static void hex_dump(const rt_uint8_t *ptr, rt_size_t buflen)
+{
+    unsigned char *buf = (unsigned char *)ptr;
+    int i, j;
+
+    RT_ASSERT(ptr != RT_NULL);
+
+    for (i = 0; i < buflen; i += 16)
+    {
+        rt_kprintf("%08X: ", i);
+
+        for (j = 0; j < 16; j++)
+            if (i + j < buflen)
+                rt_kprintf("%02X ", buf[i + j]);
+            else
+                rt_kprintf("   ");
+        rt_kprintf(" ");
+
+        for (j = 0; j < 16; j++)
+            if (i + j < buflen)
+                rt_kprintf("%c", __is_print(buf[i + j]) ? buf[i + j] : '.');
+        rt_kprintf("\n");
+    }
+}
+#endif
+
+/* get tx data */
+static err_t _netif_linkoutput(struct netif *netif, struct pbuf *p)
+{
+    RT_ASSERT(netif != RT_NULL);
+
+    if (p != RT_NULL)
+    {
+        pbuf_ref(p);
+
+        if (rt_mb_send(tcpdump_mb, (rt_uint32_t)p) != RT_EOK)
+        {
+            pbuf_free(p);
+        }
+    }
+    return link_output(netif, p);
+}
+
+/* get rx data */
+static err_t _netif_input(struct pbuf *p, struct netif *inp)
+{
+    RT_ASSERT(inp != RT_NULL);
+
+    if (p != RT_NULL)
+    {
+        pbuf_ref(p);
+        if (rt_mb_send(tcpdump_mb, (rt_uint32_t)p) != RT_EOK)
+        {
+            pbuf_free(p);
+        }
+    }
+    return input(p, inp);
+}
+
+/* import pcap file into your PC through file-system */
+static rt_err_t rt_tcpdump_pcap_file_write(const void *buf, int len)
+{
+    int length;
+
+    if (filename == RT_NULL)
+    {
+        dbg_log(DBG_ERROR, "file name is null!\n");
+        return -RT_ERROR;
+    }
+
+    if ((len == 0) && (fd > 0))
+    {
+        dbg_log(DBG_ERROR, "ip mess error and close file!\n");
+        close(fd);
+        fd = -1;
+        return -RT_ERROR;
+    }
+
+    if (fd < 0)
+    {
+        fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0);
+        if (fd < 0)
+        {
+            dbg_log(DBG_ERROR, "open file failed!\n");
+            return -RT_ERROR;
+        }
+    }
+
+    length = write(fd, buf, len);
+    if (length != len)
+    {
+        dbg_log(DBG_ERROR, "write data failed, length: %d\n", length);
+        close(fd);
+        return -RT_ERROR;
+    }
+
+    return RT_EOK;
+}
+
+/* Import pcap file into your PC through rdb tools */
+static rt_err_t rt_tcpdump_pcap_file_save(const void *buf, int len)
+{
+    rt_device_write(tcpdump_pipe, 0, buf, len);
+    return RT_EOK;
+}
+
+/* write ip mess and print */
+static void rt_tcpdump_ip_mess_write(struct pbuf *p)
+{
+    rt_uint8_t *buf = (rt_uint8_t *)rt_malloc(p->tot_len);
+
+    RT_ASSERT(buf != RT_NULL);
+
+    pbuf_copy_partial(p, buf, p->tot_len, 0);
+
+#ifdef PKG_NETUTILS_TCPDUMP_PRINT
+    hex_dump(buf, p->tot_len);
+#endif
+
+    /* write ip mess */
+    if (tcpdump_write != RT_NULL)
+        tcpdump_write(buf, p->tot_len);
+
+    rt_free(buf);
+}
+
+/* write pcap file header */
+static rt_err_t rt_tcpdump_pcap_file_init(void)
+{
+    struct rt_pcap_file_header file_header;
+    int res = -1;
+
+    if (tcpdump_pipe != RT_NULL)
+    {
+        if (rt_device_open(tcpdump_pipe, RT_DEVICE_OFLAG_WRONLY) != RT_EOK)
+        {
+            dbg_log(DBG_LOG, "not found pipe device!\n");
+            return -RT_ERROR;
+        }
+    }
+
+    /* in rdb mode does not need to write pcap file header */
+    if ((tcpdump_write != RT_NULL) && (tcpdump_write == rt_tcpdump_pcap_file_write))
+    {
+        PACP_FILE_HEADER_CREATE(&file_header);
+        res = tcpdump_write(&file_header, sizeof(file_header));
+    }
+
+#ifdef  PKG_NETUTILS_TCPDUMP_PRINT
+    hex_dump((rt_uint8_t *)&file_header, PCAP_FILE_HEADER_SIZE);
+#endif
+
+    if (res != RT_EOK)
+        return -RT_ERROR;
+
+    return RT_EOK;
+}
+
+static void rt_tcpdump_thread_entry(void *param)
+{
+    struct pbuf *pbuf = RT_NULL;
+    struct rt_pcap_pkthdr pkthdr;
+    rt_uint32_t mbval;
+
+    while (1)
+    {
+        if (rt_mb_recv(tcpdump_mb, &mbval, RT_WAITING_FOREVER) == RT_EOK)
+        {
+            pbuf = (struct pbuf *)mbval;
+            RT_ASSERT(pbuf != RT_NULL);
+
+            /* write pkthdr */
+            if ((tcpdump_write != RT_NULL) && (tcpdump_write == rt_tcpdump_pcap_file_write))
+            {
+                PACP_PKTHDR_CREATE(&pkthdr, pbuf);
+                tcpdump_write(&pkthdr, sizeof(pkthdr));
+            }
+
+#ifdef  PKG_NETUTILS_TCPDUMP_PRINT
+            hex_dump((rt_uint8_t *)&pkthdr, PCAP_PKTHDR_SIZE);
+#endif
+            rt_tcpdump_ip_mess_write(pbuf);
+            pbuf_free(pbuf);
+            pbuf = RT_NULL;
+        }
+
+        /* tcpdump deinit, the mailbox does not receive the data, exits the thread*/
+        else
+        {
+            dbg_log(DBG_INFO, "tcpdump stop and tcpdump thread exit!\n");
+            close(fd);
+            fd = -1;
+            
+            if (tcpdump_pipe != RT_NULL)
+                rt_device_close((rt_device_t)tcpdump_pipe);
+
+            tcpdump_write = RT_NULL;
+            rt_tcpdump_filename_del();
+            rt_tcpdump_ethname_del();
+            return;
+        }
+    }
+}
+
+/* set file name */
+static void rt_tcpdump_filename_set(const char *name)
+{
+    filename = rt_strdup(name);
+}
+
+/* delete file name */
+static void rt_tcpdump_filename_del(void)
+{
+    name = RT_NULL;
+    if (filename != RT_NULL)
+        rt_free(filename);
+
+    filename = RT_NULL;
+}
+
+/* set network interface name */
+static void rt_tcpdump_ethname_set(const char *eth)
+{
+    ethname = rt_strdup(eth);
+}
+
+/* delete network interface name */
+static void rt_tcpdump_ethname_del(void)
+{
+    eth = RT_NULL;
+    if (ethname != RT_NULL)
+        rt_free(ethname);
+}
+
+static int rt_tcpdump_init(void)
+{
+    struct eth_device *device;
+
+    rt_thread_t tid;
+    rt_base_t level;
+
+    if (netif != RT_NULL)
+    {
+        dbg_log(DBG_ERROR, "This command is running, please stop before you use the [tcpdump -p] command!\n");
+        return -RT_ERROR;
+    }
+
+    /* print and set default state */
+    rt_tcpdump_init_indicate();
+
+    tcpdump_pipe = rt_device_find(TCPDUMP_PIPE_DEVICE);
+    /* file-system mode does not judge pipe */
+    if (tcpdump_write != rt_tcpdump_pcap_file_write)
+    {
+        if (tcpdump_pipe == RT_NULL)
+        {
+            dbg_log(DBG_ERROR, "pipe is error!\n");
+            return -RT_ERROR;
+        }
+    }
+
+    device = (struct eth_device *)rt_device_find(eth);
+    if (device == RT_NULL)
+    {
+        dbg_log(DBG_ERROR, "network interface card [%s] device not find!\n", eth);
+        dbg_log(DBG_ERROR, "tcpdump thread startup failed and enter the correct network interface please!\n");
+        return -RT_ERROR;
+    }
+    if ((device->netif == RT_NULL) || (device->netif->linkoutput == RT_NULL))
+    {
+        dbg_log(DBG_ERROR, "this device not e0!\n");
+        return -RT_ERROR;
+    }
+
+    tcpdump_mb = rt_mb_create("tdrmb", TCPDUMP_MAX_MSG, RT_IPC_FLAG_FIFO);
+    if (tcpdump_mb == RT_NULL)
+    {
+        dbg_log(DBG_ERROR, "tcp dump mp create fail!\n");
+        return -RT_ERROR;
+    }
+
+    tid = rt_thread_create("tcpdump", rt_tcpdump_thread_entry, RT_NULL, 2048, 12, 10);
+    if (tid == RT_NULL)
+    {
+        rt_mb_delete(tcpdump_mb);
+        tcpdump_mb = RT_NULL;
+        dbg_log(DBG_ERROR, "tcpdump thread create fail!\n");
+        return -RT_ERROR;
+    }
+
+    rt_tcpdump_filename_set(name);
+    rt_tcpdump_ethname_set(eth);
+
+    netif = device->netif;
+
+    /* linkoutput and input init */
+    level = rt_hw_interrupt_disable();
+    link_output = netif->linkoutput;
+    netif->linkoutput = _netif_linkoutput;
+
+    input = netif->input;
+    netif->input = _netif_input;
+    rt_hw_interrupt_enable(level);
+    /* linkoutput and input init */
+
+    /* write pcap file header */
+    rt_tcpdump_pcap_file_init();
+
+    rt_thread_startup(tid);
+
+    dbg_log(DBG_INFO, "tcpdump start!\n");
+
+    return RT_EOK;
+}
+
+static void rt_tcpdump_deinit(void)
+{
+    rt_base_t level;
+
+    if (netif == RT_NULL)
+    {
+        dbg_log(DBG_ERROR, "capture packet stopped, no repeat input required!\n");
+        return;
+    }
+
+    /* linkoutput and input deinit */
+    level = rt_hw_interrupt_disable();
+    netif->linkoutput = link_output;
+    netif->input = input;
+    netif = RT_NULL;
+    rt_hw_interrupt_enable(level);
+    /* linkoutput and input deinit */
+
+    rt_mb_delete(tcpdump_mb);
+    tcpdump_mb = RT_NULL;
+}
+
+static void rt_tcpdump_help_info_print(void)
+{
+    rt_kprintf("\n");
+    rt_kprintf("|>------------------------- help -------------------------<|\n");
+    rt_kprintf("| tcpdump [-p] [-h] [-i interface] [-m mode] [-w file]     |\n");
+    rt_kprintf("|                                                          |\n");
+    rt_kprintf("| -h: help                                                 |\n");
+    rt_kprintf("| -i: specify the network interface for listening          |\n");
+    rt_kprintf("| -m: choose what mode(file-system or rdb) to save the file|\n");
+    rt_kprintf("| -w: write the captured packets into an xx.pcap file      |\n");
+    rt_kprintf("| -p: stop capturing packets                               |\n");
+    rt_kprintf("|                                                          |\n");
+    rt_kprintf("| e.g.:                                                    |\n");
+    rt_kprintf("| specify network interface and select save mode \\         |\n");
+    rt_kprintf("| and specify filename                                     |\n");
+    rt_kprintf("| tcpdump -ie0 -mfile -wtext.pcap                          |\n");
+    rt_kprintf("| tcpdump -ie0 -mrdb -wtext.pcap                           |\n");
+    rt_kprintf("|                                                          |\n");
+    rt_kprintf("| -m: file-system mode                                     |\n");
+    rt_kprintf("| tcpdump -mfile                                           |\n");
+    rt_kprintf("|                                                          |\n");
+    rt_kprintf("| -m: rdb mode                                             |\n");
+    rt_kprintf("| tcpdump -mrdb                                            |\n");
+    rt_kprintf("|                                                          |\n");
+    rt_kprintf("| -w: file                                                 |\n");
+    rt_kprintf("| tcpdump -wtext.pcap                                      |\n");
+    rt_kprintf("|                                                          |\n");
+    rt_kprintf("| -p: stop                                                 |\n");
+    rt_kprintf("| tcpdump -p                                               |\n");
+    rt_kprintf("|                                                          |\n");
+    rt_kprintf("| -h: help                                                 |\n");
+    rt_kprintf("| tcpdump -h                                               |\n");
+    rt_kprintf("|                                                          |\n");
+    rt_kprintf("| write commands but no arguments are illegal!!            |\n");
+    rt_kprintf("| e.g.: tcpdump -i / -i -mfile  / -i -mfile -wtext.pcap    |\n");
+    rt_kprintf("|>------------------------- help -------------------------<|\n");
+    rt_kprintf("\n");
+}
+
+static void rt_tcpdump_error_info_deal(void)
+{
+    dbg_log(DBG_ERROR, "tcpdump command is incorrect, please refer to the help information!\n");
+    rt_tcpdump_help_info_print();
+}
+
+/* print and set default state */
+static void rt_tcpdump_init_indicate(void)
+{
+    int name_flag = 0, eth_flag = 0, mode_flag = 0;
+
+    if (eth == RT_NULL)
+    {
+        rt_kprintf("[TCPDUMP]default selection [e0] network interface\n");
+        eth = "e0";
+        eth_flag = 1;
+    }
+
+    if (tcpdump_write == RT_NULL)
+    {
+        rt_kprintf("[TCPDUMP]default selection [file-system] mode\n");
+        tcpdump_write = rt_tcpdump_pcap_file_write;
+        mode_flag = 1;
+    }
+
+    if (name == RT_NULL)
+    {
+        rt_kprintf("[TCPDUMP]default save in [sample.pcap]\n");
+        name = TCPDUMP_DEFAULT_NANE;
+        name_flag = 1;
+    }
+
+    if (eth_flag == 0)
+        rt_kprintf("[TCPDUMP]select  [%s] network interface\n", eth);
+
+    if (mode_flag == 0)
+    {
+        if (STRCMP(mode, ==, "file"))
+            rt_kprintf("[TCPDUMP]select  [file-system] mode\n");
+
+        if (STRCMP(mode, ==, "rdb"))
+            rt_kprintf("[TCPDUMP]select  [rdb] mode\n");
+    }
+
+    if (name_flag == 0)
+        rt_kprintf("[TCPDUMP]save in [%s]\n", name);
+}
+
+/* msh command-line deal */
+static int rt_tcpdump_cmd_deal(struct optparse *options)
+{
+    switch (options->optopt)
+    {
+    case 'p':
+        rt_tcpdump_deinit();
+        return STOP;
+
+    case 'h':
+        rt_tcpdump_help_info_print();
+        return HELP;
+
+    case 'i':
+        /* it's illegal without parameters. */
+        if (options->optarg == RT_NULL)
+            return -RT_ERROR;
+
+        eth = options->optarg;
+        return RT_EOK;
+
+    case 'm':
+        if (options->optarg == RT_NULL)
+            return -RT_ERROR;
+
+        if (STRCMP(options->optarg, ==, "file"))
+        {
+            mode = options->optarg;
+            tcpdump_write = rt_tcpdump_pcap_file_write;
+            return RT_EOK;
+        }
+
+        if (STRCMP(options->optarg, ==, "rdb"))
+        {
+            mode = options->optarg;
+            tcpdump_write = rt_tcpdump_pcap_file_save;
+            return RT_EOK;
+        }
+
+        /* User input Error */
+        return -RT_ERROR;
+
+    case 'w':
+        if (options->optarg == RT_NULL)
+            return -RT_ERROR;
+
+        name = options->optarg;
+        break;
+
+    default:
+        return -RT_ERROR;
+    }
+
+    return RT_EOK;
+}
+
+/* msh command-line parsing */
+static int rt_tcpdump_cmd_parse(char *argv[], const char *cmd)
+{
+    int ch, res, invalid_argv = 0;
+    struct optparse options;
+
+    optparse_init(&options, argv);
+
+    while ((ch = optparse(&options, cmd)) != -1)
+    {
+        ch = ch;
+        invalid_argv = 1;
+
+        switch (options.optopt)
+        {
+        case 'p':
+            return rt_tcpdump_cmd_deal(&options);
+
+        case 'h':
+            return rt_tcpdump_cmd_deal(&options);
+
+        case 'i':
+            res = rt_tcpdump_cmd_deal(&options);
+            break;
+
+        case 'm':
+            res = rt_tcpdump_cmd_deal(&options);
+            break;
+
+        case 'w':
+            res = rt_tcpdump_cmd_deal(&options);
+            break;
+
+        default:
+            rt_tcpdump_error_info_deal();
+            return -RT_ERROR;
+        }
+
+        if (res == -RT_ERROR)
+        {
+            rt_tcpdump_error_info_deal();
+            return res;
+        }
+    }
+
+    /* judge invalid command */
+    if (invalid_argv == 0)
+    {
+        rt_tcpdump_error_info_deal();
+        return -RT_ERROR;
+    }
+
+    return RT_EOK;
+}
+
+static void rt_tcpdump_cmd_argv_deinit(void)
+{
+    eth = RT_NULL;
+    tcpdump_write = RT_NULL;
+    name = RT_NULL;
+}
+
+static int tcpdump_test(int argc, char *argv[])
+{
+    int res = 0;
+
+    if (argc == 1)
+    {
+        rt_tcpdump_cmd_argv_deinit();
+        rt_tcpdump_init();
+        return RT_EOK;
+    }
+
+    rt_tcpdump_cmd_argv_deinit();
+
+    res = rt_tcpdump_cmd_parse(argv, MSH_CMD);
+
+    if (res == STOP)
+        return RT_EOK;
+
+    if (res == HELP)
+        return RT_EOK;
+
+    if (res == -RT_ERROR)
+        return -RT_ERROR;
+
+    rt_tcpdump_init();
+
+    return RT_EOK;
+}
+#ifdef RT_USING_FINSH
+    #include <finsh.h>
+    MSH_CMD_EXPORT_ALIAS(tcpdump_test, tcpdump, test optparse_short cmd.);
+#endif