I have an application on the PC that should get some UDP broadcast messages from a device on the local network.
The device periodically sends UDP broadcast messages to its subnetwork and the application should be able to receive these broadcasts. When the PC and the device are in the same subnetwork there is no problem receiving those messages.
However, when I place the device and the PC in different subnetworks then I can no longer receive the device's broadcasts in the PC application, but I can see them in wireshark.
Scenario 1
So if I have:
- the PC at IP
10.0.100.100
with a subnet mask of255.255.0.0
- the device A at IP
10.0.254.83
with a subnet mask of255.255.255.0
this proof-of-concept PC application:
#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); } }
Then I don't receive the broadcast messages from the device.
Scenario 2
However if I have a device B at IP 10.0.255.222
with subnet mask of 255.255.0.0
I can receive the messages, even though the PC is still in another subnetwork.
Scenario 3
If I move the PC at 10.0.254.100
with subnet mask 255.255.255.0
then I can communicate with the device A, but then I cannot see the messages from the device B at 10.0.255.222
.
The thing that confuses me more is that in both cases Wireshark can capture the packets.
- Why can't my application see the packets from device A and why wireshark can (in the first scenario)? What can I do similar to wireshark so I can see those packets?
- What's the explanation behind scenario 2 and 3? Since in scenario 2 the device B is clearly in another subnetwork, but the loss of communication happens only in scenario 3
- What should I read to get a better understanding of these issues?
PS: I don't think the problem comes from the UDP's unreliability. PPS: I did try to disable "Capture packets in promiscuous mode", the result is the same, I can see the packets from the device A in Wireshark
One thing is - Wireshark uses promiscuous mode - so it can read anything that comes on the switch port. This might include your own broadcasts, some other broadcasts and even some uni/multicasts which are not meant for you - provided the packet comes to that switch port. This is not the case with your program. Your program is trying to receive datagrams for the network broadast address only. Now the explanation below would help.
I think you are confusing network Addresses and broadcast domains. Here is what is happening in your case
Scenario 1.
PC -
10.0.100.100
netmask255.255.0.0
so the broadcast address is10.0.255.255
, (In general anything that is0
in netmask - if that is set to all1
s becomes a broadcast address. )So anything sent to this broadcast address will be received by your App.
Device A
10.0.254.83
netmask255.255.255.0
. So the broadcast address is10.0.254.255
. Note it is different from the broadcast address of PC and hence - you cannot receive them.So don't get confused by outwardly looking identical network addresses.
Scenario 2
Device B -
10.0.255.222
netmask255.255.0.0
. So The broadcast address is10.0.255.255
. This is same as your PC's address in scenario 1 above and hence can receive the datagrams (without being in promiscuous mode). (The255.222
part might look like a different network, but it is not because the netmask is 16 byte255.255.0.0
.Scenario 3
PC : 10.0.254.100 netmask 255.255.255.0 so the broadcast address for the network is 10.0.254.255 - which is same as Device A's broadcast address (
10.0.254.255
) in Scenario 1, but not same as broadcast address of Device B (10.0.255.255
) in Scenario 2 and hence the expected outcome.In your scenario - the Device A's network is a subnet of Device B and PC's network and broadcasts are restricted to subnets only. When you move PC into the subnet you receive the broadcast of the Subnet (Senario 3).
Edit:
Explanation - why you can see subnetwork broadcasts in wireshark and why not in your application is - What you see in wireshark is whatever is 'received by your network card'. Since all broadcasts do have a destination mac of
ff:ff:ff:ff:ff
your card is going to receive it, but your OS stack is going to drop them as the network level address is not the network level broadcast. And Layer 2 broadcasts will be received even without promiscuous mode. Hope that helps.