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

我有兴趣检索入站数据包发送到的目标地址。 例如在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)=%s\n", inet_ntoa(pktinfo.ipi_addr)); 

已跳过步骤以节省许多行

这里的关键是recvmsg很容易使用。 类似的function是像recvfrom一样为Windows XP实现,但Windows似乎没有实现recvmsgfunction。

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

有没有一种方法可以从Windows XP中的数据包中获取头部目标地址?


我知道,使用XP是不好的,老,不幸的是,我们正在尝试修复遗留产品的错误,所以在这个时候,我们无法简单升级。

Solutions Collecting From Web of "在Windows XP中从数据包中检索标头目标地址的函数"

窗户似乎并没有实现recvmsg函数。

其实,它确实(当然,还是等价的):

WSARecvMsg函数

类似的功能已经被修改,像WSArevcMsg,但只包括在Windows Vista和以上。

你不能总是信任MSDN文档。 当微软正式放弃对Windows版本(如XP)的支持时,它倾向于从MSDN中删除对该版本的引用,包括对API函数的“最低支持…”要求(这使得很多程序员很烦恼)。 关键点是支持的 。 Microsoft不支持较旧的Windows版本。

WSARecvMsg()最初是在XP中引入的,在2014年已经被EOL化了,许多参考文献都是从MSDN文档中得到的(这里是2013年WSARecvMsg()文档声明为XP而不是Vista是“最低支持客户端” )。


WSARecvFrom()文档中所述:

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

WSAID_WSARECVMSG被定义为:

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

又名{F689D7C8-6F1F-436B-8A53-E54FE351C322}

例如:

 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_LEN() once for each option you enable // on the socket that can return data in WSARecvMsg()... int size = WSA_CMSG_LEN(WSA_CMSG_LEN(sizeof(buffer))); 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 = NULL; do { msghdr = WSA_CMSG_NXTHDR(&msg, msghdr); if (!msghdr) break; 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... } } while (true); } free(addrbuf); free(controlbuf);