簡易ping程序

當我把icmp的檢驗和設置成0時,ping百度是可以有echo返回。但是ping其他主機是沒有返回響應。

手動添加檢驗和後正常。

原因:可能是baidu服務器並沒有檢測校驗和就返回一個echo,這樣可以減少服務器的負擔。

而其他一些站點都會校驗。


注意點:IPV4的icmp,在原始套接字收到後,收到的是包含IP頭在內的完整數據報

IPV6的icmp,則是去除所有ip頭和擴展頭部的淨載荷。

#include "unp.h"
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <assert.h>
char 	sendbuf[MAXLINE], recvbuf[MAXLINE];
int 		datalen = 56,	 nseq = 0;
int 		sockfd;
struct sockaddr_in	dst, src;
socklen_t 		dstlen, srclen;


void callfunc(int signo) ;
void send_icmp( ) ;
void  recv_icmp();
unsigned short icmp_cksum(unsigned short *addr, int len);

int	main( int argc, char **argv) {
	if(argc  != 2) {
		err_quit("args");
	}
	char buf[100];
	struct addrinfo *addr, hints, *next;
	struct sockaddr *servaddr;
	struct sockaddr_in *temp;
	bzero(&hints, sizeof(struct addrinfo));
	hints.ai_family = AF_UNSPEC;
	getaddrinfo(argv[1], NULL, &hints, &addr);
	for(; addr != NULL; addr = addr->ai_next) {
		temp = (struct sockaddr_in *)(addr->ai_addr);
		dst = *temp;
		dstlen = srclen = sizeof(struct sockaddr);
		 printf("the dst ip is %s\n", inet_ntop(AF_INET, &(temp->sin_addr), buf, sizeof(buf)));
		break;
	}
	sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
	setuid(getuid());
	signal(SIGALRM, callfunc);
	callfunc(SIGALRM);
	for(;;) {
		recv_icmp();
	}
}
void callfunc(int signo) {
	send_icmp();
	alarm(1);
}
void send_icmp( ) {
	struct icmp		*icmp;
	/*		struct timeval		*timeval;*/
	icmp = (struct icmp *)sendbuf;
	icmp->icmp_type = 8;
	icmp->icmp_code = 0;
	icmp->icmp_cksum = 0;
	icmp->icmp_id = 88;
	icmp->icmp_seq = nseq ++;
	gettimeofday((struct timeval *)(icmp->icmp_data), NULL);
	icmp->icmp_cksum = icmp_cksum((u_short *)icmp, 56+8);
	sendto(sockfd, sendbuf, 56+8, 0, (SA *)&dst, dstlen);
	return;
}
void cal_time(struct timeval *time1, struct timeval *time2) { /*大 小*/
	time1->tv_usec = ((time1->tv_usec)/1000) + ((time1->tv_sec)*1000);
	time2->tv_usec = ((time2->tv_usec)/1000) + ((time2->tv_sec)*1000);
	time1->tv_usec = (time1->tv_usec) -(time2->tv_usec);
}
void  recv_icmp() {
	struct ip		*ip;
	struct icmp	*icmp;
	struct timeval *rtime;
	int			n,hl;
	char 	buf[100];
	again:
	if(( n = recvfrom(sockfd, recvbuf, sizeof(recvbuf), 0, (SA *)&src, &srclen) ) < 0) {
		if(errno == EINTR)
			goto again;
		else
			exit(0);
	}
	//printf("return a echo\n");

	ip = (struct ip *)recvbuf;
	hl = ip->ip_hl;
	hl = hl<< 2;
	icmp = (struct icmp *)(recvbuf + hl);
	if(icmp == NULL)
		printf("icmp is null\n");
	assert(icmp);
	assert(recvbuf);
	rtime = (struct timeval *)malloc(sizeof(struct timeval));
	if((icmp->icmp_type == 0) && (icmp->icmp_code == 0) &&(icmp->icmp_id == 88)){
		gettimeofday(rtime, NULL);
		cal_time(rtime, (struct timeval *)(icmp->icmp_data));
		printf("The seq %d ,", icmp->icmp_seq);
		printf("Ping the ip is %s :", inet_ntop(AF_INET,&( (&src)->sin_addr), buf, sizeof(buf)));
		printf("ttl  %d  ms\n", rtime->tv_usec);
		
	}
}

unsigned short icmp_cksum(unsigned short *addr, int len)
{
	int				nleft = len;
	int				sum = 0;
	unsigned short	*w = addr;
	unsigned short	answer = 0;
	while (nleft > 1)  {
		sum += *w++;
		nleft -= 2;
	}
	if (nleft == 1) {
		*(unsigned char *)(&answer) = *(unsigned char *)w ;
		sum += answer;
	}
	sum = (sum >> 16) + (sum & 0xffff);	
	sum += (sum >> 16);			
	answer = ~sum;				
	return(answer);
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章