0

I am trying to send UDP broadcast messages, but I have issue with the address to use. If I run:

import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
s.sendto("hello broadcast".encode("ascii"), ("<broadcast>", 1500))
s.sendto("hello 11".encode("ascii"), ("192.168.1.11", 1500))
s.sendto("hello 255".encode("ascii"), ("192.168.1.255", 1500))
s.sendto("hello 255.255".encode("ascii"), ("192.168.255.255", 1500))
s.sendto("hello 255.255.255".encode("ascii"), ("192.255.255.255", 1500))
s.sendto("hello 255.255.255.255".encode("ascii"), ("255.255.255.255", 1500))

and log the traffic with Wireshark, I only see the packets for:

192.168.1.11
192.168.1.255
192.168.255.255
192.255.255.255

but not for:

<broadcast>
255.255.255.255

This happens when I run it from WSL1 (Windows Subsystem for Linux), using Python 3.6.9, and also when I run it from Windows 10 Powershell, using Python 3.7.2.

If I use WSL2, using python 3.8.2, I get the packets for:

192.168.1.11
192.168.255.255
192.255.255.255

but not for:

<broadcast>
192.168.1.255
255.255.255.255

This is really strange. The 'real' broadcast addresses are ignored. It seems as if setting socket.SO_BROADCAST is ignored in Windows 10.

If I comment out s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1), I get errors when trying to send something on the broadcast addresses.

If I however use a Linux box (Python versions 2.7.17, 2.7.18, 3.6.9 and 3.8.5), I get the packets for:

<broadcast>
192.168.1.255
255.255.255.255

but not for:

192.168.1.11
192.168.255.255
192.255.255.255

This is what I would expect for broadcast. Why does it not work that way on Windows 10 and on WSL and how can I fix it?

I have a Windows executable that sends UDP broadcast messages and I can see that it sends to "255.255.255.255". So the limitation is not the machine.

NZD
  • 1,780
  • 2
  • 20
  • 29

1 Answers1

2

After some more testing, I found out what the problem was.

When you send a message with a destination IP address, the system knows which interface to use. Because broadcast doesn't need an IP address, the system doesn't know which interface to use. The system will choose an interface to send the broadcast messages, according to some mechanism.

All my Linux boxes only had one interface (e.g. eth0 or eno1), so there was not much to choose from. You can find the IP addresses associated with these interfaces by running hostname -I. In this case that gave me 192.168.1.51 on interface eno1 and all broadcast messages come out that interface. To see the routing run route or ip route.

My Windows 10 box however has several interfaces eth0, eth1 and eth2. My Ethernet cable is connected to eth0. When I run hostname -I I get 192.168.1.100 192.168.56.1 172.30.48.1 on respective interfaces eth0 eth1 eth2. All the broadcast messages came out of eth1 for some reason.

When I added s.bind(('192.168.1.100', 0)) to my code, the broadcast messages came out of interface eth0, which is where the Ethernet cable is connected.

The Windows executable that sends UDP broadcast messages uses a brute-force approach. It broadcasts on all interfaces.

Posts that helped me:

NZD
  • 1,780
  • 2
  • 20
  • 29