LINUX C网络抓包分析
本文地址:http://tongxinmao.com/Article/Detail/id/227
#include <sys/types.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <net/if.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <unistd.h> #include <linux/if_packet.h> #include <netinet/if_ether.h> #include <netinet/in.h> //#include <cap.h> typedef unsigned char BYTE; typedef struct _iphdr //定义IP首部 { unsigned char h_verlen; //4位首部长度+4位IP版本号 unsigned char tos; //8位服务类型TOS unsigned short total_len; //16位总长度(字节) unsigned short ident; //16位标识 unsigned short frag_and_flags; //3位标志位 unsigned char ttl; //8位生存时间 TTL unsigned char proto; //8位协议 (TCP, UDP 或其他) unsigned short checksum; //16位IP首部校验和 unsigned int sourceIP; //32位源IP地址 unsigned int destIP; //32位目的IP地址 }IP_HEADER; typedef struct _udphdr //定义UDP首部 { unsigned short uh_sport; //16位源端口 unsigned short uh_dport; //16位目的端口 unsigned int uh_len;//16位UDP包长度 unsigned int uh_sum;//16位校验和 }UDP_HEADER; typedef struct _tcphdr //定义TCP首部 { unsigned short th_sport; //16位源端口 unsigned short th_dport; //16位目的端口 unsigned int th_seq; //32位序列号 unsigned int th_ack; //32位确认号 unsigned char th_lenres;//4位首部长度/6位保留字 unsigned char th_flag; //6位标志位 unsigned short th_win; //16位窗口大小 unsigned short th_sum; //16位校验和 unsigned short th_urp; //16位紧急数据偏移量 }TCP_HEADER; typedef struct _icmphdr { unsigned char icmp_type; unsigned char icmp_code; /* type sub code */ unsigned short icmp_cksum; unsigned short icmp_id; unsigned short icmp_seq; /* This is not the std header, but we reserve space for time */ unsigned short icmp_timestamp; }ICMP_HEADER; /* ip首部长度 */ #define IP_HEADER_LEN sizeof(IP_HEADER) /* tcp首部长度 */ #define TCP_HEADER_LEN sizeof(TCP_HEADER) /* ip首部 + tcp首部长度 */ #define IP_TCP_HEADER_LEN IP_HEADER_LEN + TCP_HEADER_LEN void analyseIP(IP_HEADER *ip); void analyseTCP(IP_HEADER *ip,TCP_HEADER *tcp); void analyseUDP(UDP_HEADER *udp); void analyseICMP(ICMP_HEADER *icmp); #define ETH_NAME "eth0" int revlen=0; int iphlen=0; int tcphlen=0; BYTE buf[1024*1024]; int byteCount=0; //ifconfig eth0 promisc 设置好网卡混杂模式则不需要编程实现,否则需要编程实现。 int do_promisc(void) { int f, s; struct ifreq ifr; if ( (f=socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)))<0){ return -1; } strcpy(ifr.ifr_name, ETH_NAME); if ((s = ioctl(f, SIOCGIFFLAGS, &ifr))<0){ close(f); return-1; } if(ifr.ifr_flags & IFF_RUNNING){ printf("eth link up\n"); }else{ printf("eth link down\n"); } ifr.ifr_flags |= IFF_PROMISC; if ((s = ioctl(f, SIOCSIFFLAGS, &ifr)) < 0){ return -1; } printf("Setting interface ::: %s ::: to promisc\n\n", ifr.ifr_name); return 0; } int check_nic(void) { struct ifreq ifr; int skfd = socket(AF_INET, SOCK_DGRAM, 0); strcpy(ifr.ifr_name, ETH_NAME); if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) { close(skfd); return -1; } if(ifr.ifr_flags & IFF_RUNNING){ printf("link up\n"); close(skfd); return 0; // 网卡已插上网线 }else { printf("link down\n"); close(skfd); return -1; } } void savefile() { FILE *f; char file[64]; time_t t; if(byteCount>5){ sprintf(file,"tcp_%d.prn",time(&t)); //这里相对于当前工作路径 f=fopen(file,"wb"); if(f!=NULL) { fwrite(buf,byteCount,1,f); fclose(f); printf("save prn file:%s %d byte\n",file,byteCount); }else { printf("can not create file:%s \n",file); } }else{ printf("invial data: %u bytes\n",byteCount); } byteCount=0; } int main(int32_t argc, char **argv) { int32_t opt = 0; int sockfd; IP_HEADER *ip; char buf[1024*1000]; ssize_t n; int sport=-1; int dport=-1; //如optstring="ab:c::d::",命令行为getopt.exe -a -b host -ckeke -d haha while ((opt = getopt(argc, argv, "d:s:")) != -1) { switch (opt) { case 'd': dport=atoi(optarg); printf("dport=%s\n",optarg); break; case 's': sport=atoi(optarg); printf("sport=%s\n",optarg); break; default: break;; } } do_promisc(); /* capture ip datagram without ethernet header */ if ((sockfd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP)))== -1) { printf("socket error!\n"); return 1; } while (1) { n = recv(sockfd, buf, sizeof(buf), 0); if (n == -1) { printf("recv error!\n"); break; } else if (n<20) continue; //接收数据不包括数据链路帧头 ip = ( IP_HEADER *)(buf); revlen=ntohs(ip->total_len); //analyseIP(ip); size_t iplen = (ip->h_verlen&0x0f)*4; iphlen=iplen; TCP_HEADER *tcp = (TCP_HEADER *)(buf +iplen); if (ip->proto == IPPROTO_TCP) { TCP_HEADER *tcp = (TCP_HEADER *)(buf +iplen); if(22==ntohs(tcp->th_dport))continue; if((sport>0 && sport==ntohs(tcp->th_sport)) || (dport>0 && dport==ntohs(tcp->th_dport)) ) { printf("revlen len:%u total len:%u\n",n,ntohs(ip->total_len)); analyseTCP(ip,tcp); } } /* else if (ip->proto == IPPROTO_UDP) { UDP_HEADER *udp = (UDP_HEADER *)(buf + iplen); analyseUDP(udp); } /* else if (ip->proto == IPPROTO_ICMP) { ICMP_HEADER *icmp = (ICMP_HEADER *)(buf + iplen); analyseICMP(icmp); } else if (ip->proto == IPPROTO_IGMP) { printf("IGMP----\n"); } else { printf("other protocol!\n"); } */ //printf("."); } close(sockfd); return 0; } void analyseIP(IP_HEADER *ip) { unsigned char* p = (unsigned char*)&ip->sourceIP; unsigned char* p2; p2 = (unsigned char*)&ip->destIP; printf("IPP:\t: %u.%u.%u.%u -->\t: %u.%u.%u.%u\n",p[0],p[1],p[2],p[3], p2[0],p2[1],p2[2],p2[3]); } //https://wenku.baidu.com/view/04b0d780e53a580216fcfeaa.html void analyseTCP(IP_HEADER *ip,TCP_HEADER *tcp) { #define FIN 0x01 //FIN:标记数据是否发送完毕 #define SYN 0x02 //当SYN=1,ACK=0时,表示这是一个请求建立连接的报文段;当SYN=1,ACK=1时,表示对方同意建立连接 #define RST 0x04 //说明你与主机的连接出现了严重错误(如主机崩溃),必须释放连接,然后再重新建立连接 #define PSH 0x08 //PSH:告诉对方收到该报文段后是否应该立即把数据推送给上层 #define ACK 0x10 //TCP规定,连接建立后,ACK必须为1。 #define URG 0x20 int len; BYTE *pData; unsigned char* p = (unsigned char*)&ip->sourceIP; unsigned char* p2; short int flag; flag=tcp->th_flag; p2 = (unsigned char*)&ip->destIP; printf("tcp:\t %u.%u.%u.%u:%d -->%u.%u.%u.%u:%d flag=0x%x[%s %s %s %s %s %s] SEQ:%u ACKNUM:%u\n",p[0],p[1],p[2],p[3],ntohs(tcp->th_sport), p2[0],p2[1],p2[2],p2[3],ntohs(tcp->th_dport),flag,(flag & ACK)?"ACK":"",(flag & SYN)?"SYN":"",(flag & FIN)?"FIN":"",(flag & PSH)?"PSH":"",(flag & RST)?"RST":"",(flag & URG)?"URG":"",ntohl(tcp->th_seq),ntohl(tcp->th_ack)); if((flag & SYN) && !(flag & ACK)) { printf("request connect\n"); } if( (flag & ACK)) { // printf("ack\n"); } if(flag & FIN ) { printf("FINISH & disconnected\n"); savefile(); } if(flag & RST ) { printf("connection reset\n"); byteCount=0; } if(flag & PSH ) { } len =(tcp->th_lenres)>>4; len *=4; tcphlen=len; pData = ( (BYTE *)tcp )+len; if(revlen-iphlen-tcphlen>0) { int datalen=revlen-iphlen-tcphlen; printf("====get data byte:%d-%d-%d=%d \n", revlen,iphlen,tcphlen,datalen); if(byteCount+datalen<=sizeof(buf)) { memcpy(buf+byteCount,pData,datalen); byteCount+=datalen; } } } void analyseUDP(UDP_HEADER *udp) { printf("UDP Source port: %u--> Dest port: %u\n", ntohs(udp->uh_sport),ntohs(udp->uh_dport)); } void analyseICMP(ICMP_HEADER *icmp) { printf("ICMP -----\n"); printf("type: %u\n", icmp->icmp_type); printf("sub code: %u\n", icmp->icmp_code); }
上一篇:VCB计算String数组元素个数
下一篇:USB声卡描述符