├── utils ├── log.c └── dpi_list.c ├── include ├── utils.h ├── log.h ├── dpi_list.h └── dpi.h ├── pcapfile ├── ntp.cap ├── ssh.cap ├── ssh1.cap └── eth0.pcap ├── CMakeLists.txt ├── README.md ├── dpi ├── dpi_ssh.c ├── dpi_udp.c ├── dpi_tcp.c ├── dpi_ip.c ├── dpi_ntp.c ├── dpi_http.c ├── dpi_tftp.c ├── dpi_connection.c └── dpi_ether.c ├── main.c └── test ├── test_list.c └── test_pcap_dev.c /utils/log.c: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /include/utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "log.h" 4 | -------------------------------------------------------------------------------- /pcapfile/ntp.cap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aceld/pcap_capture/HEAD/pcapfile/ntp.cap -------------------------------------------------------------------------------- /pcapfile/ssh.cap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aceld/pcap_capture/HEAD/pcapfile/ssh.cap -------------------------------------------------------------------------------- /pcapfile/ssh1.cap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aceld/pcap_capture/HEAD/pcapfile/ssh1.cap -------------------------------------------------------------------------------- /pcapfile/eth0.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aceld/pcap_capture/HEAD/pcapfile/eth0.pcap -------------------------------------------------------------------------------- /include/log.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #define DPI_LOG_DEBUG(...) do{fprintf(stderr, __VA_ARGS__);} while(0) 5 | #define DPI_LOG_INFO(...) do{fprintf(stderr, __VA_ARGS__);} while(0) 6 | #define DPI_LOG_ERROR(...) do{fprintf(stderr, __VA_ARGS__);} while(0) 7 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include_directories(./include) 2 | file(GLOB SRC_LIST "./dpi/*.c") 3 | #add_executable(pcapc ./main.c ./dpi/dpi_ether.c ./dpi/dpi_ip.c ./dpi/dpi_tcp.c ./dpi/dpi_udp.c) 4 | add_executable(pcapc ./main.c ${SRC_LIST} ./utils/dpi_list.c) 5 | add_executable(testlist ./utils/dpi_list.c ./test/test_list.c) 6 | add_executable(pcapdev ./test/test_pcap_dev.c) 7 | target_link_libraries(pcapdev pcap) 8 | target_link_libraries(pcapc pcap) 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pcap_capture 2 | 3 | 深度报文解析功能,主要解析pcap文件及实时网口抓包分析的工具。 4 | 5 | 6 | # 环境构建依赖 7 | 8 | ## 1 依赖cmake工具 9 | 10 | ubuntu 安装 11 | ```bash 12 | $apt-get install cmake 13 | ``` 14 | 15 | 或者其他平台安装cmake即可. 16 | 17 | 18 | # 2 编译 19 | 20 | ```bash 21 | cd pcap_capture/ 22 | 23 | cmake . 24 | 25 | make 26 | ``` 27 | 28 | 29 | # 3 运行 30 | 31 | ## 3.1 基本功能测试 32 | ```bash 33 | $./pcapc ./pcapfile/eth0.pcap 34 | 35 | ``` 36 | -------------------------------------------------------------------------------- /include/dpi_list.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | //节点的定义 5 | typedef struct _dpi_list_node 6 | { 7 | void *data; 8 | struct _dpi_list_node *prev; 9 | struct _dpi_list_node *next; 10 | }dpi_list_node; 11 | 12 | //链表的定义: 13 | typedef struct _dpi_list 14 | { 15 | uint32_t size; 16 | dpi_list_node head; //哨兵节点,链表的起始位置,也是头节点 17 | }dpi_list; 18 | 19 | //创建一个链表 20 | dpi_list *dpi_list_create(); 21 | 22 | //将数据追加到链表中 23 | int dpi_list_append(dpi_list *list, void *data); 24 | 25 | //释放链表 26 | void dpi_list_destory(dpi_list *list); 27 | -------------------------------------------------------------------------------- /dpi/dpi_ssh.c: -------------------------------------------------------------------------------- 1 | #include "dpi.h" 2 | #include 3 | 4 | /* 5 | 处理ssh报文 6 | 7 | @return 8 | 0 处理失败 9 | 1 处理成功 10 | */ 11 | int dpi_pkt_ssh(dpi_result *res, dpi_pkt *pkt) 12 | { 13 | //如果报文前面的4个字节是 "SSH-" 那么就是ssh报文 14 | 15 | //保护措施,数据区域长度>4字节 16 | if (pkt->payload_len <= 4) { 17 | //DPI_LOG_ERROR("ssh payload_len <= 4"); 18 | return 0; 19 | } 20 | 21 | 22 | //识别ssh报文 23 | if (memcmp("SSH-", pkt->payload, 4) == 0) { 24 | //将ssh协议连接保存 25 | add_connection(res, pkt, SSH); 26 | return 1; 27 | } 28 | 29 | /* 判断 当前包ip+port 是否在已经探测的连接里 */ 30 | if (cmp_connection(res, pkt, SSH) == 0) { 31 | return 1; 32 | } 33 | 34 | 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "dpi.h" 3 | 4 | 5 | 6 | void usage(const char *argv0) 7 | { 8 | DPI_LOG_INFO("usage : %s \n", argv0); 9 | } 10 | 11 | 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | char errbuf[PCAP_ERRBUF_SIZE] = {0}; //错误信息buffer 16 | 17 | //如果main没有参数,就提示 18 | if (argc != 2) { 19 | usage(argv[0]); 20 | return -1; 21 | } 22 | 23 | //1 初始化 24 | #if 0 25 | dpi_result *res = dpi_init_dev(argc, argv); 26 | #endif 27 | #if 1 28 | dpi_result *res = dpi_init(argv[1]); 29 | if (!res) { 30 | DPI_LOG_ERROR("Errr in dpi_init\n"); 31 | return -1; 32 | } 33 | #endif 34 | 35 | //2 业务处理 36 | dpi_loop(res); 37 | 38 | 39 | displayResult(res); 40 | 41 | 42 | //3 资料释放 43 | dpi_destory(res); 44 | 45 | 46 | return 0; 47 | } 48 | 49 | 50 | -------------------------------------------------------------------------------- /dpi/dpi_udp.c: -------------------------------------------------------------------------------- 1 | #include "dpi.h" 2 | 3 | char *protocol_udp_string[PROTOCOL_UDP_MAX] = { 4 | PROTOC_UDP_STRING 5 | }; 6 | 7 | //实现 udp应用层报文解析函数表 8 | dpi_protocol_analyze_func_t dpi_udp_analyze_funcs[PROTOCOL_UDP_MAX] = 9 | { 10 | dpi_pkt_tftp, 11 | dpi_pkt_ntp 12 | }; 13 | 14 | //处理udp报文 15 | void dpi_pkt_udp(dpi_result *res, dpi_pkt *pkt) 16 | { 17 | //udp报文数量增加 18 | res->udp_count++; 19 | 20 | uint16_t udp_len = ntohs(pkt->udp_packet->len); 21 | 22 | 23 | //计算应用数据的起始位置及长度 24 | pkt->payload_len = udp_len - sizeof(struct udphdr); 25 | pkt->payload = (unsigned char*)pkt->udp_packet + sizeof(struct udphdr); 26 | 27 | 28 | //将全部的回调函数放在一个全局表中,抽象出来 29 | int i; 30 | for (i = 0; i < PROTOCOL_UDP_MAX; i++) { 31 | if (dpi_udp_analyze_funcs[i](res, pkt)) { 32 | //匹配了对应的协议成功 33 | res->udp_protocol_count[i]++; 34 | break; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /test/test_list.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "dpi_list.h" 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | //1 创建链表 8 | dpi_list *list = dpi_list_create(); 9 | if (!list) { 10 | fprintf(stderr, "Error in dpi_list_crete\n"); 11 | return -1; 12 | } 13 | 14 | //2 添加数据 15 | int *num10 = (int*)malloc(sizeof(int)); 16 | int *num20 = (int*)malloc(sizeof(int)); 17 | int *num30 = (int*)malloc(sizeof(int)); 18 | int *num40 = (int*)malloc(sizeof(int)); 19 | 20 | *num10 = 10; 21 | *num20 = 20; 22 | *num30 = 30; 23 | *num40 = 40; 24 | 25 | dpi_list_append(list, num10); 26 | dpi_list_append(list, num20); 27 | dpi_list_append(list, num30); 28 | dpi_list_append(list, num40); 29 | 30 | //遍历整个链表 31 | dpi_list_node *begin = list->head.next; 32 | while(begin != &list->head) { 33 | int *p = begin->data; 34 | printf("%d\n", *p); 35 | 36 | //遍历下一个 37 | begin = begin->next; 38 | 39 | } 40 | 41 | //3 释放链表 42 | dpi_list_destory(list); 43 | 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /dpi/dpi_tcp.c: -------------------------------------------------------------------------------- 1 | #include "dpi.h" 2 | 3 | char *protocol_tcp_string[PROTOCOL_TCP_MAX] = { 4 | PROTOC_TCP_STRING 5 | }; 6 | 7 | //实现 tcp应用层报文解析函数表 8 | dpi_protocol_analyze_func_t dpi_tcp_analyze_funcs[PROTOCOL_TCP_MAX] = 9 | { 10 | dpi_pkt_ssh, 11 | dpi_pkt_http 12 | }; 13 | 14 | //处理tcp报文 15 | void dpi_pkt_tcp(dpi_result *res, dpi_pkt *pkt) 16 | { 17 | res->tcp_count++; 18 | 19 | //计算tcp区域的长度 20 | int tcphl = pkt->tcp_packet->doff * 4; 21 | 22 | //计算数据区域长度 23 | pkt->payload_len = pkt->tcp_len - tcphl; //数据区域长度=tcp报文长度-tcp头部长度 24 | pkt->payload = (uint8_t*)pkt->tcp_packet + tcphl; 25 | 26 | /* 27 | //逻辑判断法 28 | if (dpi_pkt_ssh(res, pkt)) { 29 | //处理ssh报文成功 30 | } else if (dpi_pkt_tftp(res, pkt)) { 31 | //处理tftp报文成功 32 | } 33 | */ 34 | 35 | 36 | //表驱动法 37 | //将全部的回调函数放在一个全局表中,抽象出来 38 | int i; 39 | for (i = 0; i < PROTOCOL_TCP_MAX; i++) { 40 | if (dpi_tcp_analyze_funcs[i](res, pkt)) { 41 | //匹配了对应的协议成功 42 | res->tcp_protocol_count[i]++; 43 | break; 44 | } 45 | } 46 | 47 | } 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /utils/dpi_list.c: -------------------------------------------------------------------------------- 1 | #include "dpi_list.h" 2 | #include 3 | #include 4 | 5 | 6 | 7 | //创建一个链表 8 | dpi_list *dpi_list_create() 9 | { 10 | dpi_list *list = malloc(sizeof(dpi_list)) ; 11 | if (list != NULL) { 12 | memset(list, 0, sizeof(*list)); 13 | 14 | //head 哨兵节点都指向自己 15 | list->head.next = &list->head; 16 | list->head.prev = &list->head; 17 | } 18 | 19 | return list; 20 | } 21 | 22 | //将数据追加到链表中 23 | int dpi_list_append(dpi_list *list, void *data) 24 | { 25 | //当前新增加的节点 26 | dpi_list_node *node = malloc(sizeof(dpi_list_node)); 27 | 28 | if (!node) { 29 | return -1; 30 | } 31 | 32 | //链表长度++ 33 | list->size++; 34 | node->data = data; 35 | 36 | //链表最后一个节点 37 | dpi_list_node *last_node = list->head.prev; 38 | 39 | //链表的最后一个节点的next指向当前新增的节点 40 | last_node->next = node; 41 | 42 | //当前新增的节点的prev也要指向链表的最后一个节点 43 | node->prev = last_node; 44 | 45 | //哨兵节点的prev要执行当前新增的节点(因为当前节点是最后一个节点) 46 | list->head.prev = node; 47 | 48 | //新增的节点的netx要指向head 哨兵节点 49 | node->next = &list->head; 50 | 51 | return 0; 52 | } 53 | 54 | //释放链表 55 | void dpi_list_destory(dpi_list *list) 56 | { 57 | //遍历整个链表 58 | dpi_list_node *begin = list->head.next; 59 | 60 | while(begin != &list->head) { 61 | //释放每个节点的数据区域 62 | if (begin->data != NULL) { 63 | free(begin->data); 64 | } 65 | 66 | dpi_list_node *tmp = begin; 67 | begin = begin->next; 68 | 69 | //释放每个节点的内存 70 | free(tmp); 71 | } 72 | 73 | //释放链表的结构体 74 | free(list); 75 | } 76 | 77 | -------------------------------------------------------------------------------- /dpi/dpi_ip.c: -------------------------------------------------------------------------------- 1 | #include "dpi.h" 2 | 3 | //处理ip报文 4 | void dpi_pkt_ip(dpi_result *res, dpi_pkt *pkt) 5 | { 6 | //ip报文计数 ++ 7 | res->ip_count++; 8 | 9 | //ip 版本号为4 10 | 11 | if (pkt->ip_packet->version != 4) { 12 | DPI_LOG_ERROR("IP version not eq 4\n"); 13 | return ; 14 | } 15 | 16 | //ip首部长度 17 | int ihl = pkt->ip_packet->ihl << 2; //单位是4字节,所以要乘以4 得到长度字节数,<<2 表示乘以4 18 | //ip报文总长度 19 | int ip_totlen = ntohs(pkt->ip_packet->tot_len); 20 | 21 | 22 | //分片只处理第一个分片 frag_off 网络字节序的后13位 == 0 23 | if ((pkt->ip_packet->frag_off & htons(0x01fff)) != 0) { 24 | DPI_LOG_ERROR("IP frag off not eq 0\n"); 25 | return ; 26 | } 27 | 28 | //根据ip报文是什么协议来进行分支 29 | switch(pkt->ip_packet->protocol) { 30 | case IPPROTO_TCP: //6 31 | //tcp 32 | //计算tcp报文数据的长度和起始位置 33 | pkt->tcp_len = ip_totlen - ihl; 34 | pkt->tcp_packet = (struct tcphdr*)((char*)pkt->ip_packet + ihl); 35 | //如果数据区域没有数据,跳过 36 | if (pkt->tcp_len <= 0) { 37 | return; 38 | } 39 | 40 | //处理tcp报文 41 | dpi_pkt_tcp(res, pkt); 42 | 43 | break; 44 | case IPPROTO_UDP: //17 45 | //udp 46 | //计算udp报文数据的长度和起始位置 47 | pkt->udp_len = ip_totlen - ihl; 48 | pkt->udp_packet = (struct udphdr*)((char*)pkt->ip_packet + ihl); 49 | //如果数据区域没有数据,跳过 50 | if (pkt->udp_len <= 0) { 51 | return; 52 | } 53 | 54 | //处理udp报文 55 | dpi_pkt_udp(res, pkt); 56 | 57 | break; 58 | case 1: 59 | //icmp 60 | break; 61 | default: 62 | break; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /dpi/dpi_ntp.c: -------------------------------------------------------------------------------- 1 | #include "dpi.h" 2 | 3 | /* 4 | 5 | 0 1 2 3 6 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 7 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 8 | |LI | Status | Type | Precision | 9 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 10 | | Estimated Error | 11 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 12 | | Estimated Drift Rate | 13 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 14 | | Reference Clock Identifier | 15 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 16 | | | 17 | | Reference Timestamp (64 bits) | 18 | | | 19 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 20 | | | 21 | | Originate Timestamp (64 bits) | 22 | | | 23 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 24 | | | 25 | | Receive Timestamp (64 bits) | 26 | | | 27 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 28 | | | 29 | | Transmit Timestamp (64 bits) | 30 | | | 31 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 32 | 33 | */ 34 | 35 | typedef struct _dpi_ntp_header 36 | { 37 | #if __BYTE_ORDER == __LITTLE_ENDIAN 38 | uint16_t mode:3; 39 | uint16_t vn:3; 40 | uint16_t li:2; 41 | #elif __BYTE_ORDER == __BIG_ENDIAN 42 | uint16_t li:2; 43 | uint16_t vn:3; 44 | uint16_t mode:3; 45 | #endif 46 | uint8_t stratum; 47 | uint8_t poll; 48 | uint8_t precision; 49 | }dpi_ntp_header; 50 | 51 | int dpi_pkt_ntp(dpi_result *res, dpi_pkt *pkt) 52 | { 53 | //条件1: 报文长度 48字节 或者有校验和 60字节 54 | if (pkt->payload_len != 48 && pkt->payload_len != 60) { 55 | return 0; 56 | } 57 | 58 | //条件2: vn:4 59 | dpi_ntp_header *ntp = (dpi_ntp_header*)pkt->payload; 60 | 61 | if (ntp->vn != 4) { 62 | return 0; 63 | } 64 | 65 | //条件3: Stratum: 0-16 66 | if (ntp->stratum > 16) { 67 | return 0; 68 | } 69 | 70 | //没有更多条件 如果以上都符合,认为是ntp报文 71 | 72 | return 1; 73 | } 74 | -------------------------------------------------------------------------------- /dpi/dpi_http.c: -------------------------------------------------------------------------------- 1 | #include "dpi.h" 2 | #include 3 | 4 | 5 | #define HTTP_VERSION_1_1 "HTTP/1.1" 6 | #define HTTP_VERSION_1_0 "HTTP/1.0" 7 | #define CRLF "\r\n" 8 | 9 | enum _http_request_method { 10 | GET = 0, 11 | HEAD, 12 | POST, 13 | OPTIONS, 14 | PUT, 15 | DELETE, 16 | TRACE, 17 | CONNECT, 18 | HTTP_METHOD_MAX 19 | }http_request_method; 20 | 21 | 22 | char *http_request_method_strings[HTTP_METHOD_MAX] = { 23 | "GET", 24 | "HEAD", 25 | "POST", 26 | "OPTIONS", 27 | "PUT", 28 | "DELETE", 29 | "TRACE", 30 | "CONNECT" 31 | }; 32 | 33 | #define HTTP_RESPONSE_STATUS_NUM (7) 34 | 35 | char *http_response_status_strings[HTTP_RESPONSE_STATUS_NUM] = { 36 | "200 OK", 37 | "400 Bad Request", 38 | "401 Unauthorized", 39 | "403 Forbidden", 40 | "404 Not Found", 41 | "500 Internal Server Error", 42 | "503 Server Unavailable" 43 | }; 44 | 45 | 46 | 47 | /* 48 | 处理http报文 49 | 50 | @return 51 | 0 处理失败 52 | 1 处理成功 53 | */ 54 | int dpi_pkt_http(dpi_result *res, dpi_pkt *pkt) 55 | { 56 | //HTTP报文请求头 57 | //GET url HTTP/1.1\r\n 58 | if (pkt->payload_len < (strlen(http_request_method_strings[OPTIONS])+strlen(HTTP_VERSION_1_0) + strlen(" ") + strlen(CRLF))) { 59 | //请求头太小 60 | return 0; 61 | } 62 | 63 | 64 | /* 65 | POST /index.html HTTP/1.1\r\n 66 | HOST: www.baidu.com\r\n 67 | User-Agent: Mozilla/5.0(Windows NT 6.1;rv:15.0) Firefox/15.0\r\n 68 | Username=admin&password=admin 69 | */ 70 | // 匹配请求方法 71 | #if 1 72 | int i; 73 | for (i = 0; i < HTTP_METHOD_MAX; i++) { 74 | if (memcmp(http_request_method_strings[i], pkt->payload, strlen(http_request_method_strings[i])) == 0) { 75 | //匹配到请求方法 76 | //找到版本号的首地址进行匹配 77 | char* p; 78 | for(p = pkt->payload+(strlen(http_request_method_strings[i])+1); *p != ' '; p++); 79 | p++; 80 | if ( (memcmp(p, HTTP_VERSION_1_0, strlen(HTTP_VERSION_1_0)) == 0) || 81 | (memcmp(p, HTTP_VERSION_1_1, strlen(HTTP_VERSION_1_1)) == 0) ) { 82 | //找到版本号 83 | add_connection(res, pkt, HTTP); 84 | return 1; 85 | } 86 | } 87 | } 88 | #endif 89 | 90 | //匹配应答方法 91 | /* 92 | HTTP/1.1 200 OK 93 | Content-Encoding: gzip 94 | Content-Type: text/html;charset=utf-8 95 | 96 | 97 | 98 | 99 | 100 | Document 101 | 102 | 103 |

