Hi,
我们知道,发送个ICMP Echo Request报文,如果得到Destination Unreachable回复ICMP报文, 这个报文会包含IP报文头的前8个字节,以便我们APP识别。
我现在用
winSock = WSASocket(AF_INET,SOCK_RAW,IPPROTO_ICMP,NULL,0,0);
建立发送ICMP Echo Request报文。
问题是,我如何能取得保留此IP报文的前8个字节,以备得到类似Destination Unreachable ICMP响应报文时比对识别?
谢谢指点!

解决方案 »

  1.   

    here is an ICMP message sample#include "stdafx.h"
    #include "windows.h"
    #include "Winsock2.h"
    #pragma comment(lib,"ws2_32.lib")
    #pragma pack(1)
    //
    // ICMP timestamp request and reply 
    //
    typedef struct _ihdr {
      BYTE i_type;
      BYTE i_code; /* type sub code */
      USHORT i_cksum;
      USHORT i_id;
      USHORT i_seq;
      /* This is not the std header, but we reserve space for time */
      ULONG originate_timestamp;
      ULONG receive_timestamp;
      ULONG transmit_timestamp;
    }IcmpHeader;
    void printIcmpHeader(IcmpHeader& timestampreply)
    {
    printf("IcmpHeader type: %d i_code %d i_cksum %d i_id %d i_seq %d \n",timestampreply.i_type, timestampreply.i_code,
    timestampreply.i_cksum, timestampreply.i_id, timestampreply.i_seq);
    printf(" originate_timestamp :%d receive_timestamp %d transmit_timestamp %d \n", timestampreply.originate_timestamp,
    timestampreply.receive_timestamp, timestampreply.transmit_timestamp);
    printf(" pid: %d  \n",GetCurrentProcessId());}
    USHORT g_Seq = 0;
    USHORT checksum(USHORT *buffer, int size) 
    {
    unsigned long cksum=0;
    while( size >1 ) 
    {
    cksum += *buffer ++;
    size -= sizeof ( USHORT );
    }
    if(size ) 
    cksum += *(UCHAR*)buffer;
    cksum = (cksum >> 16) + (cksum & 0xffff);
    cksum += (cksum >>16);
    return (USHORT)(~cksum);
    }
    int _tmain(int argc, _TCHAR* argv[])
    {
    WSADATA wsaData;
    if ( WSAStartup ( MAKEWORD ( 2 , 0 ) , &wsaData ) != 0 )
    return FALSE;
    int iResult , iTimeOut;
    SOCKET m_socketPing = WSASocket (AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0,0);
    if (m_socketPing == INVALID_SOCKET)
    return FALSE;
    iTimeOut = 10000; 
    //Set timeout value for data receive
    iResult = setsockopt(
    m_socketPing,
    SOL_SOCKET,
    SO_RCVTIMEO,
    (char*)&iTimeOut,
    sizeof(iTimeOut));
    if( iResult == SOCKET_ERROR ) 
    return FALSE;
    iTimeOut = 10000; 
    //Set timeout value for data send
    iResult = setsockopt(
    m_socketPing,
    SOL_SOCKET,
    SO_SNDTIMEO,
    (char*)&iTimeOut,
    sizeof(iTimeOut));
    if(iResult == SOCKET_ERROR) 
    return FALSE;
    struct sockaddr_in m_adr_Dest,m_adr_From;
    m_adr_Dest.sin_family = AF_INET;
    m_adr_Dest.sin_addr.s_addr = inet_addr( LPCTSTR ( "127.0.0.3" ) );//216.239.33.99
    IcmpHeader icmph;
    int try_count=0;
    while(try_count<10)
    {
    try_count++;
    int iDataSize = sizeof(IcmpHeader);
    IcmpHeader *icmp_hdr=&icmph;
    ZeroMemory(icmp_hdr,iDataSize);
    icmp_hdr->i_type = 13;//timestamp request
    icmp_hdr->i_code = 0;
    icmp_hdr->i_id = (USHORT)GetCurrentProcessId();
    icmp_hdr->i_cksum = 0;
    icmp_hdr->i_seq = g_Seq++;
    icmp_hdr->originate_timestamp = (GetTickCount());
    icmp_hdr->i_cksum = checksum( ( USHORT* )icmp_hdr, iDataSize );
    printf("sequence %d , originate time %d\n", icmp_hdr->i_seq, icmp_hdr->originate_timestamp);
    int iDataWrite = sendto(
    m_socketPing,
    (char*)icmp_hdr,
    iDataSize,
    0,
    (struct sockaddr*)&m_adr_Dest,
    sizeof(struct sockaddr));
    if (iDataWrite == SOCKET_ERROR)
    {
    if (WSAGetLastError() == WSAETIMEDOUT) 
    {
    continue;
    }
    //terminate the ping if unable to send request.
    return 1;
    }
    //receive the reply
    //(note it.: we sent only the ICMP header and data buffer)
    //IP-Header will be added in before the ICMP header.
    //We could receive more bytes(sizeof IP-Header) than the bytes sent.
    IcmpHeader timestampreply;
    int iFromLen;
    iFromLen = sizeof ( struct sockaddr );
    memset( &m_adr_From ,0 , sizeof( m_adr_From ) );
    //IcmpHeader* pReceiveBuffer = &timestampreply;
    int nReceiveBufferSize = sizeof(IcmpHeader)+1576;
    char* pReceiveBuffer=new char[nReceiveBufferSize];
    int iDataGet = recvfrom(
    m_socketPing,
    (char*)pReceiveBuffer,
    nReceiveBufferSize,
    0,
    (struct sockaddr*)&m_adr_From,
    &iFromLen);

    if (iDataGet == SOCKET_ERROR)
    {
    DWORD iError = WSAGetLastError();
    //if timeout occured.
    if (iError == WSAETIMEDOUT) 
    {
    continue;
    }
    //terminate the ping if unable to receive reply.
    return 1;
    }
    printf("\niDataGet = %d \n",iDataGet);
    memcpy(&timestampreply,pReceiveBuffer+20,sizeof(IcmpHeader));//skip ip header(20 bytes)
    printIcmpHeader(timestampreply);
    int ts=GetTickCount()-timestampreply.originate_timestamp;
    printf(" sequence id %d use time %d\n", timestampreply.i_seq, ts);
    }
    return 0;
    }
      

  2.   

    谢谢masterz兄。
    你的Ping程式很精炼;但是你的程式中并没有判断返回的ICMP报文是否是你的程式的响应报文,也没有判断返回ICMP报文是Echo Reply, 还是Destination Unreachable.
    所以,你没有回答我的问题呵!
      

  3.   

    也许我只能生成一个RAW IP报文,而非RAW ICMP报文发送,才能记住并比较识别返回的报文。得,结帖。