Associating a Python Multicast Network with a Binding to a Specific Interface

After searching high and low on google, I did not find a definitive answer to the following question: approximately following the following guide: http://twistedmatrix.com/documents/10.2.0/core/howto/udp.html#auto3

How can I associate a binary multicaster listener with ONLY the multicast address and on certain or all interfaces.

When looking at the .listenMulticast reactor, it does not provide abstractions for the hardware interface, only the pseudo-interface represented by the IP address. I cannot find a way to bind only to a multicast address, for example. 224.0.0.1 specific interface or all interfaces. Can someone provide more information about this?

+7
source share
3 answers

reactor.listenMulticast returns a twisted.internet.udp.MulticastPort object. This object owns the socket you are listening to. So hold on to the result of the .listenMulticast reactor and set the appropriate socket option (in this case it looks like SO.BINDTODEVICE) along with the null terminated string of the device.

 import IN, socket, struct udp_port = reactor.listenMulticast(8005, MulticastServerUDP()) dev = "eth0" + "\0" udp_port.socket.setsockopt(socket.SOL_SOCKET, IN.SO_BINDTODEVICE, dev) reactor.run() 

It would be nice if it were opened directly through a call to listenMulticast , but provided that it works, it will be a fairly simple patch. Let me know if this solves your problem.

+3
source

Other answers may solve the problem, but there is a β€œmore twisted” (and probably simpler) way to listen to the multicast group on multiple interfaces.

Listening to a group on one or more interfaces

To listen to a multicast group on one or more interfaces, specify the IP of each desired interface in several calls to the transport.joinGroup () method as the argument to "interface".

The following is an example that works on my Linux box and will force your system to listen to multicast messages on specific interfaces. Replace the IP addresses with those belonging to your system.

 #!/usr/bin/env python from twisted.internet import protocol from twisted.internet import reactor class MyProtocol(protocol.DatagramProtocol): def startProtocol(self): # Join a multicast group, 224.0.0.9, on the interface belonging # to each of these IPs. # XXX Replace the interface_ips with one or more IP addresses belonging # to your system. for interface_ip in ["192.168.2.2", "10.99.1.100"]: self.transport.joinGroup("224.0.0.9", interface_ip) if __name__ == "__main__": reactor.listenMulticast(1520, MyProtocol()) reactor.run() 

You can verify that the interface is listening on a new multicast group using the /sbin/ip maddr show . Locate the interface name you are looking for in the output of the command and verify that the multicast group is displayed below it.

An example UDP server associated with the original message should be able to do the same by changing the call to joinGroup () to include the second argument of the IP address, as indicated above.

Send multicast from a specific IP

If you receive multicast data on a socket, most likely you will also want to send multicast data - perhaps from several interfaces. Since it is closely related and there are very few examples, I will drop it here. Inside the twisted.internet.protocol.DatagramProtocol object, you can use the self.transport.setOutgoingInterface () method to control the source IP address, which will be used for subsequent calls to self.transport.write (). An example showing sending a message from multiple IP addresses / interfaces:

 class MyProtocol(protocol.DatagramProtocol): # ... def send_stuff(self, msg): for src_ip in ["10.0.0.1", "192.168.1.1"]: self.transport.setOutgoingInterface(src_ip) self.transport.write(msg, ("224.0.0.9", 1520)) 

Suppose these IP addresses have been assigned to two different interfaces. Sniffing out Wireshark, you will see a message sent from the first interface, and then the second interface, using each IP as the source IP address for the corresponding transfer.

+3
source

Simple, if a tough approach might be to simply point the route through something like:

 sudo route add 239.255.0.0 -interface en0 -netmask 255.255.0.0 
+1
source

All Articles