├── README.md ├── pcap_catch.c └── pcap_analysis.c /README.md: -------------------------------------------------------------------------------- 1 | ## 介绍 2 | 3 | 基于 C语言 网络流量在线分析系统 4 | 5 | ## 实验环境 6 | 7 | > 1.操作系统:macOS Sierra 10.12.5 8 | 9 | > 2.编程语言:C语言 10 | 11 | > 3.网络数据包捕获函数包:libpcap 12 | 13 | > 4.Xcode 8.3.3 + mac终端 14 | 15 | ## 环境配置 16 | 17 | #### 1.tcpdump网站(http://www.tcpdump.org)下载libpcap的latest release 18 | 19 | #### 2.解压之后,在软件目录下执行./configure 20 | 21 | #### 3.执行 make 22 | 23 | #### 4.执行 make install,此时,在/usr/local/lib目录下会生成libpcap的动态链接库,如:libpcap.dylib 24 | 25 | #### 5.执行export DYLD_LIBRARY_PATH=/usr/local/lib 将此目录加入动态链接库的CLASSPATH 26 | #### 6.编写测试代码测试是否可用: 27 | ```bash 28 | // vim device.c 29 | #include 30 | #include 31 | int main(int argc,char *argv[]) { 32 | char *dev,errbuf[PCAP_ERRBUF_SIZE]; 33 | dev=pcap_lookupdev(errbuf); 34 | if(dev==NULL) { 35 | printf("couldn't find default device: %s\n",errbuf); 36 | return(2); 37 | } 38 | printf("Device: %s\n",dev); 39 | return(0); 40 | } 41 | ``` 42 | 43 | #### 7.执行编译指令: 44 | ```bash 45 | gcc -o device device.c -l pcap 46 | ``` 47 | 48 | #### 8.测试例程: 49 | ```bash 50 | sudo ./device 51 | ``` 52 | 如果显示:Device: en0 53 | 说明测试成功。 54 | 55 | ## 运行程序 56 | 57 | > 进入项目目录,在终端中运行下面的命令 58 | 59 | ```bash 60 | sudo su 61 | gcc -o catch pcap_catch.c -l pcap 62 | ./catch 63 | gcc -o analysis pcap_analysis.c -l pcap 64 | ./analysis 65 | ``` 66 | 67 | 68 | ## 实现功能 69 | - [x] 实时抓取网络中的数据包 70 | - [x] 离线存储网络中的数据包 71 | - [x] 分析各个网络协议格式 72 | - [x] 采用Hash链表的形式将网络数据以连接(双向流)的形式存储 73 | - [x] 计算并显示固定时间间隔内网络连接(双向流)的统计量 -------------------------------------------------------------------------------- /pcap_catch.c: -------------------------------------------------------------------------------- 1 | /** 2 | * 网络流量在线分析系统 3 | * 4 | * pcap_catch.c 5 | * 抓取网络数据包 6 | * 7 | * Created by 單棲情緒 on 2017/7/3. 8 | * Copyright © 2017年 單棲情緒. All rights reserved. 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | void callback(u_char *dumpfile, const struct pcap_pkthdr *pkthdr, const u_char *packet) 25 | { 26 | pcap_dump(dumpfile, pkthdr, packet); 27 | } 28 | 29 | int main() 30 | { 31 | char *device; // 网络设备 32 | char errbuf[PCAP_ERRBUF_SIZE]; // 错误信息 33 | bpf_u_int32 net; // 网络号 34 | bpf_u_int32 mask; // 掩码 35 | struct in_addr addr; 36 | pcap_t *handle; // 会话句柄 37 | struct bpf_program filter; /* 已经编译好的过滤器 */ 38 | char filter_app[] = "ip"; /* 过滤表达式 */ 39 | 40 | /* 网络设备名 */ 41 | device = pcap_lookupdev(errbuf); 42 | if(device == NULL) 43 | { 44 | printf("pcap_lookupdev:%s\n",errbuf); 45 | exit(1); 46 | } 47 | printf("网络设备:%s\n", device); 48 | 49 | /* 网络号和掩码 */ 50 | if(pcap_lookupnet(device, &net, &mask, errbuf) == -1){ 51 | printf("error\n"); 52 | exit(1); 53 | } 54 | 55 | addr.s_addr = net; 56 | printf("网络号:%s\n", inet_ntoa(addr)); 57 | 58 | addr.s_addr = mask; 59 | printf("网络掩码:%s\n", inet_ntoa(addr)); 60 | 61 | /* 设置抓取时长 */ 62 | int to_ms; 63 | printf("请输入抓取时长(s):"); 64 | scanf("%d", &to_ms); 65 | to_ms *= 1000; // 秒数转换为毫秒数 66 | 67 | /* 以混杂模式打开会话 */ 68 | handle = pcap_open_live(device, 65535, 1, to_ms, errbuf); 69 | if(handle == NULL) 70 | { 71 | printf("pcap_open_live:%s\n",errbuf); 72 | exit(1); 73 | } 74 | 75 | /* 编译并应用过滤器 */ 76 | if (pcap_compile(handle, &filter, filter_app, 1, mask) <0 ) 77 | { 78 | printf("Unable to compile the packet filter\n"); 79 | return 0; 80 | } 81 | if (pcap_setfilter(handle, &filter) < 0) 82 | { 83 | printf("Error setting the filter.\n"); 84 | exit(1); 85 | } 86 | 87 | /* 离线存储数据包 */ 88 | pcap_dumper_t *dumpfile; 89 | dumpfile = pcap_dump_open(handle, "/Users/sunmaer/我的文件/华中农业大学/综合实训/sniff/packet.data"); 90 | if(dumpfile == NULL){ 91 | printf("Error opening output file\n"); 92 | exit(1); 93 | } 94 | 95 | /* 抓取网络数据包 */ 96 | pcap_dispatch(handle, 0, callback, (u_char *)dumpfile); 97 | 98 | printf("数据包抓取成功\n"); 99 | 100 | /* 关闭 dumpfile */ 101 | pcap_dump_close(dumpfile); 102 | /* 关闭会话 */ 103 | pcap_close(handle); 104 | 105 | return 0; 106 | } 107 | 108 | -------------------------------------------------------------------------------- /pcap_analysis.c: -------------------------------------------------------------------------------- 1 | /** 2 | * 网络流量在线分析系统 3 | * 4 | * pcap_analysis.c 5 | * 分析网络数据包 6 | * 7 | * Created by 單棲情緒 on 2017/7/3. 8 | * Copyright © 2017年 單棲情緒. All rights reserved. 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | /* 数据包 IP 地址及端口 */ 25 | typedef struct _netset 26 | { 27 | u_int sip; 28 | u_int dip; 29 | u_short sport; 30 | u_short dport; 31 | u_char protocol; 32 | }netset; 33 | 34 | /* 数据包信息节点 */ 35 | typedef struct _net_link_node 36 | { 37 | netset nln_set; // 数据包 IP 地址及端口 38 | int nln_upl_size; // 数据包上传数据量 39 | int nln_downl_size; // 数据包下载数据量 40 | int nln_upl_pkt; // 数据包上传个数 41 | int nln_downl_pkt; // 数据包下载个数 42 | u_char nln_status; // 连接状态 43 | /* A 运行 TCP 客户程序, B 运行 TCP 服务器程序 */ 44 | #define CLOSED 0x00 45 | /* TCP 的连接建立 */ 46 | #define SYN_SENT 0x01 // A 向 B 发送连接请求报文段,首部中同步位 SYN = 1,A 进入同步已发送状态 SYN-SENT 47 | #define SYN_RECVD 0x02 // B 收到连接请求报文段,确认报文段中 SYN 和 ACK 都置1,B 进入同步收到状态 SYN-RCVD 48 | #define ESTABLISHED 0x03 // A 收到 B 的确认后,还须向 B 确认,确认报文段 ACK 置1,A 进入已连接状态 ESTABLISHED 49 | /* TCP 的连接释放 */ 50 | #define FIN_WAIT_1 0x04 // client send FIN 51 | #define CLOSE_WAIT 0x05 // server recv FIN, and send ACK 52 | #define FIN_WAIT_2 0x06 // client recv ACK 53 | #define LAST_ACK 0x07 // server send FIN 54 | #define TIME_WAIT 0x08 // client recv FIN 55 | // CLOSED: client send ACK, server recv ACK 56 | #define UNDEFINED 0xff 57 | struct _net_link_node *next; // 下一个数据包地址 58 | }net_link_node, *p_net_link; 59 | 60 | /* 链表头-统计信息 */ 61 | typedef struct _net_link_header 62 | { 63 | int count_conn; // 连接个数 64 | int count_upl_pkt; // 数据包总上传数据量 65 | int count_downl_pkt; // 数据包总下载数据量 66 | int count_upl; // 数据包总上传个数 67 | int count_downl; // 数据包总下载个数 68 | p_net_link link; // 第一个数据包地址 69 | }net_link_header; 70 | 71 | /* 将 int 类型的时间转换为 年-月-日 时:分:秒 形式 */ 72 | char *longTime(long ltime) 73 | { 74 | time_t t; 75 | struct tm *p; 76 | static char s[100]; 77 | 78 | t = ltime; 79 | p = localtime(&t); 80 | 81 | strftime(s, sizeof(s), "%Y-%m-%d %H:%M:%S", p); 82 | return s; 83 | } 84 | 85 | /* 点十分制 IP 地址转换函数 */ 86 | #define IPTOSBUFFERS 12 87 | static char *iptos(bpf_u_int32 in) 88 | { 89 | static char output[IPTOSBUFFERS][3*4+3+1]; 90 | static short which; 91 | u_char *p; 92 | 93 | p = (u_char *)∈ 94 | which = (which + 1 == IPTOSBUFFERS ? 0 : which + 1); 95 | sprintf(output[which], "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); 96 | return output[which]; 97 | } 98 | 99 | /* 100 | * 三个链表 101 | * 一个哈希链表,保存处于连接状态的数据包 102 | * 两个链表分别保存tcp和udp的流量 103 | */ 104 | 105 | net_link_header *FLowLink_TCP; // TCP 流量链表 106 | net_link_header *FLowLink_UDP; // UDP 流量链表 107 | 108 | /* ========== hash table ============= */ 109 | #define HASH_TABLE_SIZE 0xffff 110 | p_net_link HashTable[HASH_TABLE_SIZE]; // 保存处于连接状态的数据包 111 | 112 | /* 初始化流量链表 */ 113 | void init_flowLink(net_link_header *head) 114 | { 115 | head->count_conn = 0; 116 | head->count_upl_pkt = 0; 117 | head->count_downl_pkt = 0; 118 | head->count_upl = 0; 119 | head->count_downl = 0; 120 | head->link = NULL; 121 | } 122 | 123 | /* 清空流量链表 */ 124 | void clear_flowLink(net_link_header *head) 125 | { 126 | if( head->link == NULL ){ return;} 127 | 128 | net_link_node *pTemp1 = NULL; 129 | net_link_node *pTemp2 = NULL; 130 | 131 | pTemp1 = head->link; 132 | pTemp2 = pTemp1->next; 133 | while( pTemp2 != NULL ) 134 | { 135 | free(pTemp1); 136 | pTemp1 = pTemp2; 137 | pTemp2 = pTemp1->next; 138 | } 139 | free(pTemp1); 140 | 141 | head->link = NULL; 142 | } 143 | 144 | /* TCP 数据包流量分析 */ 145 | void parse_flowLink_TCP(FILE *fOutput) 146 | { 147 | fprintf(fOutput, "TCP连接个数:\t%d\n", FLowLink_TCP->count_conn); 148 | fprintf(fOutput, "TCP数据包个数:\t%d\n", FLowLink_TCP->count_upl_pkt + FLowLink_TCP->count_downl_pkt); 149 | fprintf(fOutput, "TCP数据总流量:\t%d bytes\n", FLowLink_TCP->count_upl + FLowLink_TCP->count_downl); 150 | fprintf(fOutput, "TCP数据上传量:\t%d bytes\n", FLowLink_TCP->count_upl); 151 | fprintf(fOutput, "TCP数据下载量:\t%d bytes\n", FLowLink_TCP->count_downl); 152 | fprintf(fOutput, "--------------------------------------------------------\n"); 153 | 154 | net_link_node *pTemp = NULL; 155 | pTemp = FLowLink_TCP->link; 156 | while( pTemp != NULL ) 157 | { 158 | fprintf(fOutput, "%s\t%u\t", iptos(pTemp->nln_set.sip), pTemp->nln_set.sport); 159 | fprintf(fOutput, "==>\t%s\t%u\t", iptos(pTemp->nln_set.dip), pTemp->nln_set.dport); 160 | fprintf(fOutput, "上传包数量:%d\t", pTemp->nln_upl_pkt); 161 | fprintf(fOutput, "下载包数量:%d\t", pTemp->nln_downl_pkt); 162 | fprintf(fOutput, "上传量:%d bytes\t", pTemp->nln_upl_size); 163 | fprintf(fOutput, "下载量:%d bytes\t", pTemp->nln_downl_size); 164 | fprintf(fOutput, "\n"); 165 | pTemp = pTemp->next; 166 | } 167 | clear_flowLink(FLowLink_TCP); 168 | } 169 | 170 | /* UDP 数据包流量分析 */ 171 | void parse_flowLink_UDP(FILE *fOutput) 172 | { 173 | fprintf(fOutput, "UDP数据包个数:\t%d\n", FLowLink_UDP->count_upl_pkt + FLowLink_UDP->count_downl_pkt); 174 | fprintf(fOutput, "UDP数据流量:\t%d bytes\n", FLowLink_UDP->count_upl + FLowLink_UDP->count_downl); 175 | clear_flowLink(FLowLink_UDP); 176 | } 177 | 178 | void add_to_flowLink(net_link_header *head, const net_link_node *theNode) 179 | { 180 | net_link_node *newNode = (net_link_node *)malloc(sizeof(net_link_node)); 181 | memcpy(newNode, theNode, sizeof(net_link_node)); 182 | 183 | head->count_conn ++; 184 | head->count_upl_pkt += newNode->nln_upl_pkt; 185 | head->count_downl_pkt += newNode->nln_downl_pkt; 186 | head->count_upl += newNode->nln_upl_size; 187 | head->count_downl += newNode->nln_downl_size; 188 | 189 | /* 插入一个节点 */ 190 | newNode->next = head->link; 191 | head->link = newNode; 192 | } 193 | 194 | /* HASH 值计算 */ 195 | u_short get_hash(const netset *theSet) 196 | { 197 | u_int srcIP = theSet->sip; 198 | u_int desIP = theSet->dip; 199 | u_int port = (u_int)(theSet->sport * theSet->dport); 200 | u_int res = (srcIP^desIP)^port; 201 | u_short hash= (u_short)((res & 0x00ff)^(res >> 16)); 202 | return hash; 203 | } 204 | 205 | /* 连接状态数据包 */ 206 | void add_to_hashTable(u_short hash, const net_link_node *theNode, u_char flags) 207 | { 208 | net_link_node *HashNode = (net_link_node *)malloc(sizeof(net_link_node)); 209 | memcpy(HashNode, theNode, sizeof(net_link_node)); 210 | 211 | if(HashTable[hash] == NULL) // 判断当前 HASH 关键字是否已存在,不存在就将当前节点加入 HASH 链表 212 | { 213 | HashTable[hash] = HashNode; 214 | return; 215 | } 216 | net_link_node *pTemp = HashTable[hash]; 217 | net_link_node *pBack = NULL; 218 | int isSame_up = 0; // 同一上传连接 219 | int isSame_down = 0; // 同一下载连接 220 | while(pTemp != NULL) 221 | { 222 | /* IP 地址和端口匹配 */ 223 | isSame_up = (pTemp->nln_set.sip == HashNode->nln_set.sip) 224 | && (pTemp->nln_set.dip == HashNode->nln_set.dip) 225 | && (pTemp->nln_set.sport == HashNode->nln_set.sport) 226 | && (pTemp->nln_set.dport == HashNode->nln_set.dport); 227 | 228 | isSame_down = (pTemp->nln_set.dip == HashNode->nln_set.sip) 229 | && (pTemp->nln_set.sip == HashNode->nln_set.dip) 230 | && (pTemp->nln_set.dport == HashNode->nln_set.sport) 231 | && (pTemp->nln_set.sport == HashNode->nln_set.dport); 232 | 233 | if( isSame_up ) 234 | { 235 | pTemp->nln_upl_size += HashNode->nln_upl_size; 236 | pTemp->nln_upl_pkt ++; 237 | if(pTemp->nln_status == ESTABLISHED && (flags & TH_FIN) ) 238 | { 239 | pTemp->nln_status = FIN_WAIT_1; 240 | } 241 | else if (pTemp->nln_status == TIME_WAIT && (flags & TH_ACK)) 242 | { 243 | pTemp->nln_status = CLOSED; 244 | if(pBack == NULL) 245 | { 246 | HashTable[hash] = NULL; 247 | } 248 | else 249 | { 250 | pBack->next = pTemp->next; 251 | } 252 | add_to_flowLink(FLowLink_TCP, pTemp); 253 | free(pTemp); 254 | } 255 | else if(pTemp->nln_status == CLOSE_WAIT && (flags & TH_FIN)) 256 | { 257 | pTemp->nln_status = LAST_ACK; 258 | } 259 | free(HashNode); 260 | break; 261 | } 262 | else if( isSame_down ) 263 | { 264 | pTemp->nln_downl_size += HashNode->nln_upl_size; 265 | pTemp->nln_downl_pkt ++; 266 | if(pTemp->nln_status == ESTABLISHED && (flags & TH_FIN)) 267 | { 268 | pTemp->nln_status = CLOSE_WAIT; 269 | } 270 | else if(pTemp->nln_status == LAST_ACK && (flags & TH_ACK)) 271 | { 272 | pTemp->nln_status = CLOSED; 273 | if(pBack == NULL) 274 | { 275 | HashTable[hash] = NULL; 276 | } 277 | else 278 | { 279 | pBack->next = pTemp->next; 280 | } 281 | add_to_flowLink(FLowLink_TCP, pTemp); 282 | free(pTemp); 283 | } 284 | else if(pTemp->nln_status == FIN_WAIT_1 && (flags & TH_ACK)) 285 | { 286 | pTemp->nln_status = FIN_WAIT_2; 287 | } 288 | else if(pTemp->nln_status == FIN_WAIT_2 && (flags & TH_FIN)) 289 | { 290 | pTemp->nln_status = TIME_WAIT; 291 | } 292 | 293 | free(HashNode); 294 | break; 295 | } 296 | pBack = pTemp; 297 | pTemp = pTemp->next; 298 | } 299 | if(pTemp == NULL) 300 | { 301 | pBack->next = HashNode; 302 | } 303 | } 304 | 305 | /* 初始化 HASH 表 */ 306 | void clear_hashTable() 307 | { 308 | int i = 0; 309 | net_link_node *pTemp1 = NULL; 310 | net_link_node *pTemp2 = NULL; 311 | for(i = 0; i < HASH_TABLE_SIZE; i++) 312 | { 313 | if(HashTable[i] == NULL){ continue;} 314 | 315 | pTemp1 = HashTable[i]; 316 | while(pTemp1 != NULL) 317 | { 318 | pTemp2 = pTemp1->next; 319 | add_to_flowLink(FLowLink_TCP, pTemp1); 320 | free(pTemp1); 321 | pTemp1 = pTemp2; 322 | } 323 | HashTable[i] = NULL; 324 | } 325 | } 326 | 327 | 328 | /* 数据包分析函数 */ 329 | void pcapAnalysis(u_char *dumpfile, const struct pcap_pkthdr *pkthdr, const u_char *packet); 330 | 331 | int main(int argc, char **argv) 332 | { 333 | printf("载入文件......\n"); 334 | 335 | /* 输入分析周期 */ 336 | int cycle; 337 | printf("输入分析周期(s):"); 338 | scanf("%d", &cycle); 339 | cycle = cycle > 0?cycle:10; 340 | 341 | pcap_t *handle; // 会话句柄 342 | char errbuf[PCAP_ERRBUF_SIZE]; // 错误信息 343 | 344 | /* 读取离线存储数据包文件 */ 345 | handle = pcap_open_offline("/Users/sunmaer/我的文件/华中农业大学/综合实训/sniff/packet.data",errbuf); 346 | printf("开始分析\n"); 347 | 348 | FLowLink_TCP = (net_link_header *)malloc(sizeof(net_link_header)); 349 | 350 | FLowLink_UDP = (net_link_header *)malloc(sizeof(net_link_header)); 351 | 352 | init_flowLink(FLowLink_TCP); 353 | init_flowLink(FLowLink_UDP); 354 | 355 | pcap_loop(handle, -1, pcapAnalysis, (u_char *)&cycle); 356 | printf("分析结束\n"); 357 | 358 | free(FLowLink_TCP); 359 | free(FLowLink_UDP); 360 | return 0; 361 | } 362 | 363 | void pcapAnalysis(u_char *userarg, const struct pcap_pkthdr *pkthdr, const u_char *packet) 364 | { 365 | 366 | static int id = 1; 367 | 368 | struct ether_header *eptr = (struct ether_header*)packet; // 得到以太网字头 369 | struct ip *ipptr = (struct ip*)(packet+sizeof(struct ether_header)); // 得到 IP 报头 370 | struct tcphdr *tcpptr = (struct tcphdr*)(packet+sizeof(struct ether_header)+sizeof(struct ip)); // 得到 TCP 包头 371 | struct udphdr *udpptr = (struct udphdr*)(packet+sizeof(struct ether_header)+sizeof(struct ip)); // 得到 UDP 包头 372 | u_char *ptr; 373 | int i; 374 | 375 | /* 计算周期内的相关统计量并输出到文件 */ 376 | int *cycle = (int *)userarg; // 计算周期 377 | static long tstamp_start = 0; // 第一次抓包时间 378 | static long tstamp_offset = 0; // 上一轮分析周期结束时间 379 | static long tstamp_now = 0; // 当前数据包抓取时间 380 | 381 | /* 存储分析结果 */ 382 | char *file_output = "/Users/sunmaer/我的文件/华中农业大学/综合实训/sniff/result.data"; 383 | FILE *fOutput; 384 | fOutput = fopen(file_output, "a+"); 385 | 386 | u_short ipLen_real = 0; 387 | u_short ipLen_total = 0; 388 | u_short tcpLen_real = 0; 389 | u_short dataLen = 0; 390 | 391 | netset *CurSet = (netset *)malloc(sizeof(netset)); 392 | net_link_node *LinkNode = (net_link_node *)malloc(sizeof(net_link_node)); 393 | 394 | if(id == 1) { 395 | tstamp_start = pkthdr->ts.tv_sec; 396 | tstamp_offset = tstamp_start; 397 | 398 | fOutput = fopen(file_output, "w"); 399 | fclose(fOutput); // 清空文件 400 | fOutput = fopen(file_output, "a+"); 401 | /* 数据包文件名字 */ 402 | fprintf(fOutput, "数据文件:%s\n", "packet.data"); 403 | fprintf(fOutput, "分析周期:%d s\n", *cycle); 404 | } 405 | 406 | tstamp_now = pkthdr->ts.tv_sec; 407 | 408 | if((tstamp_now - tstamp_offset) >= *cycle) { 409 | fprintf(fOutput, "\n>>>>> 时间段:%s", longTime(tstamp_offset)); 410 | fprintf(fOutput, " --> %s\n", longTime(tstamp_offset + *cycle)); 411 | 412 | /* 统计 UDP 数据包数量,数据量大小 */ 413 | fprintf(fOutput, "--------------------------------------------------------\n"); 414 | clear_hashTable(); 415 | parse_flowLink_UDP(fOutput); 416 | init_flowLink(FLowLink_UDP); 417 | 418 | /* 统计 TCP 数据包数量,数据量大小 */ 419 | fprintf(fOutput, "--------------------------------------------------------\n"); 420 | parse_flowLink_TCP(fOutput); 421 | init_flowLink(FLowLink_TCP); 422 | fprintf(fOutput, "\n"); 423 | /* 下一个分析周期开始时间 */ 424 | tstamp_offset = tstamp_now; 425 | } 426 | 427 | if(ntohs(eptr->ether_type) == ETHERTYPE_IP) { // 判断是否为 IP 数据包 428 | if(ipptr->ip_p == IPPROTO_TCP || ipptr->ip_p == IPPROTO_UDP) { // 判断是否为 TCP UDP 数据包 429 | 430 | ipLen_real = (ipptr->ip_hl & 0x0f)*4; // 大小端处理并且填充至4字节整数倍 431 | ipLen_total = ntohs(ipptr->ip_len); 432 | 433 | CurSet->sip = ipptr->ip_src.s_addr; // 存储源 IP 地址 434 | CurSet->dip = ipptr->ip_dst.s_addr; // 存储目的 IP 地址 435 | CurSet->protocol = ipptr->ip_p; 436 | 437 | if(ipptr->ip_p == IPPROTO_TCP) { 438 | 439 | tcpLen_real = (((tcpptr->th_off)>>4) & 0x0f) * 4; 440 | dataLen = ipLen_total - ipLen_real - tcpLen_real; 441 | 442 | CurSet->sport = ntohs(tcpptr->th_sport); // 存储 TCP 源端口 443 | CurSet->dport = ntohs(tcpptr->th_dport); // 存储 TCP 目的端口 444 | } else if(ipptr->ip_p == IPPROTO_UDP) { 445 | 446 | dataLen = ntohs(udpptr->uh_ulen) - 8; // UDP 用户数据包长度包括8个字节的首部信息 447 | CurSet->sport = ntohs(udpptr->uh_sport); // 存储 UDP 源端口 448 | CurSet->dport = ntohs(udpptr->uh_dport); // 存储 UDP 目的端口 449 | } 450 | 451 | /* 保存当前数据包 */ 452 | LinkNode->nln_set = *CurSet; 453 | LinkNode->nln_upl_size = dataLen; 454 | LinkNode->nln_downl_size= 0; 455 | LinkNode->nln_upl_pkt = 1; 456 | LinkNode->nln_downl_pkt = 0; 457 | LinkNode->nln_status = ESTABLISHED; 458 | LinkNode->next = NULL; 459 | 460 | if(ipptr->ip_p == IPPROTO_TCP) 461 | { 462 | /* 将当前节点加入 TCP 协议 HASH 链表 */ 463 | add_to_hashTable(get_hash(CurSet), LinkNode, tcpptr->th_flags); 464 | } 465 | else if(ipptr->ip_p == IPPROTO_UDP) 466 | { 467 | /* 将当前节点加入 UDP 协议链表 */ 468 | add_to_flowLink(FLowLink_UDP, LinkNode); 469 | } 470 | 471 | } 472 | } 473 | 474 | fprintf(fOutput, "\n**************************开始**************************\n"); 475 | fprintf(fOutput, "ID:%d\n", id++); 476 | fprintf(fOutput, "数据包长度:%d\n", pkthdr->len); 477 | fprintf(fOutput, "实际捕获包长度:%d\n", pkthdr->caplen); 478 | fprintf(fOutput, "时间:%s", ctime((const time_t *)&pkthdr->ts.tv_sec)); 479 | 480 | fprintf(fOutput, "-----------------数据链路层 解析以太网帧-----------------\n"); 481 | ptr = eptr->ether_dhost; 482 | i = ETHER_ADDR_LEN; 483 | fprintf(fOutput, "目的 MAC 地址:"); 484 | do 485 | { 486 | fprintf(fOutput, "%s%x", (i == ETHER_ADDR_LEN)?"":":", *ptr++); 487 | } while(--i>0); 488 | fprintf(fOutput, "\n"); 489 | 490 | ptr = eptr->ether_shost; 491 | i = ETHER_ADDR_LEN; 492 | fprintf(fOutput, "源 MAC 地址:"); 493 | do 494 | { 495 | fprintf(fOutput, "%s%x", (i == ETHER_ADDR_LEN)?"":":", *ptr++); 496 | } while(--i>0); 497 | fprintf(fOutput, "\n"); 498 | 499 | fprintf(fOutput, "以太网帧类型:%x\n", ntohs(eptr->ether_type)); 500 | 501 | fprintf(fOutput, "-----------------数据链路层 解析 IP 报头-----------------\n"); 502 | fprintf(fOutput, "版本号:%d\n", ipptr->ip_v); 503 | fprintf(fOutput, "首部长度:%d\n", ipptr->ip_hl); 504 | fprintf(fOutput, "服务类型:%hhu\n", ipptr->ip_tos); 505 | fprintf(fOutput, "报文总长度:%d\n", ntohs(ipptr->ip_len)); 506 | fprintf(fOutput, "标识:%d\n", ntohs(ipptr->ip_id)); 507 | fprintf(fOutput, "片偏移:%d\n", ntohs(ipptr->ip_off)); 508 | fprintf(fOutput, "生存时间:%hhu\n", ipptr->ip_ttl); 509 | fprintf(fOutput, "协议类型:%hhu\n", ipptr->ip_p); 510 | fprintf(fOutput, "首部校验和:%d\n", ntohs(ipptr->ip_sum)); 511 | fprintf(fOutput, "源地址:%s\n", inet_ntoa(ipptr->ip_src)); 512 | fprintf(fOutput, "目的地址:%s\n", inet_ntoa(ipptr->ip_dst)); 513 | 514 | 515 | /* 根据 IP 报头协议类型字段判断数据携带协议类型,TCP 协议类型为6, UDP 协议类型为17 */ 516 | if(ipptr->ip_p == IPPROTO_TCP) { 517 | 518 | fprintf(fOutput, "-----------------数据链路层 解析 TCP 报头-----------------\n"); 519 | fprintf(fOutput, "目的端口:%d\n", ntohs(tcpptr->th_dport)); 520 | fprintf(fOutput, "源端口:%d\n", ntohs(tcpptr->th_sport)); 521 | fprintf(fOutput, "序列号:%u\n", tcpptr->th_seq); 522 | fprintf(fOutput, "确认号:%u\n", tcpptr->th_ack); 523 | fprintf(fOutput, "报头长度:%d\n", tcpptr->th_off); 524 | fprintf(fOutput, "保留:%d\n", tcpptr->th_x2); 525 | fprintf(fOutput, "标志:%hhu\n", tcpptr->th_flags); 526 | fprintf(fOutput, "窗口:%d\n", ntohs(tcpptr->th_win)); 527 | fprintf(fOutput, "校验和:%d\n", ntohs(tcpptr->th_sum)); 528 | fprintf(fOutput, "紧急:%d\n", ntohs(tcpptr->th_urp)); 529 | 530 | } else if(ipptr->ip_p == IPPROTO_UDP) { 531 | 532 | fprintf(fOutput, "----------------数据链路层 解析 UDP 报头-----------------\n"); 533 | fprintf(fOutput, "源端口:%d\n", ntohs(udpptr->uh_sport)); 534 | fprintf(fOutput, "目的端口:%d\n", ntohs(udpptr->uh_dport)); 535 | fprintf(fOutput, "用户数据包长度:%d\n", ntohs(udpptr->uh_ulen)); 536 | fprintf(fOutput, "校验和:%d\n", ntohs(udpptr->uh_sum)); 537 | 538 | } 539 | 540 | fprintf(fOutput, "**************************结束**************************\n"); 541 | 542 | free(CurSet); 543 | free(LinkNode); 544 | fclose(fOutput); 545 | } 546 | 547 | --------------------------------------------------------------------------------