当我把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);
}