Search code examples
udpbroadcastpacketnetcat

Making UDP broadcast work with wifi router


I'd like to test out UDP broadcast on a very simple network: an old wifi router (WRT54GS) that's not connected to the internet at all, an android tablet, and my macbook:

[Tablet] <\/\/\/\/\/> [Wifi Router] <\/\/\/\/\/> [Macbook]

where the wavy lines indicate wireless connections.

The Macbook has IP address 192.168.1.101, the tablet has IP address 192.168.1.102. The router is 192.168.1.1.

To avoid too much low-level detail, I wanted to use netcat to do my testing. I decided to use port 11011 because it was easy to type.

As a first step, I thought I'd try just making this work from the macbook back to itself. In two terminal windows, I ran these programs

Window 1: % nc -ul 11011

which I started up first, and then:

Window 2: % echo 'foo' | nc -v -u 255.255.255.255 11011

Nothing showed up in Window 1. The result in Window 2 was this:

found 0 associations
found 1 connections:
     1: flags=82<CONNECTED,PREFERRED>
    outif (null)
    src 192.168.1.2 port 61985
    dst 255.255.255.255 port 11011
    rank info not available

I'm fairly certain I'm missing something obvious here. Can someone familiar with nc spot my obvious error?


Solution

  • This is a multi-part answer, gleaned from other SO and SuperUser answers and a bit of guesswork.

    Mac-to-mac communication via UDP broadcast over wifi

    The first thing is that the mac version of netcat (nc) as of Oct 2018 doesn't support broadcast, so you have to switch to "socat", which is far more general and powerful in what it can send. As for the listening side, what worked for me, eventually, was

    Terminal 1: % nc  -l -u 11011
    

    What about the sending side? Well, it turns out I needed more information. For instance, trying this with the localhost doesn't work at all, because that particular "interface" (gosh, I hate the overloading of words in CS; as a mathematician, I'd hope that CS people might have learned from our experience what a bad idea this is...) doesn't support broadcast. And how did I learn that? Via ifconfig, a tool that shows how your network is configured. In my case, the output was this:

    lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
      options=1203<RXCSUM,TXCSUM,TXSTATUS,SW_TIMESTAMP>
      inet 127.0.0.1 netmask 0xff000000 
      inet6 ::1 prefixlen 128 
      inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1 
      nd6 options=201<PERFORMNUD,DAD>
      gif0: flags=8010<POINTOPOINT,MULTICAST> mtu 1280
      stf0: flags=0<> mtu 1280
    en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
      ether 98:01:a7:8a:6b:35 
      inet 192.168.1.101 netmask 0xffffff00 broadcast 192.168.1.255
      media: autoselect
      status: active
    en1: flags=963<UP,BROADCAST,SMART,RUNNING,PROMISC,SIMPLEX> mtu 1500
      options=60<TSO4,TSO6>
      ether 4a:00:05:f3:ac:30 
      media: autoselect <full-duplex>
      status: inactive
    en2: flags=963<UP,BROADCAST,SMART,RUNNING,PROMISC,SIMPLEX> mtu 1500
      options=60<TSO4,TSO6>
      ether 4a:00:05:f3:ac:31 
      media: autoselect <full-duplex>
      status: inactive
    bridge0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
      options=63<RXCSUM,TXCSUM,TSO4,TSO6>
      ether 4a:00:05:f3:ac:30 
      Configuration:
        id 0:0:0:0:0:0 priority 0 hellotime 0 fwddelay 0
        maxage 0 holdcnt 0 proto stp maxaddr 100 timeout 1200
        root id 0:0:0:0:0:0 priority 0 ifcost 0 port 0
        ipfilter disabled flags 0x2
      member: en1 flags=3<LEARNING,DISCOVER>
            ifmaxaddr 0 port 5 priority 0 path cost 0
      member: en2 flags=3<LEARNING,DISCOVER>
            ifmaxaddr 0 port 6 priority 0 path cost 0
      media: <unknown type>
      status: inactive
    p2p0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 2304
      ether 0a:01:a7:8a:6b:35 
      media: autoselect
      status: inactive
    awdl0: flags=8943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST> mtu 1484
      ether 7e:00:76:6d:5c:09 
      inet6 fe80::7c00:76ff:fe6d:5c09%awdl0 prefixlen 64 scopeid 0x9 
      nd6 options=201<PERFORMNUD,DAD>
    media: autoselect
    status: active
    utun0: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 2000
    inet6 fe80::773a:6d9e:1d47:7502%utun0 prefixlen 64 scopeid 0xa 
    nd6 options=201<PERFORMNUD,DAD>
    

    most of which means nothing to me. But look at "en0", the ethernet connection to the wireless network (192.168). The data there really tells you something. The flags tell you that it supports broadcast and multicast. Two lines late, the word broadcast appears again, followed by 192.168.1.255, which suggested to me that this might be the right address to which to send broadcast packets.

    With that in mind, I tried this:

    Terminal 2: % echo -n "TEST" | socat - udp-datagram:192.168.1.255:11011,broadcast
    

    with the result that in Terminal 1, the word TEST appeared!

    When I retyped the same command in Terminal 2, nothing more appeared in Terminal 1; it seems that the "listen" is listening for a single message, for reasons I do not understand. But hey, at least it's getting me somewhere!

    Mac to tablet communication

    First, on the tablet, I tried to mimic the listening side of the mac version above. The termux version of nc didn't support the -u flag, so I had to do something else. I decided to use socat. As a first step, I got it working mac-to-mac (via the wifi router of course). It turns out that to listen for UDP packets, you have to use udp-listen rather than udp-datagram, but otherwise it was pretty simple. In the end, it looked like this:

    Terminal 1: % socat udp-listen:11011 -
    

    meaning "listen for stuff on port 11011 and copy to standard output", and

    Terminal 2: % echo -n "TEST" | socat - udp-datagram:192.168.1.255:11011,broadcast
    

    Together, this got data from Terminal 2 to Terminal 1.

    Then I tried it on the tablet. As I mentioned, nc on the tablet was feeble. But socat was missing entirely.

    I tried it, found it wasn't installed, and installed it.

    Once I'd done that, on the Tablet I typed

    Tablet: % socat udp-listen:11011 -
    

    and on the mac, in Terminal 2, I once again typed

    Terminal 2: echo -n "TEST" | socat - udp-datagram:192.168.1.255:11011,broadcast
    

    and sure enough, the word TEST appeared on the tablet!

    Even better, by reading the docs I found I could use

    socat udp:recv:11011 -
    

    which not only listens, but continues to listen, and hence will report multiple UDP packets, one after another. (udp-listen, by contrast, seems to wait for one packet and then try to communicate back with the sender of that packet, which isn't what I wanted at all.)