使用libpcab抓包&处理包
#include <stdio.h> #include <stdlib.h> #include <strings.h> #include <string.h> #include <pcap.h> #include <ctype.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> /* 默认捕获长度 (每个包捕获的最大长度) */ #define SNAP_LEN 1518 /* 以太网头部14个字节 */ #define SIZE_ETHERNET 14 /* 以太网地址6个字节 */ #define ETHER_ADDR_LEN 6 #define NUM_PACKET 5 #define PACKETS_NUM 2000 #define TCP_FLAG 0 #define UDP_FLAG 1 #define MYIP "192.168.1.106" /* UDP header */ struct sniff_udp { uint16_t sport; /* source port */ uint16_t dport; /* destination port */ uint16_t udp_length; uint16_t udp_sum; /* checksum 检验和 */ }; /* Ethernet header */ struct sniff_ethernet { u_char ether_dhost[ETHER_ADDR_LEN]; /* destination host address */ u_char ether_shost[ETHER_ADDR_LEN]; /* source host address */ u_short ether_type; /* IP? ARP? RARP? etc */ }; /* IP header */ struct sniff_ip { u_char ip_vhl; /* version << 4 | header length >> 2 */ u_char ip_tos; /* type of service */ u_short ip_len; /* total length */ u_short ip_id; /* identification */ u_short ip_off; /* fragment offset field */ #define IP_RF 0x8000 /* reserved fragment flag */ #define IP_DF 0x4000 /* dont fragment flag */ #define IP_MF 0x2000 /* more fragments flag */ #define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ u_char ip_ttl; /* time to live */ u_char ip_p; /* protocol */ u_short ip_sum; /* checksum */ struct in_addr ip_src,ip_dst; /* source and dest address */ }; #define IP_HL(ip) (((ip)->ip_vhl) & 0x0f) #define IP_V(ip) (((ip)->ip_vhl) >> 4) /* TCP header */ typedef unsigned long tcp_seq; struct sniff_tcp { u_short th_sport; /* source port */ u_short th_dport; /* destination port */ tcp_seq th_seq; /* sequence number */ tcp_seq th_ack; /* acknowledgement number */ u_char th_offx2; /* data offset, rsvd */ #define TH_OFF(th) (((th)->th_offx2 & 0xf0) >> 4) u_char th_flags; #define TH_FIN 0x01 #define TH_SYN 0x02 #define TH_RST 0x04 #define TH_PUSH 0x08 #define TH_ACK 0x10 #define TH_URG 0x20 #define TH_ECE 0x40 #define TH_CWR 0x80 #define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR) u_short th_win; /* window */ u_short th_sum; /* checksum */ u_short th_urp; /* urgent pointer */ }; int tcp_num_count; int udp_num_count; int fin, syn, rst, push, ack, urg, ece, cwr; void callback(unsigned char*, const struct pcap_pkthdr*, const unsigned char*); int main() { char errBuf[PCAP_ERRBUF_SIZE]; char *dev = NULL; // dev应设置为网卡 /* 获取网络设备接口,即网络设备名 */ dev = pcap_lookupdev(errBuf); // dev应设置为网卡 /* 显示捕获设备信息 * printf("Device: %s\n", dev); */ if (dev == NULL) { printf("%s\n", errBuf); exit(1); } // netp为ip地址, bpf_u_int32为32位无符号整型 bpf_u_int32 netp = 0, maskp = 0; int ret = 0; /* 获取网络号和掩码,成功返回0 */ ret = pcap_lookupnet(dev, &netp, &maskp, errBuf); if (ret == -1) { printf("%s\n", errBuf); exit(1); } // printf("ip = %d\n", netp); 应转化为点二进制形式 // 打开网络接口 // 参数分别为接口名, 捕获数据包的长度不能超过65535字节 // 混杂模式, 等待的ms数(超过该时间函数立即返回,0表示一直等待) pcap_t* pcap_handle = pcap_open_live(dev, SNAP_LEN, 1, 0, errBuf); //实例 pcap_t *pcap_handle = pcap_open_live("eth0", 1024, 1, 0, errBuf); if (pcap_handle == NULL) { printf("%s\n", errBuf); exit(1); } /* pcap_datalink(); * 返回数据链路层类型,例如DLT_EN10MB; * 确保我们对以太网设备捕获 */ if (pcap_datalink(pcap_handle) != DLT_EN10MB) { fprintf(stderr, "%s is not an Ethernet\n", dev); exit(EXIT_FAILURE); } // 捕获单个数据包 const u_char *pcap_next(pcap_t *p,struct pcap_pkthdr *h); // 参数分别为:打开网络接口返回的指针 捕获的数据包头 /* const unsigned char *packet_addr = NULL; // 捕获的包的地址 struct pcap_pkthdr packet_header; // 抓到的时间 实际长度 原来长度 packet_addr = pcap_next(pcap_handle, &packet_header); printf("Packet's length is:%d\n", packet_header.len); // 原来长度 printf("Packet's true length is:%d\n", packet_header.caplen); */ // 捕获多个数据包 int pcap_loop(pcap_t *p,int cnt,pcap_handler callback,u_char *user); // 每捕获一个就调用callback指定的回调函数,可在回调函数中处理数据包 // 参数分别为:同pcap_next 指定捕获数据包的个数(设为-1将一直捕获) // 参数分别为:回调函数(名字自取) 向回调函数中传递的参数 // 回调函数说明 void callback(u_char *userarg,const struct pcap_pkthdr *pkthdr,const u_char *packet) // 参数:pcap_loop的最后一个参数 捕获的数据包的头(同pcap_next第二个参数) // 参数:捕获的的数据包数据 /* 设置回掉函数并开始捕获包 */ if (pcap_loop(pcap_handle, NUM_PACKET, callback, NULL) < 0) { perror("pcap_loop finish!\n"); } // 捕获多个数据包 int pcap_dispatch(pcap_t *p,int cnt,pcap_handler callback,u_char *user); // 说明:和pcap_loop类似,只是超过x毫秒后返回(x是pcap_open_live的第四个参数) // 关闭网络接口 pcap_close(pcap_handle); } //void func(unsigned char *argument, const struct pcap_pkthdr *packet_header, const unsigned char *packet_data) //{ // printf("使用pcap_loop的回调函数,该包长度为%d\n", packet_header->len); //} void callback(unsigned char *args, const struct pcap_pkthdr *header, const unsigned char *packet) { static int count = 1; /* 包计数器,记录捕获多少包 */ /* 显示包总数 * printf("\nPacket number %d:\n", count); * count++; */ /* declare pointers to packet headers */ struct sniff_ethernet *ethernet; /* 以太网头部 */ struct sniff_ip *ip; /* IP 头部 */ struct sniff_tcp *tcp; /* TCP 头部 */ struct sniff_udp *udp; /* UDP 头部 */ unsigned char *payload; /* Packet payload */ int size_ip; int size_tcp; int size_udp; int size_payload; int proto_flag = 2; // 0=TCP_FLAG; 1=UDP_FLAG //==== /* 定义以太网头部 */ ethernet = (struct sniff_ethernet*)(packet); /* 定义/计算 IP 头部偏移 */ ip = (struct sniff_ip*)(packet + SIZE_ETHERNET); size_ip = IP_HL(ip)*4; // ip头部长度 if (size_ip < 20) { printf(" * Invalid IP header length: %u bytes\n", size_ip); return; } /* 显示源IP和目的IP print source and destination IP addresses */ // only print internet->me information if(strcmp(inet_ntoa(ip->ip_src), MYIP) == 0) return; /* 确定协议 determine protocol */ switch(ip->ip_p) { case IPPROTO_TCP: //useful // printf(" Protocol: TCP\n"); proto_flag=0; break; case IPPROTO_UDP: //useful // printf(" Protocol: UDP\n"); proto_flag=1; break; case IPPROTO_ICMP: //useless // printf(" Protocol: ICMP\n"); return; case IPPROTO_IP: //useless // printf(" Protocol: IP\n"); return; default: // printf(" Protocol: unknown\n"); return; } /* * This packet is TCP. */ if (proto_flag == 0) { /* 定义/计算 TCP 头部偏移 */ tcp = (struct sniff_tcp *) (packet + SIZE_ETHERNET + size_ip); /* 计算TCP头部长度 */ size_tcp = TH_OFF(tcp) * 4; if (size_tcp < 20) { printf (" * Invalid TCP header length: %u bytes\n", size_tcp); return; } // printf(" From: %s\n", inet_ntoa(ip->ip_src)); // printf(" To: %s\n", inet_ntoa(ip->ip_dst)); printf (" Src port : %d\n", ntohs (tcp->th_sport)); printf (" Dst port : %d\n", ntohs (tcp->th_dport)); printf (" Seq number: %d\n", ntohl (tcp->th_seq)); int fin=0; if(tcp->th_flags & TH_FIN) fin=1; printf (" FIN : %d\n", fin); /* define/compute tcp payload (segment) offset */ payload = (unsigned char *) (packet + SIZE_ETHERNET + size_ip + size_tcp); /* compute tcp payload (segment) size , 即TCP报文数据部分字节数 */ size_payload = ntohs (ip->ip_len) - (size_ip + size_tcp); printf (" TCP size_payload: %d\n", size_payload); printf (" Payload (%d bytes):\n", size_payload); /* if (size_payload > 0) { //printf (" Payload (%d bytes):\n", size_payload); // insert_tcp_hex_mysql(0, inet_ntoa(ip->ip_src), inet_ntoa(ip->ip_dst), ntohs (tcp->th_sport), ntohs (tcp->th_dport), payload, ntohl (tcp->th_seq), size_payload,fin ); } */ } //end tcp //===================================================================================== /* * This packet is UDP. */ else if (proto_flag == 1) { /* define/compute udp header offset */ udp = (struct sniff_udp *) (packet + SIZE_ETHERNET + size_ip); // printf(" From: %s\n", inet_ntoa(ip->ip_src)); // printf(" To: %s\n", inet_ntoa(ip->ip_dst)); printf (" Src port: %d\n", ntohs (udp->sport)); printf (" Dst port: %d\n", ntohs (udp->dport)); printf ("udp length:%d\n", ntohs (udp->udp_length)); // printf ("udp sum:%d\n", ntohs (udp->udp_sum)); /* define/compute udp payload (segment) offset */ payload = (unsigned char *) (packet + SIZE_ETHERNET + size_ip + 8); size_payload = ntohs (ip->ip_len) - (size_ip + 8); printf (" UDP size_payload: %d\n", size_payload); }//end udp return; }