RAW ICMP套接字:recvfrom()不接收任何数据

以下代码是一个旨在发送ICMP回应请求并接收回复的程序。

/* 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()调用没有收到任何数据,并返回TIMEOUTERROR(10060),尽pipeping 被回复(Wireshark捕获请求和回复正在发送)。 sendto()工作,但recvfrom()行为怪异,我不知道是什么问题。

我觉得有趣的是recvfrom()只有在网关告诉我主机不可访问时才会接收数据。 如果主机可以访问,并且已经响应了ping,则不会发生。

问题在于struct ICMP

ICMP的typecode应该是unsigned char

ICMP头应该是8字节,而struct ICMP大小是10字节。

所以应该改成:

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

事实证明,整个过程都是我的防火墙阻止了回应。 我的代码中唯一的错误是我的ICMP结构(由cshu提到)的大小。

谢谢各位的帮助。