?? ping.c
字號(hào):
#include <stdio.h>#include <signal.h>#include <arpa/inet.h>#include <sys/types.h>#include <sys/socket.h>#include <unistd.h>#include <netinet/in.h>#include <netinet/ip.h>#include <netinet/ip_icmp.h>#include <netdb.h>#include <setjmp.h>#include <errno.h>#define PACKET_SIZE 4096#define MAX_WAIT_TIME 5#define MAX_NO_PACKETS 2 //發(fā)包的個(gè)數(shù)#define ICMP_ECHO 8#define ICMP_ECHOREPLY 0char sendpacket[PACKET_SIZE];char recvpacket[PACKET_SIZE];int sockfd,datalen = 56;int nsend = 0,nreceived = 0;struct sockaddr_in dest_addr;pid_t pid;struct sockaddr_in from;struct timeval tvrecv;void statistics(int signo);unsigned short cal_chksum(unsigned short *addr,int len);int pack(int pack_no);void send_packet(void);void recv_packet(void);int unpack(char *buf,int len);void statistics(int signo){ if (MAX_NO_PACKETS != nreceived) printf ("not found\n"); else printf ("found\n"); close(sockfd); exit(1);}unsigned short cal_chksum(unsigned short *addr,int len) //校驗(yàn)和算法{ int nleft = len; int sum = 0; unsigned short *w = addr; unsigned short answer = 0; while(nleft>1) //把ICMP報(bào)頭二進(jìn)制數(shù)據(jù)以2字節(jié)為單位累加起來 { sum += *w++; nleft-=2; } //若ICMP報(bào)頭為奇數(shù)個(gè)字節(jié),會(huì)剩下最后一字節(jié)。 if( nleft == 1) //把最后一個(gè)字節(jié)視為一個(gè)2字節(jié)數(shù)據(jù)的高字節(jié),這個(gè)2字節(jié)數(shù)據(jù)的低字節(jié)為0,繼續(xù)累加 { *(unsigned char *)(&answer) = *(unsigned char *)w; sum += answer; } sum = (sum>>16)+(sum&0xffff); sum += (sum>>16); answer = ~sum; return answer;}int pack(int pack_no) //設(shè)置ICMP報(bào)頭{ int i,packsize; struct icmp *icmp; struct timeval *tval; icmp=(struct icmp*)sendpacket; icmp->icmp_type = ICMP_ECHO; icmp->icmp_code = 0; icmp->icmp_cksum = 0; icmp->icmp_seq=pack_no; icmp->icmp_id = pid; packsize=8+datalen; tval= (struct timeval *)icmp->icmp_data; gettimeofday(tval,NULL); //記錄發(fā)送時(shí)間 icmp->icmp_cksum=cal_chksum( (unsigned short *)icmp,packsize); //校驗(yàn)算法 return packsize;}void send_packet() //發(fā)送三個(gè)ICMP報(bào)文{ int packetsize; while( nsend < MAX_NO_PACKETS) { nsend++; packetsize = pack(nsend); //設(shè)置ICMP報(bào)頭 if( sendto(sockfd,sendpacket,packetsize,0, (struct sockaddr *)&dest_addr,sizeof(dest_addr) )<0 ) { perror("sendto error"); continue; } sleep(1); //每隔一秒發(fā)送一個(gè)ICMP報(bào)文 }}void recv_packet() //接收所有ICMP報(bào)文{ int n,fromlen; extern int errno; signal(SIGALRM,statistics); fromlen = sizeof(from); while( nreceived < nsend) { alarm(MAX_WAIT_TIME); if( (n = recvfrom(sockfd,recvpacket,sizeof(recvpacket),0,(struct sockaddr *)&from,&fromlen)) < 0 ) { if(errno == EINTR) continue; } gettimeofday(&tvrecv,NULL); //記錄接收時(shí)間 if(unpack(recvpacket,n) == -1) { continue; } nreceived++; }}int unpack(char *buf,int len) //剝?nèi)CMP報(bào)頭{ int i,iphdrlen; struct ip *ip; struct icmp *icmp; struct timeval *tvsend; ip = (struct ip *)buf; iphdrlen = ip->ip_hl<<2; //求ip報(bào)頭長(zhǎng)度,即ip報(bào)頭的長(zhǎng)度標(biāo)志乘4 icmp = (struct icmp *)(buf + iphdrlen); //越過ip報(bào)頭,指向ICMP報(bào)頭 len -= iphdrlen; //ICMP報(bào)頭及ICMP數(shù)據(jù)報(bào)的總長(zhǎng)度 if(len < 8) //小于ICMP報(bào)頭長(zhǎng)度則不合理 return -1; //確保所接收的是我所發(fā)的的ICMP的回應(yīng) if( (icmp->icmp_type != ICMP_ECHOREPLY) || (icmp->icmp_id != pid) ) return -1;}int main(int argc,char *argv[]){ struct hostent *host; struct protoent *protocol; unsigned long inaddr = 0l; int waittime = MAX_WAIT_TIME; int size = 50*1024; if(argc < 2) { printf("usage:%s hostname/IP address\n",argv[0]); exit(1); } if( (protocol = getprotobyname("icmp") ) == NULL) { perror("getprotobyname"); exit(1); } if( (sockfd = socket(AF_INET,SOCK_RAW,protocol->p_proto)) < 0 ) //生成使用ICMP的原始套接字,這種套接字只有root才能生成 { perror("socket error"); exit(1); } setuid(getuid()); //回收root權(quán)限,設(shè)置當(dāng)前用戶權(quán)限 setsockopt(sockfd,SOL_SOCKET,SO_RCVBUF,&size,sizeof(size) ); bzero(&dest_addr,sizeof(dest_addr)); dest_addr.sin_family = AF_INET; if((inaddr = inet_addr(argv[1])) == INADDR_NONE) //判斷是主機(jī)名還是ip地址 { if((host = gethostbyname(argv[1]) ) == NULL) //是主機(jī)名 { printf("gethostbyname error\n"); exit(1); } memcpy( (char *)&dest_addr.sin_addr,host->h_addr,host->h_length); } else //是ip地址 dest_addr.sin_addr.s_addr = inaddr; pid = getpid(); //獲取main的進(jìn)程id,用于設(shè)置ICMP的標(biāo)志符 send_packet(); //發(fā)送所有ICMP報(bào)文 recv_packet(); //接收所有ICMP報(bào)文 statistics(SIGALRM); //進(jìn)行統(tǒng)計(jì) return 0;}
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -