码迷,mamicode.com
首页 > 其他好文 > 详细

ICMP 获取时间戳 代码

时间:2017-04-29 19:52:36      阅读:325      评论:0      收藏:0      [点我收藏+]

标签:字符   强制   函数返回   style   bool   赋值   signed   sizeof   packet   

技术分享
#include<iostream>
#include<cstdio>
#include<cstring>
#include<winsock2.h>
using namespace std;
#define  TIME_STAMP_REQUEST 13
struct iphdr {
    unsigned char  ip_hdr_len : 4; //包头长度
    unsigned char  ip_version : 4; //版本
    unsigned char  ip_tos;
    unsigned short ip_length;  //总长度
    unsigned short ip_identify;//标识
    unsigned short ip_offset;//片偏移
    unsigned char  ip_ttl;
    unsigned char  ip_protocol;
    unsigned short ip_cksum;
    struct in_addr ip_src; //源地址
    struct in_addr ip_dst; //目的地址
};
struct icmphdr {
    unsigned char  icmp_type; //8位类型
    unsigned char  icmp_code; //8位代码
    unsigned short icmp_cksum; //16位的校验和
    unsigned short icmp_identify;
    unsigned short icmp_seq;
    unsigned int   icmp_otime;
    unsigned int   icmp_rtime; //接收时间
    unsigned int   icmp_ttime; //应答时间
};
unsigned short checksum(int count,unsigned short* addr) {
    long sum = 0;

    while(count > 1) {
        sum   +=*addr++;
        count -= sizeof(unsigned short);
    }

    if(count > 0) {
        sum  +=*(unsigned char*)addr;
    }

    while(sum >> 16) {
        sum = (sum & 0xFFFF) + (sum >> 16);
    }

    return (unsigned short)(~sum);
}
bool timestamp_request(char * argv) {
    WSADATA wsaData;
    WSAStartup(MAKEWORD(2, 2), &wsaData);
    SOCKET soc = socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);
    if(soc == -1) {
        printf("create raw socket failed!\n");
        return false;
    }
    struct sockaddr_in  addrsrv;
    addrsrv.sin_family      = AF_INET;
    addrsrv.sin_port = htons(0);
    addrsrv.sin_addr.s_addr = inet_addr("202.112.10.36"); //预设地址
    struct hostent* phostent  = gethostbyname(argv);
    if (phostent) {
        addrsrv.sin_addr.s_addr = *(u_long *)phostent->h_addr_list[0];;
    }
    printf("sending timestamp request to host [%s]\n",inet_ntoa(addrsrv.sin_addr));
    icmphdr ihdr       = {0};
    ihdr.icmp_type     = TIME_STAMP_REQUEST;
    ihdr.icmp_identify = (unsigned short)GetCurrentProcessId();
    ihdr.icmp_cksum    = checksum(sizeof(icmphdr),(unsigned short *)&ihdr);
    if(sendto(soc,(char *)&ihdr,sizeof(ihdr),0,(sockaddr *)&addrsrv,sizeof(addrsrv)) == -1) {
        printf("send icmp packet failed!\n");
        return false;
    }
    struct sockaddr_in addrcli;
    int  nlength       = sizeof(addrcli);
    char recv[MAXBYTE] = {0};
    struct timeval timeout;
    timeout.tv_sec  = 3000;
    timeout.tv_usec = 0;
    setsockopt(soc, SOL_SOCKET,SO_RCVTIMEO, (char*)&timeout,sizeof(timeout));
    if(recvfrom(soc,recv,MAXBYTE,0,(sockaddr *)&addrcli,&nlength) == -1) {
        printf("recv ip packet failed!\n");
        return false;
    }

    iphdr* piphdr = (iphdr *)recv;
    if(checksum(piphdr->ip_hdr_len << 2,(unsigned short *)piphdr) != 0) {
        printf("invalid ip packet!\n");
        return false;
    }
    icmphdr* pichdr = (icmphdr *)(piphdr + 1);
    if(checksum(sizeof(icmphdr),(unsigned short *)pichdr) != 0) {
        printf("invalid icmp packet!\n");
        return false;
    }
    printf("recv time:[%u] transmit time:[%u]\n",ntohl(pichdr->icmp_rtime),ntohl(pichdr->icmp_ttime));
    return true;
}

int main(int argc,char * argv[]) {
    if(argc < 2) {
        return 0;
    }
    timestamp_request(argv[1]);
}
View Code

 函数及变量的解释:

WSADATA : 存储由WSAStartup函数返回的数据。

int WSAStartup( WORD wVersionRequested, LPWSADATA lpWSAData);

    启动异步套接字,加载运行库

  wVersionRequest : 高阶字段表示小版本号,低位字段表示主版本号

  lpWSAData:  指向WSADATA的指针。

int socket( int af, int type, int protocol);

  根据指定协议族、数据类型、协议来分配一个套接口

  af : 地址描述,目前仅支持AF_INET

  type :指定socket类型,SOCK_STREAM是面向连接的socket,SOCK_DGRAME是无连接的socket,SOCK_RAW是原始套接字,可以接收到本机网卡上的数据帧。

  protocol : 指定协议。IPPROTO_TCP , IPPROTO_UDP,IPPROTO_ICMP等等

sockaddr_in

  作为bind、connect、recvfrom、sendto函数中指明地址的信息。

  内部成员:

  short sin_family  指明协议族

  u_short sin_port  端口号,必须是网络字节流

  sin_addr 类型为in_addr,真正存储IP的是s_addr,s_addr其实就是一个 u_int 类型的数据,其中存储的IP地址为网络字节流形式。

in_addr

  in_addr 这个结构体中只有一个u_int的变量,用来存储网络字节顺序的IP地址

  既然只有一个变量,还定义个毛结构体,出了好多麻烦事

htons(u_short x)

  是将整型变量从主机字节顺序转变成网络字节顺序

ntohs(u_short x)

  将网络字节序的u_short x转变为主机字节序

ntohl(u_long x)

  将网络字节序的u_long x转变为主机字节序

in_addr_t   inet_addr(const char* strptr);

  in_addr_t = u_int

  如果字符串有效,把字符串转变为网络字节序的 IPV4地址,返回类型为u_int

gethostbyname(char * name)

  通过主机名获得主机的信息

hostent *p

  gethostbyname的返回类型

  char ** h_addr_list : 主机网络地址的指针,网络字节顺序,以字符串的形式描述一个IP地址,如果对sockaddr_in中存储IP地址的变量进行赋值,需要进行强制转换。

char *inet_ntoa(in_addr in)

  将一个in_addr 的网络字节流转换为点分十进制的IP地址

  注意 sockaddr_in.sin_addr的类型就是 in_addr,可以作为参数直接传进去

int sendto(SOCKET s,char *buf,int blen,int flags,sockaddr *to,int tlen);

  flags 用来改变sendto发送的形式

  适用于发送无连接的UDP数据包

 

ICMP 获取时间戳 代码

标签:字符   强制   函数返回   style   bool   赋值   signed   sizeof   packet   

原文地址:http://www.cnblogs.com/jifahu/p/6785768.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!