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

2023-12-02

我有兴趣检索入站数据包发送到的目标地址。例如在 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很容易使用。 Windows XP 也实现了类似的功能,例如recvfrom但Windows似乎没有实现recvmsg功能。

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

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


我知道使用 XP 很糟糕而且很旧,不幸的是我们正在尝试修复旧产品上的错误,所以目前我们无法简单地升级。


windows好像没有实现recvmsg功能。

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

WSARecvMsg 函数

类似的功能已被修改,如 WSRevcMsg,但这些功能仅包含在 Windows Vista 及更高版本中。

您不能总是相信 MSDN 文档。当 Microsoft 正式放弃对某个 Windows 版本(如 XP)的支持时,它往往会从 MSDN 中删除对该版本的引用,包括“最低支持……”API 函数的要求(这让许多程序员烦恼)。关键点是支持的。微软没有support较旧的 Windows 版本。

WSARecvMsg()首次在 XP 中引入,于 2014 年停产,MSDN 文档中删除了许多对它的引用(这里是proof从 2013 年起,当WSARecvMsg()文档指出 XP 而不是 Vista 是“最低限度支持的 client").


如中所述WSARecvFrom()文档:

Note函数指针为WSARecvMsg函数必须在运行时通过调用来获得WSAIoctl()函数与SIO_GET_EXTENSION_FUNCTION_POINTER指定操作码。输入缓冲区传递给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}}

aka {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_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);
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

随机推荐

  • 如何使用ajax保存到数据库

    我有一个工作正常的代码 但数据无法保存到数据库 我想通过 Ajax 将 cost currency rate profit rate 和 pprice 插入数据库 这是javascript和update php的代码 我尝试修改代码以保存在
  • 如何使用批处理文件分割字符串?

    如何使用批处理脚本分割字符串 设置java path C Program Files Java jdk1 6 0 31 上面是我的字符串 我只想要 java path 中的 C Program Files 如何得到它 您可以按字符位置拆分字
  • 使用 Log4j 的每个用户都有不同的日志

    我有一个 Web 应用程序 我想为每个用户使用不同的日志 这样我就可以获得用户在系统上执行的操作的 历史记录 这是我到目前为止所拥有的 import java io File import java io IOException impor
  • 将单词列表转换为数组[关闭]

    Closed 这个问题需要细节或清晰度 目前不接受答案 我试图查看是否有任何脚本可以将单词列表转换为数组 但我似乎找不到 有人知道我在哪里可以找到一个吗 Input Dog Cat Hamster 转换为 Dog Cat Hamster 不
  • cURL 错误 58:SSL:无法加载证书“...”及其私钥:Mac 上的 OSStatus -25299

    该代码在 Ubuntu vagrant box 上运行良好 但在本地 MacO 上它不会加载证书 说 cURL error 58 SSL Can t load the certificate and its private key OSSt
  • 如何像矩阵乘法一样将行向量添加到列向量

    我有一个 nx1 向量和一个 1xn 向量 我想以一种特殊的方式添加它们 例如以有效的方式 矢量化 矩阵乘法 Example A 1 2 3 B 4 5 6 A odd add B 1 4 1 5 1 6 2 4 2 5 2 6 3 4 3
  • 命名空间::变量的多重定义,甚至使用 ifndef

    我知道我在这里一定做错了什么 rank h ifndef RANK H define RANK H namespace mmi int chunk void rank int my rank endif rank cpp include r
  • 如何检测 Python 是否作为 64 位应用程序运行? [复制]

    这个问题在这里已经有答案了 我正在对 Windows 注册表进行一些工作 根据 Python 运行为 32 位还是 64 位 某些键值会有所不同 如何检测 Python 是作为 64 位应用程序运行还是作为 32 位应用程序运行 我对检测
  • 在悬停时添加边框时如何防止移动? (透明边框不是解决方案)[重复]

    这个问题在这里已经有答案了 我想在悬停时为 div 添加边框 但是添加边框时 div 稍微有点拉屎 这是一个众所周知的问题 常见的解决方案是添加透明边框 例如 但是 我的 div 中有一张包含一些文本的图像 我希望该图像占据 div 的全宽
  • 正则表达式西班牙语和阿拉伯语单词

    如何编写匹配所有有效的西班牙语和阿拉伯语单词的正则表达式 用我知道的英语来说 它是a zA z 在希伯来语中是 俄语 我使用 JavaScript 范围a zA Z因为英语单词的简单和天真令人难以接受 它省略了所有带有重音符号的字母以及在借
  • 过渡到 vim。存在缩进问题

    我正在从手术中恢复 因此 我正在过渡到 VIM 作为起点 我选择使用 vim sensible 插件作为我的配置的基础 此外 我还安装了 vim rails 和 vim ruby 插件 这些都是通过 Pathogen 加载的 无论出于何种原
  • 序列化 JFrame 并通过网络发送

    我想做的是通过套接字发送 JFrame 问题是在我发送表格并按下按钮查看它之后 我得到以下异常 package ds3 import java io IOException import java io ObjectInputStream
  • Android - 在 UI Fragment 中保留对象

    在我的项目中 我最初使用的是这个方案 活动A UI gt 片段B 非 UI gt 适配器 AsyncTask B保留与setRetainInstance true 并更新A UI A实例化B with getFragmentManager
  • 在 .NET 中按换行符拆分字符串

    我需要在 NET 中将字符串拆分为换行符 我知道拆分字符串的唯一方法是使用Split方法 然而 这不允许我 轻松地 在换行符上拆分 那么最好的方法是什么 要分割字符串 您需要使用采用字符串数组的重载 string lines theText
  • jQuery Mobile 站点中所有页面通用的弹出窗口

    我正在尝试使用 jQuery Mobile 制作一个网站 它由 HTML 文件中的许多页面组成 有些只有一页 有些有多个页面 使用它们的多页功能 该网站将有一些通知弹出窗口 它们在所有页面上看起来都一样 我正在使用他们的弹出窗口新的弹出功能
  • Python-按前两个单词对行进行分组

    我想按文件中的前两个单词对文件进行分组 然后重新排列和打印 我想做 lines file readlines i 0 for line in lines word1 line split 0 word2 line split 1 if wo
  • c - 嵌入式系统中Long Long到char的转换函数

    我正在使用嵌入式系统 我需要实现一种将 long long 转换为 char 的方法 问题是我不能在这个系统中使用 sprintf 来做到这一点 所以我正在寻找替代方法 函数来实现这一点 欢迎提出 LongLongToChar 函数的实现建
  • FindBugs 希望 readObject(...) 为私有序列化,为什么?

    我正在某些代码上运行 findbugs 它说 readObject 方法必须是私有的才能调用序列化 反序列化 为什么 如果公开的话会有什么问题呢 About readObject writeObject 作为私有的 情况如下 如果你的类 B
  • 图像比较 - 旋转、对齐和缩放

    我有以下需求 有一些表格 即空白表格 例如调查中使用的表格 那些没有填充信息的 从现在开始我将称之为图像模板 除了图像模板之外 我还有很多图像 这些图像本质上都是充满信息的图像模板 例如 有一项调查 有两个空白需要填写 这些是图像模板 许多
  • 在 Windows XP 中从数据包中检索标头目标地址的函数

    我有兴趣检索入站数据包发送到的目标地址 例如在 Linux 上你可以使用recvmsg res recvmsg socket msghdr 0 get cmsg CMSG FIRSTHDR msghdr struct in pktinfo