Receive UDP broadcast packets across subnetworks the way wireshark can do it

2.4k views Asked by At

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 of 255.255.0.0
  • the device A at IP 10.0.254.83 with a subnet mask of 255.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.

  1. 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?
  2. 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
  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

3

There are 3 answers

0
gabhijit On BEST ANSWER

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 netmask 255.255.0.0 so the broadcast address is 10.0.255.255, (In general anything that is 0 in netmask - if that is set to all 1s becomes a broadcast address. )

So anything sent to this broadcast address will be received by your App.

Device A 10.0.254.83 netmask 255.255.255.0. So the broadcast address is 10.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 netmask 255.255.0.0. So The broadcast address is 10.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). (The 255.222 part might look like a different network, but it is not because the netmask is 16 byte 255.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.

1
Joni On

Wireshark puts the network adapter into "promiscuous mode" where it reports all packets it sees on the network. Normally it reports only the packets destined to the host. It sounds like in your case the difference in network mask means the device will use a different broadcast address, and the packets are dropped.

Wireshark installs a special network driver on Windows to get access to all traffic https://wiki.wireshark.org/WinPcap

0
SHASHI BHUSAN On

Whenever you run wireshark .it automatically put your device (interface) in "promiscuous mode" .so it will capture all the packets which is in the air , without bothering the subnet mask.

whereas your PC will capture the UDP frame which is multicasted on the same subnet .