Reputation: 31
I am working on an Ubuntu 14.04 server with multiple interfaces on different subnets. I am trying to write a twisted(13.2.0) application that listens for broadcasts on one interface only, ignoring the other interfaces.
I am able to receive broadcasts with this code.
from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor
import IN, socket, struct
class BroadcastListener(DatagramProtocol):
def startProtocol(self):
self.transport.getHandle().setsockopt(socket.SOL_SOCKET,
socket.SO_BROADCAST, True)
def datagramReceived(self, datagram, address):
print "Received datagram from %s" % (address[0])
#reactor.listenUDP(65001, BroadcastListener(), interface='192.168.1.1')
reactor.listenUDP(3200, BroadcastListener())
reactor.run()
I am sending test UDP broadcasts from another machine on the 192.168.1.x subnet with socat.
echo Hi |socat - UDP-DATAGRAM:192.168.1.255:3200,broadcast
However, this will receive broadcasts on any interface on the server. I thought it would be specificying the interface in reactor.listenUDP(), as I did the commented call.
If I use the reactor.listenUDP() call that includes the interface, I no longer receive broadcast. I still receive unicasted UDP sent with socat.
echo Hi |socat - UDP-DATAGRAM:192.168.1.1:3200
I can see when specifying the interface that the socket is bound to the interface.
$ netstat -an |grep udp |grep 3200
udp 0 0 10.10.0.1:3200 0.0.0.0:*
But the broadcasts are being dropped. I confirmed with tcpdump the broadcasts are arriving to the server.
What is the correct way to set a UDP listener's interface in twisted python?
Upvotes: 3
Views: 2185
Reputation: 249153
I'm assuming you're on Linux here. It seems that bind()
won't work because it drops packets not addressed to the interface, which for broadcast packets is all of them. Instead, try the socket option SO_BINDTODEVICE
, which may not be in your Python socket
module, but has the value 25
on my Linux system and probably on yours (check /usr/include/asm-generic/socket.h
). It takes an interface name rather than an IP address, so it should look something like this:
self.transport.getHandle().setsockopt(socket.SOL_SOCKET, 25, "eth0")
Upvotes: 1