函数从windows XP中的数据包中检索标头目标地址

Function to retrieve the header destination address from a packet in windows XP

本文关键字:目标 地址 检索 windows XP 函数 数据包      更新时间:2023-10-16

我有兴趣检索入站数据包发送到的目标地址。例如,在Linux上,您可以使用recvmsg:

res = recvmsg(socket, &msghdr, 0);
get_cmsg = CMSG_FIRSTHDR(msghdr);   
struct in_pktinfo *get_pktinfo = (struct in_pktinfo *)CMSG_DATA(get_cmsg);
printf(" - Header destination address (get_pktinfo.ipi_addr)=%sn", inet_ntoa(pktinfo.ipi_addr));

跳过步骤以保存许多行

这里的关键是recvmsg易于使用。类似于recvfrom的功能在Windows XP中实现,但Windows似乎没有实现recvmsg功能。

存在类似命名的函数,如WSARevcMsg函数,但根据链接文档,它仅包含在Windows Vista及更高版本中。

有没有办法在Windows XP中从数据包中获取标头目标地址


我知道使用XP既糟糕又陈旧,不幸的是,我们正试图修复遗留产品上的一个错误,因此目前我们无法简单升级

windows似乎没有实现recvmsg函数。

事实上,它确实如此(好吧,无论如何都是等价的):

WSARecvMsg函数

类似的功能也进行了改进,如WSArevcMsg,但这些功能仅包含在windowsvista及更高版本中。

您不能总是信任MSDN文档。当微软正式放弃对Windows版本(如XP)的支持时,它倾向于从MSDN中删除对该版本的引用,包括"支持的最小值">API函数的需求(这让许多程序员感到恼火)。关键是支持。Microsoft不支持旧的Windows版本。

WSARecvMsg()最初是在XP中引入的,XP于2014年被EOL'ed,许多对它的引用都从MSDN文档中删除了(这是2013年的证据,当时WSARecvMsg()文档指出XP而不是Vista是"支持的最小客户端")。


WSARecvFrom()文件所述:

注意必须在运行时通过使用指定的SIO_GET_EXTENSION_FUNCTION_POINTER操作码调用WSAIoctl()函数来获得WSARecvMsg函数的函数指针。传递给WSAIoctl函数的输入缓冲区必须包含WSAID_WSARECVMSG,这是一个全局唯一标识符(GUID),其值标识WSARecvMsg扩展函数。成功后,WSAIoctl函数返回的输出包含指向WSARecvMsg函数的指针。WSAID_WSARECVMSGGUID在Mswsock.h头文件中定义。

WSAID_WSARECVMSG定义为:

#define WSAID_WSARECVMSG 
{0xf689d7c8,0x6f1f,0x436b,{0x8a,0x53,0xe5,0x4f,0xe3,0x51,0xc3,0x22}}

又称为文本格式的CCD_ 19。

例如:

SOCKET sckt = ...;
LPFN_WSARECVMSG lpWSARecvMsg = NULL;
GUID g = WSAID_WSARECVMSG;
DWORD dwBytesReturned = 0;
if (WSAIoctl(sckt, SIO_GET_EXTENSION_FUNCTION_POINTER, &g, sizeof(g), &lpWSARecvMsg, sizeof(lpWSARecvMsg), &dwBytesReturned, NULL, NULL) != 0)
{
// WSARecvMsg is not available...
}

然后,使用它:

BYTE buffer[...];
DWORD dwBytesRecv;
WSABUF msgbuf;
memset(&msgbuf, 0, sizeof(msgbuf));
msgbuf.len = sizeof(buffer);
msgbuf.buf = (char *) buffer;
// call WSA_CMSG_SPACE() once for each option you enable
// on the socket that can return data in WSARecvMsg()...
int size = 0;
if (... IP_PKTINFO is enabled ...)
size += WSA_CMSG_SPACE(sizeof(struct in_pktinfo));
if (... IPV6_PKTINFO is enabled ...)
size += WSA_CMSG_SPACE(sizeof(struct in6_pktinfo));
// other packet options as needed...
BYTE *controlbuf = (BYTE *) malloc(size);
SOCKADDR_STORAGE *addrbuf = (SOCKADDR_STORAGE *) malloc(sizeof(SOCKADDR_STORAGE));
WSAMSG msg;
memset(&msg, 0, sizeof(msg));
msg.name = (struct sockaddr *) addrbuf;
msg.namelen = sizeof(SOCKADDR_STORAGE);
msg.lpBuffers = &msgbuf;
msg.dwBufferCount = 1;
msg.Control.len = size;
msg.Control.buf = (char *) controlbuf;
if (lpWSARecvMsg(sckt, &msg, &dwBytesRecv, NULL, NULL) == 0)
{
// addrbuf contains the sender's IP and port...
switch (addrbuf->ss_family)
{
case AF_INET:
{
struct sockaddr_in *addr = (struct sockaddr_in*) addrbuf;
// use addr as needed...
break;
}
case AF_INET6:
{
struct sockaddr_in6 *addr = (struct sockaddr_in6*) addrbuf;
// use addr as needed...
break;
}
}
WSACMSGHDR *msghdr = WSA_CMSG_FIRSTHDR(&msg);
while (msghdr)
{
switch (msghdr->cmsg_type)
{
case IP_PKTINFO: // also IPV6_PKTINF
{
// must call setsockopt(sckt, IPPROTO_IP, IP_PKTINFO, TRUE) beforehand to receive this for IPv4
// must call setsockopt(sckt, IPPROTO_IPV6, IPV6_PKTINFO, TRUE) beforehand to receive this for IPv6
switch (addrbuf->ss_family)
{
case AF_INET:
{
struct in_pktinfo *pktinfo = (struct in_pktinfo *) WSA_CMSG_DATA(msghdr);
// use pktinfo as needed...
break;
}
case AF_INET6:
{
struct in6_pktinfo *pktinfo = (struct in6_pktinfo *) WSA_CMSG_DATA(msghdr);
// use pktinfo as needed...
break;
}
}
break;
}
// other packet options as needed...
}
msghdr = WSA_CMSG_NXTHDR(&msg, msghdr);
}
}
free(addrbuf);
free(controlbuf);