以 wireshark 的方式接收跨子网的 UDP 广播数据包
Receive UDP broadcast packets across subnetworks the way wireshark can do it
我在 PC 上有一个应用程序应该从本地网络上的设备获取一些 UDP 广播消息。
设备定期向其子网发送 UDP 广播消息,应用程序应该能够接收这些广播。当 PC 和设备在同一个子网中时,接收这些消息没有问题。
但是,当我将设备和 PC 放在不同的子网中时,我无法再在 PC 应用程序中接收设备的广播,但我可以在 wireshark 中看到它们。
情景一
所以如果我有:
- IP 为
10.0.100.100
的 PC,子网掩码为 255.255.0.0
- IP
10.0.254.83
的 设备 A 子网掩码 255.255.255.0
这个概念验证 PC 应用程序:
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <stdio.h>
#include <assert.h>
#pragma comment(lib, "Ws2_32.lib")
int main()
{
WSADATA wsaData;
int iResult;
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed: %d\n", iResult);
return 1;
}
sockaddr_in si_me, si_other;
int s;
assert((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) != -1);
int port = 32002;
BOOL broadcast = TRUE;
setsockopt(s, SOL_SOCKET, SO_BROADCAST,
(char*)&broadcast, sizeof(broadcast));
memset(&si_me, 0, sizeof(si_me));
si_me.sin_family = AF_INET;
si_me.sin_port = htons(port);
si_me.sin_addr.s_addr = INADDR_ANY;
assert(bind(s, (sockaddr *)&si_me, sizeof(sockaddr)) != -1);
while (1)
{
char buf[10000];
memset(buf, 0, 10000);
int slen = sizeof(sockaddr);
recvfrom(s, buf, sizeof(buf)-1, 0, (sockaddr *)&si_other, &slen);
char *ip = inet_ntoa(si_other.sin_addr);
printf("%s: %s\n", ip, buf);
}
}
那我收不到设备的广播消息
场景 2
但是,如果我有一个 设备 B IP 10.0.255.222
子网掩码 255.255.0.0
我可以接收消息,即使 PC 仍然在另一个子网中。
场景 3
如果我将 PC 移动到 10.0.254.100
并使用子网掩码 255.255.255.0
然后我可以与 设备 A 通信,但是我看不到消息来自设备 B 10.0.255.222
.
更让我困惑的是,在这两种情况下,Wireshark 都可以捕获数据包。
- 为什么我的应用程序不能看到来自 设备 A 的数据包,为什么 wireshark 可以(在第一种情况下)?我可以像 wireshark 一样做些什么才能看到这些数据包?
- 场景 2 和 3 背后的解释是什么?
由于在场景2中,设备B显然在另一个子网中,但通信丢失只发生在场景3
- 我应该阅读哪些内容才能更好地理解这些问题?
PS:我不认为问题出在UDP的不可靠性上。
PPS: 我确实尝试禁用"Capture packets in promiscuous mode",结果是一样的,我可以在Wireshark
中看到来自设备A的数据包
Wireshark 将网络适配器置于 "promiscuous mode" 中,报告它在网络上看到的所有数据包。通常它只报告发往主机的数据包。在您的情况下,听起来网络掩码的差异意味着设备将使用不同的广播地址,并且数据包被丢弃。
Wireshark 在 Windows 上安装了一个特殊的网络驱动程序以访问所有流量 https://wiki.wireshark.org/WinPcap
每当你 运行 wireshark .it 自动将你的设备(接口)放入
"promiscuous mode" .so 它将捕获空中的所有数据包,
无需打扰子网掩码。
而您的 PC 将捕获在
同一个子网。
一件事是 - Wireshark 使用混杂模式 - 因此它可以读取交换机端口上的任何内容。这可能包括您自己的广播、一些其他广播,甚至一些不适合您的 uni/multicasts - 只要数据包到达该交换机端口。你的程序不是这种情况。您的程序正在尝试仅接收 网络广播地址 的数据报。现在下面的解释会有所帮助。
我认为您混淆了网络地址和广播域。这是你的情况
场景一。
PC - 10.0.100.100
网络掩码 255.255.0.0
所以广播地址是 10.0.255.255
,(通常任何在网络掩码中是 0
的东西 - 如果它被设置为所有 1
s 成为一个广播地址。)
所以任何发送到这个广播地址的东西都会被你的应用接收。
设备 A 10.0.254.83
网络掩码 255.255.255.0
。所以广播地址是10.0.254.255
。请注意,它不同于 PC 的广播地址,因此您无法接收它们。
所以不要被外表相同的 网络地址所迷惑。
场景 2
设备 B - 10.0.255.222
网络掩码 255.255.0.0
。所以广播地址是10.0.255.255
。这与上面场景 1 中您的 PC 地址相同,因此可以接收数据报(无需处于混杂模式)。 (255.222
部分可能看起来像一个不同的网络,但这不是因为网络掩码是 16 字节 255.255.0.0
。
场景 3
PC : 10.0.254.100 netmask 255.255.255.0 因此网络的广播地址是 10.0.254.255 - 这与场景 1 中设备 A 的广播地址 (10.0.254.255
) 相同,但与广播不同场景 2 中设备 B (10.0.255.255
) 的地址以及预期结果。
在您的场景中 - 设备 A 的网络是设备 B 的子网,PC 的网络和广播仅限于子网。当您将 PC 移入子网时,您会收到子网的广播(Senario 3)。
编辑:
解释 - 为什么你可以在 wireshark 中看到子网广播而为什么在你的应用程序中看不到 - 你在 wireshark 中看到的就是 'received by your network card'。由于所有广播都有 ff:ff:ff:ff:ff
的目的地 mac,您的卡将接收它,但您的 OS 堆栈将丢弃它们,因为网络级地址不是网络级广播.即使没有混杂模式,也会收到第 2 层广播。
希望对您有所帮助。
我在 PC 上有一个应用程序应该从本地网络上的设备获取一些 UDP 广播消息。
设备定期向其子网发送 UDP 广播消息,应用程序应该能够接收这些广播。当 PC 和设备在同一个子网中时,接收这些消息没有问题。
但是,当我将设备和 PC 放在不同的子网中时,我无法再在 PC 应用程序中接收设备的广播,但我可以在 wireshark 中看到它们。
情景一
所以如果我有:
- IP 为
10.0.100.100
的 PC,子网掩码为255.255.0.0
- IP
10.0.254.83
的 设备 A 子网掩码255.255.255.0
这个概念验证 PC 应用程序:
#ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include <windows.h> #include <winsock2.h> #include <ws2tcpip.h> #include <iphlpapi.h> #include <stdio.h> #include <assert.h> #pragma comment(lib, "Ws2_32.lib") int main() { WSADATA wsaData; int iResult; iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); if (iResult != 0) { printf("WSAStartup failed: %d\n", iResult); return 1; } sockaddr_in si_me, si_other; int s; assert((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) != -1); int port = 32002; BOOL broadcast = TRUE; setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char*)&broadcast, sizeof(broadcast)); memset(&si_me, 0, sizeof(si_me)); si_me.sin_family = AF_INET; si_me.sin_port = htons(port); si_me.sin_addr.s_addr = INADDR_ANY; assert(bind(s, (sockaddr *)&si_me, sizeof(sockaddr)) != -1); while (1) { char buf[10000]; memset(buf, 0, 10000); int slen = sizeof(sockaddr); recvfrom(s, buf, sizeof(buf)-1, 0, (sockaddr *)&si_other, &slen); char *ip = inet_ntoa(si_other.sin_addr); printf("%s: %s\n", ip, buf); } }
那我收不到设备的广播消息
场景 2
但是,如果我有一个 设备 B IP 10.0.255.222
子网掩码 255.255.0.0
我可以接收消息,即使 PC 仍然在另一个子网中。
场景 3
如果我将 PC 移动到 10.0.254.100
并使用子网掩码 255.255.255.0
然后我可以与 设备 A 通信,但是我看不到消息来自设备 B 10.0.255.222
.
更让我困惑的是,在这两种情况下,Wireshark 都可以捕获数据包。
- 为什么我的应用程序不能看到来自 设备 A 的数据包,为什么 wireshark 可以(在第一种情况下)?我可以像 wireshark 一样做些什么才能看到这些数据包?
- 场景 2 和 3 背后的解释是什么? 由于在场景2中,设备B显然在另一个子网中,但通信丢失只发生在场景3
- 我应该阅读哪些内容才能更好地理解这些问题?
PS:我不认为问题出在UDP的不可靠性上。 PPS: 我确实尝试禁用"Capture packets in promiscuous mode",结果是一样的,我可以在Wireshark
中看到来自设备A的数据包Wireshark 将网络适配器置于 "promiscuous mode" 中,报告它在网络上看到的所有数据包。通常它只报告发往主机的数据包。在您的情况下,听起来网络掩码的差异意味着设备将使用不同的广播地址,并且数据包被丢弃。
Wireshark 在 Windows 上安装了一个特殊的网络驱动程序以访问所有流量 https://wiki.wireshark.org/WinPcap
每当你 运行 wireshark .it 自动将你的设备(接口)放入 "promiscuous mode" .so 它将捕获空中的所有数据包, 无需打扰子网掩码。
而您的 PC 将捕获在 同一个子网。
一件事是 - Wireshark 使用混杂模式 - 因此它可以读取交换机端口上的任何内容。这可能包括您自己的广播、一些其他广播,甚至一些不适合您的 uni/multicasts - 只要数据包到达该交换机端口。你的程序不是这种情况。您的程序正在尝试仅接收 网络广播地址 的数据报。现在下面的解释会有所帮助。
我认为您混淆了网络地址和广播域。这是你的情况
场景一。
PC - 10.0.100.100
网络掩码 255.255.0.0
所以广播地址是 10.0.255.255
,(通常任何在网络掩码中是 0
的东西 - 如果它被设置为所有 1
s 成为一个广播地址。)
所以任何发送到这个广播地址的东西都会被你的应用接收。
设备 A 10.0.254.83
网络掩码 255.255.255.0
。所以广播地址是10.0.254.255
。请注意,它不同于 PC 的广播地址,因此您无法接收它们。
所以不要被外表相同的 网络地址所迷惑。
场景 2
设备 B - 10.0.255.222
网络掩码 255.255.0.0
。所以广播地址是10.0.255.255
。这与上面场景 1 中您的 PC 地址相同,因此可以接收数据报(无需处于混杂模式)。 (255.222
部分可能看起来像一个不同的网络,但这不是因为网络掩码是 16 字节 255.255.0.0
。
场景 3
PC : 10.0.254.100 netmask 255.255.255.0 因此网络的广播地址是 10.0.254.255 - 这与场景 1 中设备 A 的广播地址 (10.0.254.255
) 相同,但与广播不同场景 2 中设备 B (10.0.255.255
) 的地址以及预期结果。
在您的场景中 - 设备 A 的网络是设备 B 的子网,PC 的网络和广播仅限于子网。当您将 PC 移入子网时,您会收到子网的广播(Senario 3)。
编辑:
解释 - 为什么你可以在 wireshark 中看到子网广播而为什么在你的应用程序中看不到 - 你在 wireshark 中看到的就是 'received by your network card'。由于所有广播都有 ff:ff:ff:ff:ff
的目的地 mac,您的卡将接收它,但您的 OS 堆栈将丢弃它们,因为网络级地址不是网络级广播.即使没有混杂模式,也会收到第 2 层广播。
希望对您有所帮助。