from:http://blog.chinaunix.net/u2/62281/showart_1096746.html
|
|
#include "stdio.h" #include "stdlib.h" #include "string.h" #include "unistd.h" #include "sys/types.h" #include "sys/socket.h" #include "netinet/in.h" #include "netinet/ip.h" #include "netinet/ip_icmp.h" #include "netdb.h" #include "errno.h" #include "arpa/inet.h" #include "signal.h" #include "sys/time.h" extern int errno; int sockfd; struct sockaddr_in addr; //peer addr char straddr[128]; //peer addr ip(char*) char sendbuf[2048]; char recvbuf[2048]; int sendnum; int recvnum; int datalen = 30; unsigned short my_cksum(unsigned short *data, int len) { int result = 0; int i; for(i=0; i < len/2; i++) { result += *data; data++; } while(result >> 16)result = (result&0xffff) + (result>>16); return ~result; } void tv_sub(struct timeval* recvtime, const struct timeval* sendtime) { int sec = recvtime->tv_sec - sendtime->tv_sec; int usec = recvtime->tv_usec - sendtime->tv_usec; if(usec >= 0) { recvtime->tv_sec = sec; recvtime->tv_usec = usec; } else { recvtime->tv_sec = sec-1; recvtime->tv_usec = -usec; } } void send_icmp() { struct icmp* icmp = (struct icmp*)sendbuf; icmp->icmp_type = ICMP_ECHO; icmp->icmp_code = 0; icmp->icmp_cksum = 0; icmp->icmp_id = getpid(); //needn't use htons() call, because peer networking kernel didn't handle this data and won't make different meanings(bigdian litteldian) icmp->icmp_seq = ++sendnum; //needn't use hotns() call too. gettimeofday((struct timeval*)icmp->icmp_data, NULL); int len = 8 + datalen; icmp->icmp_cksum = my_cksum((unsigned short*)icmp, len); int retval = sendto(sockfd, sendbuf, len, 0, (struct sockaddr*)&addr, sizeof(addr)); if(retval == -1){ perror("sendto()"); exit(-1); } else { // printf("send icmp request to %s(%d) bytes/n", straddr, len); } } void recv_icmp() { struct timeval *sendtime; struct timeval recvtime; for(;;) { int n = recvfrom(sockfd, recvbuf, sizeof(recvbuf), 0, 0, 0); if(n == -1) { if(errno == EINTR)continue; else { perror("recvfrom()"); exit(-1); } } else { gettimeofday(&recvtime, NULL); struct ip *ip = (struct ip*)recvbuf; if(ip->ip_src.s_addr != addr.sin_addr.s_addr) { // printf("ip_src is not : %s/n", straddr); continue; } struct icmp *icmp = (struct icmp*)(recvbuf + ((ip->ip_hl)<<2)); if(icmp->icmp_id != getpid()) { // printf("icmp_id is not :%d/n", getpid()); continue; } recvnum++; sendtime = (struct timeval*)icmp->icmp_data; tv_sub(&recvtime, sendtime); printf("imcp echo from %s(%dbytes)/tttl=%d/tseq=%d/ttime=%d.%06d s/n", straddr, n, ip->ip_ttl, icmp->icmp_seq, (int)recvtime.tv_sec, (int)recvtime.tv_usec); } } } void catch_sigalrm(int signum) { send_icmp(); alarm(1); } void catch_sigint(int signum) { printf("/nPing statics:send %d packets, recv %d packets, %d%% lost.../n", sendnum, recvnum, (int)((float)(sendnum-recvnum)/sendnum)*100); exit(0); } int main(int argc, char **argv) { if(argc != 2) { printf("please use format: ping hostname/n"); exit(-1); } sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); if(sockfd == -1) { perror("socket()"); return -1; } /* int sendbufsize = 180; socklen_t sendbufsizelen = sizeof(sendbufsize); if(setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &sendbufsize, sendbufsizelen) == -1)perror("setsockopt()"); int recvbufsize; socklen_t recvbufsizelen; if(getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &recvbufsize, &recvbufsizelen) == -1)perror("getsockopt()"); */ memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; int retval = inet_pton(AF_INET, argv[1], &addr.sin_addr); if(retval == -1 || retval == 0) { struct hostent* host = gethostbyname(argv[1]); if(host == NULL) { fprintf(stderr, "gethostbyname(%s):%s/n", argv[1], strerror(errno)); exit(-1); } /* if(host->h_name != NULL)printf("hostent.h_name:%s/n", host->h_name); if(host->h_aliases != NULL && *(host->h_aliases) != NULL)printf("hostent.h_aliases:%s/n", *(host->h_aliases)); printf("hostent.h_addrtype:%d/n", host->h_addrtype); printf("hostent.h_length:%d/n", host->h_length); */ if(host->h_addr_list != NULL && *(host->h_addr_list) != NULL) { strncpy((char*)&addr.sin_addr, *(host->h_addr_list), 4); inet_ntop(AF_INET, *(host->h_addr_list), straddr, sizeof(straddr)); } printf("Ping address:%s(%s)/n/n", host->h_name, straddr); } else { strcpy(straddr, argv[1]); printf("Ping address:%s(%s)/n/n", straddr, straddr); } struct sigaction sa1; memset(&sa1, 0, sizeof(sa1)); sa1.sa_handler = catch_sigalrm; sigemptyset(&sa1.sa_mask); sa1.sa_flags = 0; if(sigaction(SIGALRM, &sa1, NULL) == -1)perror("sigaction()"); struct sigaction sa2; memset(&sa2, 0, sizeof(sa2)); sa2.sa_handler = catch_sigint; sigemptyset(&sa2.sa_mask); sa2.sa_flags = 0; if(sigaction(SIGINT, &sa2, NULL) == -1)perror("sigaction()"); alarm(1); recv_icmp(); return 0; }