我想把TCP/IP详解(卷1)第六章 ICMP 中的 icmpaddmask程序移植到windows下,
但是用recvfrom接受不到数据,请指教?
下面是我写的程序:/*File:icmpaddrmask.cpp
 *Author:ybluo
 *Date:2003-10-27
 *Description:
 *Issue an ICMP address mask request and print the reply for microsoft windows
*/#include <winsock2.h>
#include <iostream>
using namespace std;
#pragma comment(lib,"ws2_32.lib")//-------------------------
typedef struct _iphdr 
{
    unsigned int   h_len:4;        // Length of the header
    unsigned int   version:4;      // Version of IP
    unsigned char  tos;            // Type of service
    unsigned short total_len;      // Total length of the packet
    unsigned short ident;          // Unique identifier
    unsigned short frag_and_flags; // Flags
    unsigned char  ttl;            // Time to live
    unsigned char  proto;          // Protocol (TCP, UDP etc)
    unsigned short checksum;       // IP checksum    unsigned int   sourceIP;
    unsigned int   destIP;
} IP;typedef struct _icmp
{
unsigned char icmp_type;
unsigned char icmp_code;
unsigned short icmp_chsum;
unsigned short icmp_id;
unsigned short icmp_seq;
unsigned long  icmp_mask;
}ICMP;const unsigned char ICMP_MASKREQ=17; //mask request 
const unsigned char ICMP_MASKREPLY=18;//mask reply;
const int ICMP_MASKLEN=12; /* 12 = 8 bytes of header, 4 bytes of mask */
const int MAX_PACKET=1024;      // Max ICMP packet size//-------------------------
SOCKET             sockRaw = INVALID_SOCKET;
char recvbuf[MAX_PACKET];
struct sockaddr_in dest;
void Help();
void ShowError(char *);
void SendIcmp();
unsigned short checksum(unsigned short *buffer, int size);
void DecodePack(char *recvbuf, int ilen,sockaddr_in *from);//--------------------------
void main(int argc,char **argv)
{
if( argc !=2 )
{
Help();
return;
} char *szHost=argv[1];
WSADATA            wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
    {
        cout<<"WSAStartup() failed: "<<GetLastError();
        return;
    }

// raw socket
sockRaw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if(sockRaw == INVALID_SOCKET) 
    {
        ShowError("socket");
    }
struct hostent    *hp = NULL;
dest.sin_family=AF_INET; //
    // Resolve the host's name if necessary
    //
    dest.sin_family = AF_INET;
    if ((dest.sin_addr.s_addr = inet_addr(szHost)) == INADDR_NONE)
    {
        if ((hp = gethostbyname(szHost)) != NULL)
        {
            memcpy(&(dest.sin_addr), hp->h_addr, hp->h_length);
            dest.sin_family = hp->h_addrtype;
            cout<<"dest.sin_addr =  "<< inet_ntoa(dest.sin_addr)<<endl;
        }
        else
        {
            ShowError("gethostbyname");            
        }
    }

//Send the ICMP address mask request.
SendIcmp(); //receive
while(1)
{
struct sockaddr_in from;
int  fromlen;
int  iret;
fromlen=sizeof(from);
cout<<"before recvfrom() function "<<endl;
iret=recvfrom(sockRaw,recvbuf,MAX_PACKET,0,(sockaddr *)&from, &fromlen);
cout<<"after recvfrom() function "<<endl;
if( iret<0 )
{
ShowError("recvfrom");
continue;
}
cout<<"recv = "<<iret<<endl;
DecodePack(recvbuf,iret,&from);
Sleep(1000); }
WSACleanup();

}
//---------------------------
void Help()
{
cout<<"icmpaddrmask for Microsoft Windows"<<endl;
cout<<"\tby ybluo 2003-10-27"<<endl;
cout<<"Usage:"<<endl;
cout<<"\ticmpaddrmask <Host>"<<endl;
}
//---------------------------
void ShowError(char *szErrorFunction)
{
cout<<szErrorFunction
<<"() failed: "
<<WSAGetLastError()<<endl;
exit(0);
}
//---------------------------
void SendIcmp()
{
ICMP icmp;
memset(&icmp,0,sizeof(ICMP));
icmp.icmp_type=ICMP_MASKREQ;
icmp.icmp_code=0; icmp.icmp_id=GetCurrentProcessId();/* seq and id must be reflected */
icmp.icmp_seq=12345;
    /* compute ICMP checksum here */
icmp.icmp_chsum=checksum((unsigned short *)&icmp,ICMP_MASKLEN);

int iret=sendto(sockRaw,
(char *)&icmp,
ICMP_MASKLEN,
0,
(sockaddr *)&dest,
sizeof(sockaddr));
   if (iret < 0 || iret != ICMP_MASKLEN) 
   {
if (iret < 0)
{
ShowError("sendto");
}
cout<<"wrote "<<ICMP_MASKLEN<<" ret="<<iret<<endl;
}
   cout<<"wrote = "<<iret<<endl;}
//---------------------------
// 
// Function: checksum
//
// Description:
//    This function calculates the 16-bit one's complement sum
//    of the supplied buffer (ICMP) header
//
unsigned short checksum(unsigned short *buffer, int size) 
{
    unsigned long cksum=0;    while (size > 1) 
    {
        cksum += *buffer++;
        size -= sizeof(unsigned short);
    }
    if (size) 
    {
        cksum += *(unsigned char*)buffer;
    }
    cksum = (cksum >> 16) + (cksum & 0xffff);
    cksum += (cksum >>16);
    return (unsigned short)(~cksum);
}
//--------------------------------------------
void DecodePack(char *recvbuf, int ilen,sockaddr_in *from)
{
IP *ip=NULL;
ICMP *icmp=NULL;
ip=(IP *)recvbuf;
int hlen=ip->h_len * 4; icmp=(ICMP *)(recvbuf+hlen);
if( icmp->icmp_type== ICMP_MASKREPLY)
{
if( ilen-hlen !=ICMP_MASKLEN )
{
cout<<"ilen-hlen = "<<ilen-hlen <<" expected = 12"<<endl;
}
if ( icmp->icmp_seq != 12345)
{
cout<<"received sequence ="<< icmp->icmp_seq<<endl;
}
if( icmp->icmp_id !=GetCurrentProcessId() )
{
cout<< "received id = "<<icmp->icmp_id<<endl;
} cout<<" received mask = "<<hex
<<ntohl(icmp->icmp_mask)
<<inet_ntoa(*(struct in_addr *) &from->sin_addr.s_addr)
<<endl;
}
}
//-------------------------------------------

解决方案 »

  1.   

    如果你使在私网内,你还必须考虑代理服务器的问题,那样你要看一下RFC1928(SOCKS5代理协议)
      

  2.   

    问题在于该程序发往自己的主机,一样没有回应。我觉得问题不是出在程序本身。
    检查了几遍,也没发现有什么错,而且它能接收我发出的ping包。把SDK下的ping程序中改icmp_hdr->i_type = ICMP_MASKREQ一样接收不到数据TCP/IP详解(卷1)53页:
    RFC规定,除非系统是地址掩码的授权代理,否则它不能发送地址掩码应答(为了成为授权代理,它必须进行特殊配置,以发送这些应答。参见附录E)。但是,正如我们从本例中看到的那样,大多数主机在收到请求时都发送一个应答,甚至有一些主机还发送差错的应答。这可能会是解释,进一步关注