this is http response

104 | 105 | 106 | */ 107 | #if 1 108 | //匹配到版本号 109 | if ( (memcmp(HTTP_VERSION_1_1, pkt->payload, strlen(HTTP_VERSION_1_1)) == 0) || 110 | (memcmp(HTTP_VERSION_1_0, pkt->payload, strlen(HTTP_VERSION_1_0)) == 0)) { 111 | 112 | //匹配应答码 及 状态描述 113 | char* p = pkt->payload+(strlen(HTTP_VERSION_1_0)+1); 114 | 115 | int i; 116 | for (i = 0; i < HTTP_RESPONSE_STATUS_NUM; i ++) { 117 | if (memcmp(http_response_status_strings[i], p, strlen(http_response_status_strings[i])) == 0) { 118 | add_connection(res, pkt, HTTP); 119 | return 1; 120 | } 121 | } 122 | } 123 | #endif 124 | 125 | #if 1 126 | //从链接集合中匹配 127 | if (cmp_connection(res, pkt, HTTP) == 0) { 128 | return 1; 129 | } 130 | #endif 131 | 132 | 133 | return 0; 134 | } 135 | -------------------------------------------------------------------------------- /test/test_pcap_dev.c: -------------------------------------------------------------------------------- 1 | #include "pcap.h" 2 | #include "stdlib.h" 3 | #include 4 | #include 5 | #define SNAP_LEN 65536 6 | 7 | //prototype of the packet handler 8 | void dispatcher_handler(u_char *temp1, 9 | const struct pcap_pkthdr *header, const u_char *pkt_data); 10 | 11 | int main(int argc, char **argv) 12 | { 13 | char *dev = NULL; /* capture device name */ 14 | char errbuf[PCAP_ERRBUF_SIZE]; /* error buffer */ 15 | pcap_t *handle; /* packet capture handle */ 16 | pcap_if_t *alldev, *p; 17 | char filter_exp[] = "tcp"; /* filter expression [3] */ 18 | struct bpf_program fp; /* compiled filter program (expression) */ 19 | bpf_u_int32 mask; /* subnet mask */ 20 | bpf_u_int32 net; /* ip */ 21 | int num_packets = 10000; /* number of packets to capture */ 22 | /* check for capture device name on command-line */ 23 | if (argc == 2) { 24 | dev = argv[1]; 25 | } 26 | else if (argc > 2) { 27 | fprintf(stderr, "error: unrecognized command-line options\n\n"); 28 | exit(EXIT_FAILURE); 29 | } 30 | else { 31 | /* find a capture device if not specified on command-line */ 32 | int i=0,num; 33 | if(pcap_findalldevs(&alldev,errbuf)==-1) 34 | { 35 | printf("find all devices is error\n"); 36 | return 0; 37 | } 38 | for(p=alldev;p;p=p->next) 39 | { 40 | printf("%d:%s\n",++i,p->name); 41 | if(p->description) 42 | { 43 | printf("%s\n",p->description); 44 | } 45 | } 46 | printf("please input which interface you want to use\n"); 47 | scanf("%d",&num); 48 | if(num<1||num>i) 49 | { 50 | printf("interface is unavillible\n"); 51 | return 0; 52 | } 53 | for(p=alldev,i=1;i<=num;p=p->next,i++) 54 | dev=p->name; 55 | if (dev == NULL) { 56 | fprintf(stderr, "Couldn't find default device: %s\n", 57 | errbuf); 58 | exit(EXIT_FAILURE); 59 | } 60 | } 61 | /* print capture info */ 62 | printf("Device: %s\n", dev); 63 | printf("Number of packets: %d\n", num_packets); 64 | printf("Filter expression: %s\n", filter_exp); 65 | /* open capture device */ 66 | handle = pcap_open_live(dev, SNAP_LEN, 1, 1000, errbuf); 67 | if (handle == NULL) { 68 | fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf); 69 | exit(EXIT_FAILURE); 70 | } 71 | /* make sure we're capturing on an Ethernet device [2] */ 72 | if (pcap_datalink(handle) != DLT_EN10MB) { 73 | fprintf(stderr, "%s is not an Ethernet\n", dev); 74 | exit(EXIT_FAILURE); 75 | } 76 | /* compile the filter expression */ 77 | if (pcap_compile(handle, &fp, filter_exp, 0, 24) == -1) { 78 | fprintf(stderr, "Couldn't parse filter %s: %s\n", 79 | filter_exp, pcap_geterr(handle)); 80 | exit(EXIT_FAILURE); 81 | } 82 | /* apply the compiled filter */ 83 | if (pcap_setfilter(handle, &fp) == -1) { 84 | fprintf(stderr, "Couldn't install filter %s: %s\n", 85 | filter_exp, pcap_geterr(handle)); 86 | exit(EXIT_FAILURE); 87 | } 88 | /* now we can set our callback function */ 89 | pcap_loop(handle, num_packets, dispatcher_handler, NULL); 90 | /* cleanup */ 91 | pcap_freecode(&fp); 92 | pcap_close(handle); 93 | printf("\nCapture complete.\n"); 94 | return 0; 95 | } 96 | 97 | void dispatcher_handler(u_char *temp1, 98 | const struct pcap_pkthdr *header, const u_char *pkt_data) 99 | { 100 | printf("I get one packet!\n"); 101 | } 102 | -------------------------------------------------------------------------------- /dpi/dpi_tftp.c: -------------------------------------------------------------------------------- 1 | #include "dpi.h" 2 | #include 3 | 4 | #define DPI_TFTP_NETASCII "netascii" 5 | #define DPI_TFTP_OCTET "octet" 6 | #define DPI_TFTP_MAIL "mail" 7 | 8 | typedef struct _dpi_tftp_header 9 | { 10 | uint16_t opcode; 11 | }dpi_tftp_header; 12 | 13 | typedef struct _dpi_tftp_error_header 14 | { 15 | uint16_t opcode; 16 | uint16_t errorcode; 17 | }dpi_tftp_error_header; 18 | 19 | 20 | 21 | /* 22 | 处理TFTP报文 23 | 24 | @return 25 | 0 处理失败 26 | 1 处理成功 27 | */ 28 | int dpi_pkt_tftp(dpi_result *res, dpi_pkt *pkt) 29 | { 30 | 31 | dpi_tftp_header *tftp = (dpi_tftp_header*)pkt->payload; 32 | 33 | 34 | /* 35 | WRQ|RRQ报文 36 | 37 | 2 bytes string 1 byte string 1 byte 38 | ------------------------------------------------ 39 | | Opcode | Filename | 0 | Mode | 0 | 40 | ------------------------------------------------ 41 | 42 | Mode: "netascii","octet", "mail" 43 | opcode:1 | 2 44 | 45 | */ 46 | if (pkt->payload_len >= 9) { 47 | //整个报文至少9个字节 48 | //opcode : 1 | 2 49 | if (tftp->opcode == htons(1) || tftp->opcode == htons(2)) { 50 | //最后几个字节肯定是 "netascii","octet", "mail" 中间都夹着一个\0 51 | 52 | if (pkt->payload_len >= strlen(DPI_TFTP_NETASCII) + 4) { 53 | //4 表示 opcode:2 \0:1 \0:1 54 | char *begin = (char *)pkt->payload + pkt->payload_len - 1 - strlen(DPI_TFTP_NETASCII); 55 | if (memcmp(begin, DPI_TFTP_NETASCII, strlen(DPI_TFTP_NETASCII)) == 0) { 56 | //判断成功 57 | return 1; 58 | } 59 | } 60 | 61 | 62 | if (pkt->payload_len >= strlen(DPI_TFTP_OCTET) + 4) { 63 | //4 表示 opcode:2 \0:1 \0:1 64 | char *begin = (char *)pkt->payload + pkt->payload_len - 1 - strlen(DPI_TFTP_OCTET); 65 | if (memcmp(begin, DPI_TFTP_OCTET, strlen(DPI_TFTP_OCTET)) == 0) { 66 | //判断成功 67 | return 1; 68 | } 69 | } 70 | 71 | 72 | if (pkt->payload_len >= strlen(DPI_TFTP_MAIL) + 4) { 73 | //4 表示 opcode:2 \0:1 \0:1 74 | char *begin = (char *)pkt->payload + pkt->payload_len - 1 - strlen(DPI_TFTP_MAIL); 75 | if (memcmp(begin, DPI_TFTP_MAIL, strlen(DPI_TFTP_MAIL)) == 0) { 76 | //判断成功 77 | return 1; 78 | } 79 | } 80 | } 81 | 82 | } 83 | 84 | 85 | /* 86 | DATA报文 87 | 88 | 2 bytes 2 bytes n bytes 89 | ---------------------------------- 90 | | Opcode | Block # | Data | 91 | ---------------------------------- 92 | 93 | opcode : 3 94 | len : 4 - 516字节 95 | */ 96 | if (pkt->payload_len >= 4 && pkt->payload_len <= 516 && tftp->opcode == htons(3)) { 97 | return 1; 98 | } 99 | 100 | 101 | /* 102 | ACK 报文 103 | 104 | 2 bytes 2 bytes 105 | --------------------- 106 | | Opcode | Block # | 107 | --------------------- 108 | 109 | opcode : 4 110 | len : 4 111 | */ 112 | if (pkt->payload_len == 4 && tftp->opcode == htons(4)) { 113 | return 1; 114 | } 115 | 116 | /* 117 | ERROR 报文 118 | 119 | 2 bytes 2 bytes string 1 byte 120 | ----------------------------------------- 121 | | Opcode | ErrorCode | ErrMsg | 0 | 122 | ----------------------------------------- 123 | 124 | opcode : 5 125 | errorcode : 0-7 126 | len : >=5 字节 127 | */ 128 | dpi_tftp_error_header *tftp_error = (dpi_tftp_error_header*)tftp; 129 | 130 | if (pkt->payload_len >= 5 && tftp_error->opcode == htons(5)) { 131 | if (tftp_error->errorcode >= htons(0) && tftp_error->errorcode <= htons(7)) { 132 | //最后一个字节是\0 133 | if (*(pkt->payload + pkt->payload_len-1) == '\0') { 134 | return 1; 135 | } 136 | } 137 | } 138 | 139 | 140 | return 0; 141 | } 142 | -------------------------------------------------------------------------------- /include/dpi.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "utils.h" 10 | 11 | 12 | 13 | //tcp应用层协议索引号 14 | typedef enum _dpi_tcp_protocol 15 | { 16 | SSH = 0, 17 | HTTP, 18 | PROTOCOL_TCP_MAX 19 | }dpi_tcp_protocol; 20 | 21 | 22 | #define PROTOC_TCP_STRING \ 23 | "SSH", \ 24 | "HTTP" 25 | 26 | extern char *protocol_tcp_string[PROTOCOL_TCP_MAX]; 27 | 28 | //udp应用层协议索引号 29 | typedef enum _dpi_udp_protocol 30 | { 31 | TFTP = 0, 32 | NTP, 33 | PROTOCOL_UDP_MAX 34 | }dpi_udp_protocol; 35 | 36 | 37 | #define PROTOC_UDP_STRING \ 38 | "TFTP", \ 39 | "NTP" 40 | 41 | extern char *protocol_udp_string[PROTOCOL_UDP_MAX]; 42 | 43 | 44 | //句柄定义 45 | typedef struct dpi_result 46 | { 47 | char *dev; //当前抓取的网卡设备 48 | void *pcap_handle; 49 | 50 | unsigned int ether_count; //以太坊报文数量 51 | 52 | unsigned int ip_count; //ip报文数量 53 | 54 | unsigned int tcp_count; //tcp 报文数量 55 | unsigned int udp_count; //udp 报文数量 56 | 57 | unsigned int tcp_protocol_count[PROTOCOL_TCP_MAX]; 58 | unsigned int udp_protocol_count[PROTOCOL_UDP_MAX]; 59 | 60 | }dpi_result; 61 | 62 | 63 | /* 64 | 一个报文的解析信息 65 | */ 66 | typedef struct dpi_pkt 67 | { 68 | uint32_t ether_len; //以太网报文长度 69 | struct ether_header *ether_packet; //以太坊报文地址 70 | uint32_t ip_len; //IP报文长度 71 | struct iphdr *ip_packet; //IP报文地址 72 | 73 | uint32_t tcp_len; //tcp报文长度 74 | struct tcphdr *tcp_packet; //tcp报文地址 75 | 76 | uint32_t udp_len; //udp报文长度 77 | struct udphdr *udp_packet; //udp报文地址 78 | 79 | uint8_t *payload; //报文装载的数据区域 80 | uint32_t payload_len; //报文装载的数据区域长度 81 | 82 | }dpi_pkt; 83 | 84 | 85 | /* 保存已探测的写 ip+port对 链接信息 */ 86 | struct ipv4_port_pair { 87 | uint32_t src_ip; 88 | uint16_t src_port; 89 | uint32_t dst_ip; 90 | uint16_t dst_port; 91 | }; 92 | 93 | 94 | //dpi的链接信息定义 95 | typedef struct dpi_connection { 96 | struct ipv4_port_pair ipv4; 97 | 98 | /* 根据需要添加 ...如果是ipv6 */ 99 | 100 | }dpi_connection; 101 | 102 | 103 | //对已经探测到的协议报文,保存IP+port 的链接信息 104 | int add_connection(struct dpi_result *res, struct dpi_pkt *pkt, dpi_tcp_protocol protocol); 105 | 106 | /* 107 | ip + port 的比较,比较保存的当前的报文的ip_pair是否相同 108 | 109 | return: 110 | 0: 相同 111 | 1: 不同 112 | */ 113 | int cmp_connection(struct dpi_result *res, struct dpi_pkt *pkt, dpi_tcp_protocol protocol); 114 | 115 | 116 | 117 | void init_connection_list(); 118 | void destory_connection_list(); 119 | void show_connections(); 120 | 121 | 122 | //1 初始化 123 | //pcapfile: 要处理的pcap文件 124 | //返回值: 设计一个句柄,这个句柄包含了结果 125 | //成功返回非空的指针,失败,返回NULL 126 | dpi_result *dpi_init(const char *pcapfile); 127 | //1 实时抓包初始化 128 | dpi_result *dpi_init_dev(int argc, char **argv); 129 | 130 | //2 业务处理 131 | //启动执行报文的函数 132 | void dpi_loop(dpi_result *res); 133 | 134 | //3 资源释放 135 | void dpi_destory(dpi_result *res); 136 | 137 | //4 打印当前抓包结果 138 | void displayResult(dpi_result *res); 139 | 140 | 141 | //处理以太网报文 142 | void dpi_pcap_callback(u_char *user, const struct pcap_pkthdr *h, const u_char *data); 143 | 144 | //处理ip报文 145 | void dpi_pkt_ip(dpi_result *res, dpi_pkt *pkt); 146 | 147 | //处理tcp报文 148 | void dpi_pkt_tcp(dpi_result *res, dpi_pkt *pkt); 149 | 150 | //处理udp报文 151 | void dpi_pkt_udp(dpi_result *res, dpi_pkt *pkt); 152 | 153 | //处理icmp报文 154 | //void dpi_pkt_icmp(dpi_result *res, dpi_pkt *pkt); 155 | 156 | //处理ssh报文 157 | int dpi_pkt_ssh(dpi_result *res, dpi_pkt *pkt); 158 | 159 | //处理tftp报文 160 | int dpi_pkt_tftp(dpi_result *res, dpi_pkt *pkt); 161 | 162 | //处理ntp报文 163 | int dpi_pkt_ntp(dpi_result *res, dpi_pkt *pkt); 164 | 165 | //处理http报文 166 | int dpi_pkt_http(dpi_result *res, dpi_pkt *pkt); 167 | 168 | 169 | 170 | /* 处理tcp应用层报文的解析函数表 */ 171 | //定义一个函数指针,专门用来识别协议报文 172 | typedef int (*dpi_protocol_analyze_func_t)(dpi_result *res, dpi_pkt *pkt); 173 | 174 | 175 | //tcp应用层报文解析函数表 176 | dpi_protocol_analyze_func_t dpi_tcp_analyze_funcs[PROTOCOL_TCP_MAX]; 177 | 178 | 179 | //udp应用层报文解析函数表 180 | dpi_protocol_analyze_func_t dpi_udp_analyze_funcs[PROTOCOL_UDP_MAX]; 181 | 182 | -------------------------------------------------------------------------------- /dpi/dpi_connection.c: -------------------------------------------------------------------------------- 1 | #include "dpi.h" 2 | #include "dpi_list.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | 11 | 12 | //定义全局的链接协议链接集合 13 | //static struct dpi_connection g_connections[PROTOCOL_TCP_MAX]; 14 | static dpi_list *g_connections[PROTOCOL_TCP_MAX]; 15 | 16 | 17 | /* -------------------------------------------*/ 18 | /** 19 | * @brief 初始化链接链表 20 | */ 21 | /* -------------------------------------------*/ 22 | void init_connection_list() { 23 | int i; 24 | 25 | for (i = 0; i < PROTOCOL_TCP_MAX; i ++) { 26 | g_connections[i] = dpi_list_create(); 27 | } 28 | } 29 | 30 | 31 | /* -------------------------------------------*/ 32 | /** 33 | * @brief 销毁链接链表 34 | */ 35 | /* -------------------------------------------*/ 36 | void destory_connection_list() { 37 | int i; 38 | 39 | for (i = 0; i < PROTOCOL_TCP_MAX; i ++) { 40 | dpi_list_destory(g_connections[i]); 41 | } 42 | } 43 | 44 | 45 | 46 | 47 | //对已经探测到的协议报文,保存IP+port 的链接信息 48 | int add_connection(struct dpi_result *res, struct dpi_pkt *pkt, dpi_tcp_protocol protocol) 49 | { 50 | int ret = 0; 51 | 52 | dpi_connection *con = malloc(sizeof(dpi_connection)); 53 | if (con == NULL) { 54 | return -1; 55 | } 56 | memset(con, 0, sizeof(dpi_connection)); 57 | 58 | 59 | /* 保存源ip+port的链接信息 */ 60 | con->ipv4.src_ip = pkt->ip_packet->saddr; 61 | con->ipv4.dst_ip = pkt->ip_packet->daddr; 62 | 63 | 64 | //保存端口信息 65 | if (pkt->tcp_packet != NULL) { 66 | /* TCP */ 67 | con->ipv4.src_port = pkt->tcp_packet->source; 68 | con->ipv4.dst_port = pkt->tcp_packet->dest; 69 | 70 | } 71 | 72 | //将链接添加对应协议的链表中 73 | dpi_list_append(g_connections[protocol], con); 74 | 75 | return ret; 76 | } 77 | 78 | /* 79 | ip + port 的比较,比较保存的当前的报文的ip_pair是否相同 80 | 81 | return: 82 | 0: 相同 83 | 1: 不同 84 | */ 85 | int cmp_connection(struct dpi_result *res, struct dpi_pkt *pkt, dpi_tcp_protocol protocol) 86 | { 87 | int ret = 1; 88 | 89 | uint32_t sip; 90 | uint32_t dip; 91 | uint16_t sport; 92 | uint16_t dport; 93 | 94 | dpi_list_node *node = g_connections[protocol]->head.next; 95 | 96 | for (; node != &g_connections[protocol]->head; node = node->next) { 97 | dpi_connection *con = node->data; 98 | 99 | sip = con->ipv4.src_ip; 100 | dip = con->ipv4.dst_ip; 101 | sport = con->ipv4.src_port; 102 | dport = con->ipv4.dst_port; 103 | 104 | 105 | /* 106 | 计算机A <-----> 计算机B 107 | 源A == 源A 表示 A---->B的包 108 | //源A == 目的A, 表示 B---->A的包 109 | */ 110 | 111 | if (sip == pkt->ip_packet->saddr) { 112 | /* A ---> B */ 113 | if (dip == pkt->ip_packet->daddr) { 114 | if (pkt->tcp_packet != NULL) { 115 | // tcp协议 116 | if ((sport == pkt->tcp_packet->source) && (dport == pkt->tcp_packet->dest)) { 117 | ret = 0; 118 | goto END; 119 | } 120 | } 121 | } 122 | } 123 | #if 1 124 | else if (sip == pkt->ip_packet->daddr) { 125 | /* B ---> A 的包 */ 126 | if (dip == pkt->ip_packet->saddr) { 127 | if (pkt->tcp_packet != NULL) { 128 | /* tcp 协议 */ 129 | if ((sport == pkt->tcp_packet->dest) && (dport == pkt->tcp_packet->source)) { 130 | ret = 0; 131 | goto END; 132 | } 133 | } 134 | } 135 | } else { 136 | /* nothing to do */ 137 | } 138 | #endif 139 | } 140 | 141 | 142 | END: 143 | return ret; 144 | } 145 | 146 | 147 | void show_connections() 148 | { 149 | int i; 150 | for (i = 0; i < PROTOCOL_TCP_MAX; i++) { 151 | printf("========= TCP Connection =========\n"); 152 | printf("tcp protocol : %s\n", protocol_tcp_string[i]); 153 | 154 | dpi_list_node *node = g_connections[i]->head.next; 155 | while( node != &g_connections[i]->head) { 156 | dpi_connection *con = node->data; 157 | struct in_addr in; 158 | in.s_addr = con->ipv4.src_ip; 159 | printf("src:%s:%d\t", inet_ntoa(in), ntohs(con->ipv4.src_port)); 160 | in.s_addr = con->ipv4.dst_ip; 161 | printf("dst:%s:%d\n", inet_ntoa(in), ntohs(con->ipv4.dst_port)); 162 | node = node->next; 163 | } 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /dpi/dpi_ether.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "dpi.h" 6 | 7 | #define SNAP_LEN 65536 8 | 9 | 10 | void displayResult(dpi_result *res) 11 | { 12 | //链路层 13 | printf("以太坊报文数量: %u\n", res->ether_count); 14 | 15 | //ip层 16 | printf("ip报文数量: %u\n", res->ip_count); 17 | 18 | 19 | //传输层 20 | printf("tcp报文数量: %u\n", res->tcp_count); 21 | printf("udp报文数量: %u\n", res->udp_count); 22 | 23 | //tcp应用协议 24 | printf("ssh报文数量: %u\n", res->tcp_protocol_count[SSH]); 25 | printf("http报文数量: %u\n", res->tcp_protocol_count[HTTP]); 26 | 27 | //udp应用协议 28 | printf("tftp报文数量: %u\n", res->udp_protocol_count[TFTP]); 29 | printf("ntp报文数量: %u\n", res->udp_protocol_count[NTP]); 30 | 31 | 32 | //链接信息 33 | show_connections(); 34 | } 35 | 36 | 37 | dpi_result *dpi_init_dev(int argc, char **argv) 38 | { 39 | char errbuf[PCAP_ERRBUF_SIZE] = {0};//错误信息buffer 40 | char *dev = NULL; //当前抓取的网卡设备 41 | pcap_t *handle; //pcap句柄 42 | 43 | if (argc == 2) { 44 | dev = argv[1]; 45 | } 46 | 47 | handle = pcap_open_live(dev, SNAP_LEN, 1, 1000000, errbuf); 48 | if (handle == NULL) { 49 | DPI_LOG_ERROR("Error in pcap_open_live :%s\n", errbuf); 50 | return NULL; 51 | } 52 | 53 | 54 | /* 确保 正在从一个网络设备上抓包 */ 55 | if (pcap_datalink(handle) != DLT_EN10MB) { 56 | DPI_LOG_ERROR("%s is not an ethernet\n", dev); 57 | return NULL; 58 | } 59 | 60 | 61 | //创建一个句柄 62 | dpi_result *res = malloc(sizeof(dpi_result)); 63 | //重置为0 64 | memset(res, 0, sizeof(*res)); 65 | //将pcap打开文件产生的句柄也存到res句柄中,方便之后调用 66 | res->pcap_handle = handle; 67 | res->dev = dev; 68 | 69 | /* 初始化 链接链表 */ 70 | init_connection_list(); 71 | 72 | 73 | return res; 74 | } 75 | 76 | 77 | 78 | //1 初始化 79 | //pcapfile: 要处理的pcap文件 80 | //返回值: 设计一个句柄,这个句柄包含了结果 81 | //成功返回非空的指针,失败,返回NULL 82 | dpi_result *dpi_init(const char *pcapfile) 83 | { 84 | //1 pcap 打开文件 85 | char errbuf[PCAP_ERRBUF_SIZE] = {0};//错误信息buffer 86 | 87 | pcap_t *handle = pcap_open_offline(pcapfile, errbuf); 88 | if (!handle) { 89 | //出错处理 90 | DPI_LOG_ERROR("Error in pcap_open_offline :%s\n", errbuf); 91 | return NULL; 92 | } 93 | 94 | //创建一个句柄 95 | dpi_result *res = malloc(sizeof(dpi_result)); 96 | //重置为0 97 | memset(res, 0, sizeof(*res)); 98 | //将pcap打开文件产生的句柄也存到res句柄中,方便之后调用 99 | res->pcap_handle = handle; 100 | 101 | /* 初始化 链接链表 */ 102 | init_connection_list(); 103 | 104 | 105 | return res; 106 | } 107 | 108 | //2 业务处理 109 | //启动执行报文的函数 110 | void dpi_loop(dpi_result *res) 111 | { 112 | //业务处理 113 | //每次pcap遍历一个报文都会调用我们的回调函数dpi_pcap_callback 114 | pcap_loop((pcap_t*)res->pcap_handle, 0, dpi_pcap_callback,(u_char*)res); 115 | } 116 | 117 | //3 资源释放 118 | void dpi_destory(dpi_result *res) 119 | { 120 | if(!res) 121 | return; 122 | 123 | //释放pcap的句柄 124 | pcap_close(res->pcap_handle); 125 | 126 | //释放自己的句柄 127 | free(res); 128 | 129 | //销毁链接链表 130 | destory_connection_list(); 131 | } 132 | 133 | 134 | //pcap回调函数 135 | void dpi_pcap_callback(u_char *user, const struct pcap_pkthdr *h, const u_char *data) 136 | { 137 | dpi_result *res = (dpi_result*)user; 138 | 139 | //以太网报文数量自增 140 | res->ether_count ++; 141 | 142 | //从package header 中输出报文的长度 143 | /* 144 | 每个packet header中都有两个字段 caplen len 145 | caplen -> 是抓取到的报文存到pcap文件中的实际大小 146 | len -> 是被抓取的报文的理应该大小 147 | 148 | 如果抓包的过程中,2k的报文,抓到1k数据后就中断 149 | caplen = 1k 150 | len = 2k 151 | */ 152 | //printf("caplen:%d , len %d\n", h->caplen, h->len); 153 | 154 | //保护措施 155 | //如果两个len不相等,说明报文被中弄断,不应该继续做解析 156 | if (h->caplen != h->len ) { 157 | return; 158 | } 159 | 160 | 161 | /* 162 | 解析以太帧 163 | ...--------+--------+--------+------+-----------+--------+ 164 | 前导码 |目的地址| 源地址 | 类型 | 数据 | CRC | 165 | ...--------+--------+--------+------+-----------+--------+ 166 | 6 6 2 46~1500 4 167 | */ 168 | //创建一个 pkt 结构体, 标识解析信息 169 | dpi_pkt pkt; 170 | memset(&pkt, 0, sizeof(pkt)); 171 | pkt.ether_len = h->caplen;//以太网报文长度 172 | pkt.ether_packet = (struct ether_header *)data; //以太网报文起始地址 173 | 174 | //以太网的报文类型 175 | //printf("type : %#x\n", ntohs(pkt.ether_packet->ether_type)); 176 | 177 | if (pkt.ether_packet->ether_type == htons(0x0800)) { 178 | //IP报文 179 | 180 | //解析ip报文 181 | pkt.ip_len = pkt.ether_len-sizeof(*pkt.ether_packet);//计算ip报文长度 182 | pkt.ip_packet = (struct iphdr*)((char*)pkt.ether_packet + sizeof(*pkt.ether_packet));//计算ip把稳的起始位置 183 | 184 | dpi_pkt_ip(res, &pkt); 185 | 186 | } else if (pkt.ether_packet->ether_type == htons(0x0806)) { 187 | //ARP 报文 188 | } else if (pkt.ether_packet->ether_type == htons(0x8035)) { 189 | //RARP 报文 190 | } 191 | 192 | 193 | //displayResult(res); 194 | 195 | } 196 | --------------------------------------------------------------------------------