ICMP->linux c 时间戳请求功能实现

报文格式:

ICMP->linux c 时间戳请求功能实现_第1张图片

代码实现:

#include 
#include 
#include 
#include 
#include  //struct icmp
#include  //sockaddr_in
#include 
#include 
#include 
#include 
#include 
#include 

//校验和计算
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;
}

 

你可能感兴趣的:(linux,c)