|
|
#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;
for(int 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, recvtime.tv_sec, 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_RCVBUF, &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;
}