#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <netdb.h>
#include <netinet/in.h>
int sockfd,sentp,recvp,seq;
struct sockaddr_in dst;
typedef struct Icmphead
{
u_char type;
u_char code;
u_short checksum;
u_short id;
u_short seq;
}icmphead;
u_short chksum(u_short*,int);
void ping()
{
char sendpacket[100];
int icmpsize=8;
icmphead*icmp;
icmp=(icmphead*)sendpacket;
icmp->type=8;
icmp->code=0;
icmp->checksum=0;
icmp->id=icmp->seq=seq;
icmp->checksum=chksum((u_short*)icmp,icmpsize);
int len=sizeof(dst);
if((sendto(sockfd,sendpacket,icmpsize,0,(struct sockaddr*)&dst,len))<0)
{
printf("sendto error\n");
exit(0);
}
sentp++;
alarm(1);
}
void result()
{
if(sentp)
{
printf("sent packet %d recvpacket %d\n",sentp,recvp);
}
else
{
printf("no packet send successful\n");
}
exit(0);
}
u_short chksum(u_short*icmpdata,int icmpsize)
{
u_short sum=0;
while(icmpsize>1)
{
sum=sum+*(icmpdata++);
icmpsize-=2;
}
if(icmpsize)
{
sum=sum+*icmpdata;
}
while(sum>>16)
sum=(sum>>16)+(sum&0xffff);
return ~sum;
}
int main()
{
char hostname[100];
printf("input hostname:");scanf("%s",hostname);
struct hostent*h;
dst.sin_family=AF_INET;
seq=sentp=recvp=0;
if(h=gethostbyname(hostname))
{
bcopy(h->h_addr,&dst.sin_addr,h->h_length);
strcpy(hostname,(char*)inet_ntoa(dst.sin_addr));
printf("hostname ip is %s\n",hostname);
}
else
{
printf("wrong hostname\n");
exit(0);
}
if((sockfd=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP))<0)
{
printf("create socket fail\n");
exit(0);
}
signal(SIGINT,result);
signal(SIGALRM,ping);
alarm(1);
for(;;)
{
char buf[100];
int len=sizeof(dst);
int recvsize=recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr*)&dst,&len);
if(recvsize<=0)
{
printf("recvfrom faild\n");
}
else
{
char info[100];
icmphead*icmp;
char *p;
p=(char*)buf;
icmp=(icmphead*)(p+20);
if(icmp->type!=0){printf("not the reply type,type is %d\n",icmp->type);continue;}
if(icmp->seq!=seq||icmp->id!=seq){printf("not the right echo,now seq is %d, but icmp->seq is %d\n",seq,icmp->seq);continue;}
sprintf(info,"icmp_seq:%d",icmp->seq);
printf("reply from %s:%s\n",hostname,info);
recvp++;
seq++;
}
}
return 0;
}
对应上面的ping有几个地方要注意的是:
1,如果没有把发过去的包的校验码算准确,那么将得不到回应(尼吗在这里卡了好久好久,最后用wireshark才看出来校验码错了,根本没有回应)
2,在套接字设置时候,注意protol字段选择IPPROTO_ICMP,这样就只接受icmp和发送icmp了。
3,学会alarm和signal(SIGALRM,xxx)的用法。
4,注意到接受到的包带有ip包头,计算时候要跳过。
暂时就这么多了。。。。。