RAW ICMP 套接字:recvfrom() 未接收到任何数据
RAW ICMP socket: recvfrom() not recieving any data
以下代码是用于发送 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()
调用没有收到任何数据和 returns TIMEOUTERROR (10060) 尽管 ping 已经 得到回复到(Wireshark 捕获正在发送的请求和回复)。 sendto()
有效,但 recvfrom()
行为异常,我无法弄清楚问题所在。
我觉得有趣的是 recvfrom()
只有当网关告诉我主机不可达时才会接收数据;如果主机可访问并且已响应 ping,则不会。
问题出在struct ICMP
.
ICMP的type
和code
应该是unsigned char
.
ICMP的Header应该是8字节,但是struct ICMP
的大小是10字节。
所以应该改为:
struct ICMP {
unsigned char type;
unsigned char code;
USHORT cksum;
USHORT id;
USHORT seq;
}*_ICMP;
原来是我的防火墙一直在阻止响应。我的代码中唯一的错误是我的 ICMP 结构的大小(由 cshu 提到)。
感谢大家的帮助。
以下代码是用于发送 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()
调用没有收到任何数据和 returns TIMEOUTERROR (10060) 尽管 ping 已经 得到回复到(Wireshark 捕获正在发送的请求和回复)。 sendto()
有效,但 recvfrom()
行为异常,我无法弄清楚问题所在。
我觉得有趣的是 recvfrom()
只有当网关告诉我主机不可达时才会接收数据;如果主机可访问并且已响应 ping,则不会。
问题出在struct ICMP
.
type
和code
应该是unsigned char
.
Header应该是8字节,但是struct ICMP
的大小是10字节。
所以应该改为:
struct ICMP {
unsigned char type;
unsigned char code;
USHORT cksum;
USHORT id;
USHORT seq;
}*_ICMP;
原来是我的防火墙一直在阻止响应。我的代码中唯一的错误是我的 ICMP 结构的大小(由 cshu 提到)。
感谢大家的帮助。