We have existing software that periodically broadcasts UDP packets to a specific port (7125) on the local subnet (x.x.x.255). We have monitoring software running on HP-UX (11.11) that is able to receive these packets no problem. However, after porting the monitoring software to Linux (RHEL 6.1) we have found that it does not receive the broadcast packets. tcpdump shows the packets arriving at the Linux host, but the kernel does not send them through to our software.
I've been using a couple of python 2.x scripts that mimic the socket API calls the monitoring software uses to test different scenarios. The Linux kernel passes the packets to the receiver software if the sender uses unicast (10.1.0.5), but not broadcast (10.1.0.255). I've been searching the web for several days and have not found anyone with the same problem. Any ideas?
receiver.py
from __future__ import print_function
import socket
localHost = ''
localPort = 7125
remoteHost = '10.1.0.5'
remotePort = 19100
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
s.bind((localHost, localPort))
s.connect((remoteHost, remotePort))
print('Listening on {0}:{1} for traffic from {2}:{3}'.format(localHost, localPort, remoteHost, remotePort))
data = s.recv(1024)
print('Received: {0}'.format(data))
s.close()
sender.py
from __future__ import print_function
import socket
import time
localHost = ''
localPort = 19100
remoteHost = '10.1.0.255'
remotePort = 7125
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
s.bind((localHost, localPort))
s.connect((remoteHost, remotePort))
data = 'sending this from {0}:{1} to {2}:{3}'.format(localHost, localPort, remoteHost, remotePort)
print(data)
print('2')
time.sleep(1)
print('1')
time.sleep(1)
s.send(data)
print('sent at {0}'.format(time.ctime()))
s.close()
Well, I suggested this answer in a comment, and it proved correct in practice. I would like to investigate surrounding nuances further with my own code, but this is the canonical case-closer.
In addition to setting the SO_BROADCAST
socket option on both sides (as you are already correctly doing), you must also bind your receiver to the broadcast address (e.g., INADDR_BROADCAST
, which is 255.255.255.255 and essentially serves the same role as INADDR_ANY
for unicast).
Apparently, in the HP-UX configuration of the original poster, a UDP socket bound to a unicast address (or INADDR_ANY
, specifically) but with the SO_BROADCAST
socket option set will still receive all UDP datagrams addressed to the local broadcast address as well as unicast traffic directed at the host.
Under Linux, this is not the case. Binding a UDP socket, even when SO_BROADCAST
-enabled, to INADDR_ANY
is insufficient to receive both unicast and broadcast datagrams on the bound port. One can use a separate INADDR_BROADCAST
-bound SO_BROADCAST
socket for the broadcast traffic.