报文格式:
代码实现:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/ip_icmp.h> //struct icmp
#include <netinet/in.h> //sockaddr_in
#include <netinet/ip.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/time.h>
#include <string.h>
//校验和计算
unsigned short calc_cksum(char *buff,int len)
{
int blen = len;
unsigned short *mid = (unsigned short*)buff;
unsigned short te = 0;
unsigned int sum = 0;
while(blen > 1)
{
sum += *mid++;
blen -= 2;
}
if(blen == 1)
{
te = *(unsigned char*)mid;
te = (te << 8) & 0xff;
sum += te;
}
sum = (sum >> 16) + (sum&0xffff);
sum += sum >>16;
return (unsigned short)(~sum);
}
static void time_packet(char *buff,int len,int id,int seq)
{
time_t *ti;
struct icmp *icmp = (struct icmp*)buff;
struct timeval val;
icmp->icmp_type = 13; //Timestamp Request
icmp->icmp_code = 0;
icmp->icmp_cksum = 0; //first set zero
icmp->icmp_id = id & 0xffff;
icmp->icmp_seq = seq;
gettimeofday(&val,NULL);
//24*60*60 = 86400 自午夜开始计算的毫秒数
icmp->icmp_otime = htonl((val.tv_sec % 86400)*1000 + val.tv_usec / 1000);
icmp->icmp_rtime = 0;
icmp->icmp_ttime = 0;
//计算校验和
icmp->icmp_cksum = calc_cksum(buff,len);
return;
}
void parse_packet(char *buff,int len)
{
struct icmp *icmp;
struct iphdr *iphead = (struct iphdr *)buff;
struct in_addr addr;
addr.s_addr = iphead->saddr;
printf("comefrom ip=%s ",inet_ntoa(addr));
//跳过ip头
icmp = (struct icmp *)(buff+sizeof(struct iphdr));
//看传输回的包校验和是否正确
if(calc_cksum((char *)icmp,len-sizeof(sizeof(struct iphdr))) > 1)
{
printf("receiver error\n");
return;
}
printf("type=%d seq=%d id=%d pid=%d otime=%d rtime=%d ttime=%d\n",icmp->icmp_type,icmp->icmp_seq,icmp->icmp_id,(getpid()&0xffff),ntohl(icmp->icmp_otime),ntohl(icmp->icmp_rtime),ntohl(icmp->icmp_ttime));
}
int main(int argc,char *argv[])
{
int skfd;
struct sockaddr_in addr={0};
struct sockaddr_in saddr={0};
char buff[64]={0};
char recvbuff[512]={0};
int ret;
int addrlen = 0;
int count = 5;
int i = 1;
skfd = socket(PF_INET,SOCK_RAW,IPPROTO_ICMP);
if(skfd < 0)
{
printf("socket error\n");
return -1;
}
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("192.168.21.244");
//每一秒发送一次 共发送count次
while(count > 0)
{
//序列号seq 从1 开始传输 buff的大小为64
memset(buff,0,sizeof(buff));
time_packet(buff,64,getpid(),i);
i++;
count --;
//将数据发送出去
ret = sendto(skfd,buff,64,0,(struct sockaddr *)&addr,sizeof(addr));
if(ret <= 0)
{
printf("send error\n");
goto out;
}
else
printf("send success ret=%d\n",ret);
//接收echo replay
memset(recvbuff,0,sizeof(recvbuff));
memset(&saddr,0,sizeof(saddr));
addrlen = sizeof(saddr);
ret = recvfrom(skfd,recvbuff,sizeof(recvbuff),0,(struct sockaddr *)&saddr,&addrlen);
if(ret <= 0)
{
printf("recv error\n");
continue;
}
parse_packet(recvbuff,ret);
sleep(2);
}
out:
close(skfd);
return 0;
}