How to Limit Traffic Using LAN Multicast

I use multicast UDP on top of localhost to implement a free set of shared programs running on the same machine. The following code works well on Mac OSX, Windows, and Linux. The disadvantage is that the code will receive UDP packets outside the local network. For example, sendSock.sendto(pkt, ('192.168.0.25', 1600)) accepted by my test machine when sending from another field on my network.

 import platform, time, socket, select addr = ("239.255.2.9", 1600) sendSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) sendSock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 24) sendSock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF, socket.inet_aton("127.0.0.1")) recvSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) recvSock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) if hasattr(socket, 'SO_REUSEPORT'): recvSock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, True) recvSock.bind(("0.0.0.0", addr[1])) status = recvSock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, socket.inet_aton(addr[0]) + socket.inet_aton("127.0.0.1")); while 1: pkt = "Hello host: {1} time: {0}".format(time.ctime(), platform.node()) print "SEND to: {0} data: {1}".format(addr, pkt) r = sendSock.sendto(pkt, addr) while select.select([recvSock], [], [], 0)[0]: data, fromAddr = recvSock.recvfrom(1024) print "RECV from: {0} data: {1}".format(fromAddr, data) time.sleep(2) 

I tried recvSock.bind(("127.0.0.1", addr[1])) , but this prevents the socket from receiving multicast traffic. Is there a way to configure recvSock to only receive multicast packets from the 127/24 network, or do I need to check the address of each packet received?

+7
python multicast sockets localhost
source share
4 answers

Unfortunately, a multicast IP address does not have such a “subnet filtering” function, so if you do not want to use IPTables (on Linux) or the equivalent SW / HW firewall of your system / network to try to “Fall on the floor” you don’t like every multicast packet, I think you have to do it at the application level (for example, with fromAddr test in your inner loop). Is IP traffic from other hosts so badly degrading your performance ...?

+2
source share

Unlike what other answers said, IPv4 supports TTL-based multicast scans, as shown below:

 0: node-local (not forwarded outside the current host) 1: link-local (not forwarded outside the current subnet) < 32: site-local < 64: region-local < 128: continent-local < 255: global 

(It also supports Administratively Enhanced Multicast .)

Source: WR Stevens, Unix Network Programming, 2 nd edition, Volume I, Section 19.2, with corrections for RFC 2365 compliance.

+5
source share

If your host supports IPv6, you can use the multicast scope component (this is the “x” in the FF0x multicast prefix :) to implicitly restrict both inbound and outbound packets to the local host by specifying a scope of 1 (for example, use IPv6 multicast FF01 :: 107 for "name service server" on the local host only). Unfortunately, the IPv4 multicast mechanism is not explicitly visible, and RFC 2365 (http://tools.ietf.org/html/rfc2365), which defines IPv4 extended multicast ranges, does not determine the node -local scope address, only local range of the link area.

+1
source share

You can use connect() to 127.0.0.1 on a multicast socket, then the IP stack can filter for you.

Updated with source code for demonstration.

You can run this script several times on the same host and view distributed multicast packets:

 #!/usr/bin/python import platform, time, socket, select addr = ("239.255.2.9", 1600) sendSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) sendSock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 24) sendSock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF, socket.inet_aton("127.0.0.1")) recvSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) recvSock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) if hasattr(socket, 'SO_REUSEPORT'): recvSock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, True) recvSock.bind(("0.0.0.0", addr[1])) status = recvSock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, socket.inet_aton(addr[0]) + socket.inet_aton("127.0.0.1")); sendSock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) if hasattr(socket, 'SO_REUSEPORT'): sendSock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, True) sendSock.bind(("127.0.0.1", addr[1])); recvSock.connect(("127.0.0.1", addr[1])); while 1: pkt = "Hello host: {1} time: {0}".format(time.ctime(), platform.node()) print "SEND to: {0} data: {1}".format(addr, pkt) r = sendSock.sendto(pkt, addr) while select.select([recvSock], [], [], 0)[0]: data, fromAddr = recvSock.recvfrom(1024) print "RECV from: {0} data: {1}".format(fromAddr, data) time.sleep(2) 

To initiate packets from another interface:

 #!/usr/bin/python import platform, time, socket, select sendSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) pkt = "Hello from network."; sendSock.sendto(pkt, ('10.65.42.129', 1600)) 

I ran all three on Cygwin in Windows XP and checked the result as needed.

Output example

 SEND to: ('239.255.2.9', 1600) data: Hello host: NYCMDV8X5R1 time: Thu Feb 21 13:15:15 2013 RECV from: ('127.0.0.1', 1600) data: Hello host: NYCMDV8X5R1 time: Thu Feb 21 13:15:14 2013 RECV from: ('127.0.0.1', 1600) data: Hello host: NYCMDV8X5R1 time: Thu Feb 21 13:15:15 2013 SEND to: ('239.255.2.9', 1600) data: Hello host: NYCMDV8X5R1 time: Thu Feb 21 13:15:17 2013 RECV from: ('127.0.0.1', 1600) data: Hello host: NYCMDV8X5R1 time: Thu Feb 21 13:15:16 2013 RECV from: ('127.0.0.1', 1600) data: Hello host: NYCMDV8X5R1 time: Thu Feb 21 13:15:17 2013 

Previously, external packages were displayed on the output, for example:

 SEND to: ('239.255.2.9', 1600) data: Hello host: NYCMDV8X5R1 time: Thu Feb 21 13:07:05 2013 RECV from: ('10.65.42.129', 4711) data: Hello from network. RECV from: ('127.0.0.1', 4710) data: Hello host: NYCMDV8X5R1 time: Thu Feb 21 13:07:05 2013 SEND to: ('239.255.2.9', 1600) data: Hello host: NYCMDV8X5R1 time: Thu Feb 21 13:07:11 2013 RECV from: ('10.65.42.129', 4712) data: Hello from network. 
0
source share

All Articles