How to change a socket's IP_MULTICAST_IF

11,000

Solution 1

The answer: my firewall did not accept udp packet from that RFC1918 IP address.

Solution 2

In case the server and the client are on the same machine (for testing), maybe you need to set IP_MULTICAST_LOOP option like this (c Code):

int loop_on = 1;
setsockopt(socket, IPPROTO_IP, IP_MULTICAST_LOOP, &loop_on, sizeof(loop_on));

In python you can try something like this:

sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_LOOP, 1)

Hope this help.

Edit : Adding some trace (From my Linux box)

The code i use is the same as posted by SquallLeohart:

#! /usr/bin/python

import socket

MCAST_GRP = '224.0.0.1'
MCAST_PORT = 10222

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_IF, socket.inet_aton("192.168.1.7"))
sock.sendto("HELLO", (MCAST_GRP, MCAST_PORT))

And:

#! /usr/bin/python
import socket
import sys

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(("", 10222))
sock.setsockopt(socket.IPPROTO_IP,
                                 socket.IP_ADD_MEMBERSHIP,
                                 socket.inet_aton("224.0.0.1") +
                                 socket.inet_aton("192.168.1.7"))
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_LOOP, 0)

while True:
    print >>sys.stderr, '\nwaiting to receive message'
    data, address = sock.recvfrom(1024)

    print >>sys.stderr, 'received %s bytes from %s' % (len(data), address)
    print >>sys.stderr, data

    print >>sys.stderr, 'sending acknowledgement to', address
    sock.sendto('ack', address)

I got this output :

waiting to receive message
received 5 bytes from ('192.168.1.7', 43761)
HELLO
sending acknowledgement to ('192.168.1.7', 43761)

waiting to receive message
received 5 bytes from ('192.168.1.7', 52326)
HELLO
sending acknowledgement to ('192.168.1.7', 52326)

waiting to receive message

And with tcpdump:

21:01:33.814728 IP localhost.localdomain.34956 > all-systems.mcast.net.10222: UDP, length 5
21:01:35.364605 IP localhost.localdomain.39078 > all-systems.mcast.net.10222: UDP, length 5
21:01:36.228477 IP localhost.localdomain.49926 > all-systems.mcast.net.10222: UDP, length 5

Regards.

Share:
11,000
Squall Leohart
Author by

Squall Leohart

I like serious and concise answers!

Updated on June 04, 2022

Comments

  • Squall Leohart
    Squall Leohart almost 2 years

    I have a Computer with 5 interfaces: 3 with public IPs and 2 local IPs. I am trying to send "HELLO" to a UDP server, but I would like to change the interface to one of the local IP addresses. I did some research and this is the line I need to add in python:

    sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_IF, socket.inet_aton("64.195.10.11"))
    

    with 64.195.10.11 being the IP I want to change to

    So my python code looks like this:

    import socket
    
    MCAST_GRP = '224.0.0.1'
    MCAST_PORT = 10222
    
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
    sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_IF, socket.inet_aton("64.195.10.10"))
    sock.sendto("HELLO", (MCAST_GRP, MCAST_PORT))
    

    It works perfectly when I change between my 3 public IP addresses. However, it does not work (packet is not delivered) if I put a local IP in the argument. I am not sure if the script does not send, or the server does not receive. What is happening?

    SL

    Edit: I am listening using two ways:

    import socket
    import sys
    
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.bind(("", 10222))
    sock.setsockopt(socket.IPPROTO_IP,
                                     socket.IP_ADD_MEMBERSHIP,
                                     socket.inet_aton("224.0.0.1") +
                                     socket.inet_aton("64.195.10.11"))
    sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_LOOP, 0)
    
    while True:
        print >>sys.stderr, '\nwaiting to receive message'
        data, address = sock.recvfrom(1024)
    
        print >>sys.stderr, 'received %s bytes from %s' % (len(data), address)
        print >>sys.stderr, data
    
        print >>sys.stderr, 'sending acknowledgement to', address
        sock.sendto('ack', address)
    

    and using twisted:

    from twisted.internet.protocol import DatagramProtocol
    from twisted.internet import reactor
    from twisted.application.internet import MulticastServer
    
    class MulticastServerUDP(DatagramProtocol):
        def __init__ (self, group, name):
            self.group = group
            self.name = name
        def startProtocol(self):
            print '%s Started Listening' % self.group
            self.transport.joinGroup(self.group)
    
        def datagramReceived(self, datagram, address):
            print "%s Received:"%self.name + repr(datagram) + repr(address)
    
    reactor.listenMulticast(10222, MulticastServerUDP('224.0.0.1', 'SERVER1'), listenMultiple = True)             
    reactor.run()
    
  • Squall Leohart
    Squall Leohart over 11 years
    It does not help unfortunately. It seems like interfaces with similar IP addresses have no problem when I switch them, such as 64.195.10.110, 64.195.10.11, 64.195.10.12 But 192.168.1.75, for example, is an address that I cannot switch to.
  • TOC
    TOC over 11 years
    @SquallLeohart: can you use tcpdump and dump some packets here please?
  • TOC
    TOC over 11 years
    @SquallLeohart : Yes i post it, i use it on my local LAN on (192.168.1.7)
  • Squall Leohart
    Squall Leohart over 11 years
    Your line about the loop does not help, as it gives me the same problem whether I run the codes on the same machine or two different machine. I just found out that the problem was due to my firewall setting. My code works now. Anyway, thank you very much!