2017-02-13 18 views
2

次のコードは、ICMPエコー要求を送信し、応答を受け取るように設計されたプログラムです。RAW ICMPソケット:recvfrom()はデータを受信しません

/* 
    Forgive my lack of error handling :) 
*/ 
SOCKET ASOCKET = INVALID_SOCKET; 
struct sockaddr saddr; 
struct sockaddr_in *to = (struct sockaddr_in *) &saddr; 
struct sockaddr_in from; 
int fromsize = sizeof(from); 
std::string ip = "[arbitrary ip address]"; 

struct ICMP { 
    USHORT type; 
    USHORT code; 
    USHORT cksum; 
    USHORT id; 
    USHORT seq; 
}*_ICMP; 

char sendBuffer[sizeof(struct ICMP)]; 
char recvBuffer[256]; 

WSADATA wsaData; 
WSAStartup(MAKEWORD(2, 2), &wsaData); 

memset(&saddr, NULL, sizeof(saddr)); 
ASOCKET = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 

// Configure timeout 
DWORD timeoutmilsec = 3000; 
setsockopt(ASOCKET, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeoutmilsec, sizeof(timeoutmilsec)); 

to->sin_family = AF_INET; 
inet_pton(AF_INET, ip.c_str(), &(to->sin_addr)); 

_ICMP = new ICMP(); 

_ICMP->type = 8; 
_ICMP->code = 0; 
_ICMP->cksum = 0; 
_ICMP->id = rand(); 
_ICMP->seq++; 
// I have omitted my declaration of checksum() for simplicity 
_ICMP->cksum = checksum((u_short *)_ICMP, sizeof(struct ICMP)); 

memcpy(sendBuffer, _ICMP, sizeof(struct ICMP)); 

if (sendto(ASOCKET, sendBuffer, sizeof(sendBuffer), NULL, (sockaddr *)&saddr, sizeof(saddr)) == SOCKET_ERROR) 
{ 
    printf("sendto() failed with error: %u\n", WSAGetLastError()); 
    return false; 
} 

if (recvfrom(ASOCKET, recvBuffer, sizeof(recvBuffer), NULL, (sockaddr *)&from, &fromsize) == SOCKET_ERROR) 
{ 
    if (WSAGetLastError() == TIMEOUTERROR) 
    { 
     printf("Timed out\n\n"); 
     return false; 
    } 

    printf("recvfrom() failed with error: %u\n", WSAGetLastError()); 
    return false; 
} 

私の問題は私のrecvfrom()呼び出しが任意のデータを受信して​​いないことであるとping は(Wiresharkの要求をキャプチャして送信される返信)に回答されたという事実にもかかわらずTIMEOUTERROR(10060)を返します。 sendto()が動作しますが、recvfrom()は奇妙に動作し、問題の内容を把握できません。

興味深いのは、recvfrom()は、ゲートウェイがホストに到達できないと伝えたときにのみデータを受信することです。ホストが到達可能で、pingに応答していればそれはできません。

+1

Windowsのファイアウォールがパケットをブロックしている可能性がありますか? –

答えて

1

それが応答をブロックし、私のファイアウォールた全体の時間が判明。私のコードの唯一のエラーは、私のICMP構造体のサイズ(cshuで言及された)でした。

ありがとうございました。

3

問題はstruct ICMPにあります。

typeおよびcodeは、unsigned charである必要があります。

ICMPのヘッダーは8バイトですが、struct ICMPのサイズは10バイトです。

だから、それは次のように変更します。

struct ICMP { 
    unsigned char type; 
    unsigned char code; 
    USHORT cksum; 
    USHORT id; 
    USHORT seq; 
}*_ICMP; 
+1

正解[RFC 792](https://tools.ietf.org/html/rfc792)を参照してください。 – EJP