I am interested in retrieving the destination address that an inbound packet is sent to. For example on Linux you can utilize 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));
Steps have been skipped to save many many lines
The key here is that recvmsg
is easy to use. Similar functions are implemented for Windows XP like recvfrom
but Windows does not seem to implement the recvmsg
function.
Similarly named functions exist, like the WSARevcMsg
function, but according to the linked documentation it is only included in Windows Vista and above.
Is there a way I can get the header destination address from a packet in Windows XP?
I know that using XP is bad and old, unfortunately we are attempting to fix a bug on a legacy product, so at this time we are unable to simply upgrade.
windows does not seem to implement the recvmsg function.
Actually, it does (well, an equivalent, anyway):
Similar functions have been revamped like the WSArevcMsg but these are only included in windows vista and above.
You can't always trust MSDN documentation. When Microsoft officially drops support for a Windows version (like XP), it tends to remove references to that version from MSDN, including "Minimum supported ..." requirements of API functions (which annoys many programmers). The key point is supported . Microsoft does not support older Windows versions.
WSARecvMsg()
was first introduced in XP, which was EOL'ed in 2014 and many references to it were stricken from MSDN documentation (here is proof from 2013 when the WSARecvMsg()
documentation stated XP and not Vista was the "Minimum supported client" ).
As stated in the WSARecvFrom()
documentation:
Note The function pointer for the
WSARecvMsg
function must be obtained at run time by making a call to theWSAIoctl()
function with theSIO_GET_EXTENSION_FUNCTION_POINTER
opcode specified. The input buffer passed to theWSAIoctl
function must containWSAID_WSARECVMSG
, a globally unique identifier (GUID) whose value identifies theWSARecvMsg
extension function. On success, the output returned by theWSAIoctl
function contains a pointer to theWSARecvMsg
function. TheWSAID_WSARECVMSG
GUID is defined in the Mswsock.h header file.
WSAID_WSARECVMSG
is defined as:
#define WSAID_WSARECVMSG \
{0xf689d7c8,0x6f1f,0x436b,{0x8a,0x53,0xe5,0x4f,0xe3,0x51,0xc3,0x22}}
aka {F689D7C8-6F1F-436B-8A53-E54FE351C322}
in text format.
For example:
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...
}
Then, to use it:
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 = 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);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.