I have a server(Running on Windows 10) and client (Running on Raspbian) communicating with each other and I'm having issues receiving multicast data from a client device.
I believe I've isolated the problem on my server. The problem is that when I set up the receive socket on my server, the socket only receives multicast data from it's only IP address only, the multicast address is not added even though I've configured it to do so. Currently the code I use to set up my receive socket is...
def _init_recv_socket(self):
self.recieve_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
self.recieve_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.recieve_socket.bind(('', MCAST_PORT))
mreq = struct.pack("4sl", socket.inet_aton(MCAST_GRP), socket.INADDR_ANY)
self.recieve_socket.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
I read online that using socket.INADDR_ANY is dangerous because it won't always set up to the correct interface. I called
print socket.gethostbyname_ex(socket.gethostname())
and it displayed what address I was receiving from and my multicast address was not displayed. The output was:
('MSI', [], ['192.168.99.1])
I found online how to set the multicast and interface address only getting the same output:
group = socket.inet_atons(MCAST_GRP)
iface = socket.inet_atons('192.168.99.1')
self.recieve_socket.setsocketopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, group+iface)
My multicast still isn't showing up when running the gethostbyname command.
I'm stuck and not sure how to get my server working to recieve multicast data...
Note: The same code works fine on my raspberry pi, just not on my windows.
Related
I'm trying to receive UDP Broadcast packets sent from FPGA connected via a LAN cable. the FPGA sends continuous packets to port 5001.
My python receiver code is simple:
from socket import *
s=socket(AF_INET, SOCK_DGRAM)
s.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
s.bind(('', 5001))
print "trying to receive"
msg = s.recvfrom(1024)[0]
print msg
print "I'm outta here! Bye!"
I checked using Wireshark, and I found that the PC receives the packets. However, my Python code doesn't. I also checked sending packets from another local python code (to the same address and port) and my receiver got those packets.
Wireshark captures:
The issue was the firewall permissions for python
I have got a multicast packet capture I'm playing with tcpreplay:
sysctl net.ipv4.conf.all.rp_filter=0
sysctl net.ipv4.conf.eth0.rp_filter=0
tcpreplay -i eth0 --loop=100 new.pcap
I watch the traffic on eth0 with wireshark and I can see the packets I'm interested in (let's say 224.0.23.60:4937).
But the following python app cannot find the packets:
import socket
import struct
MCAST_GRP = '224.0.23.60'
MCAST_PORT = 4937
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((MCAST_GRP, MCAST_PORT)) # use MCAST_GRP instead of '' to listen only
# to MCAST_GRP, not all groups on MCAST_PORT
mreq = struct.pack("4sl", socket.inet_aton(MCAST_GRP), socket.INADDR_ANY)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
while True:
print '#'
print sock.recv(64)
netstat -g is giving the following output:
lo 1 all-systems.mcast.net
eth0 1 224.0.23.60
Am I missing something here ?
[Edit] I should precise that the ip src in my packet capture is not in the same network subdomain (ip src: 192.168.1.10) whereas my ip is something like 146.186.197.164.
After reading carefully the documentation (http://tcpreplay.synfin.net/wiki/FAQ), it seems that tcpreplay sends the packets between the TCP/IP stack and the ethernet device driver, therefore the TCP/IP stack of the host system never sees the packets.
I ended up using a debian Os with virtual box configured with the host only adapter and use tcpreplay in that machine.
Now, it is mentioned clearly on the FAQ page.
https://tcpreplay.appneta.com/wiki/faq.html#can-i-send-packets-on-the-same-computer-running-tcpreplay
Q: Can I send packets on the same computer running tcpreplay?
Generally speaking no. When tcpreplay sends packets, it injects them
between the TCP/IP stack of the system and the device driver of the
network card. The result is the TCP/IP stack system running tcpreplay
never sees the packets.
One suggestion that has been made is using something like VMWare,
Parallels or Xen. Running tcpreplay in the virtual machine (guest)
would allow packets to be seen by the host operating system.
I'm trying to listen to multicast trafic with Python. I try to listen to decode carp protocol, so it's raw trafic not UDP. But I don't receive any data.
If, on the same host, I use an appication listening for the carp trafic (ucarp), the application see the trafic, so it should be working.
Here is the code I'm using:
import socket
import struct
MCAST_GRP = '224.0.0.18'
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, 112)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
mreq = struct.pack("4sl", socket.inet_aton(MCAST_GRP), socket.INADDR_ANY)
s.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
print("waiting for data...")
print(s.recvfrom(10))
In fact, this code is working. The network setup I was using, not. I don't know why this was working with ucarp and not python.
The setup which was not working was a libvirt host running the python and a kvm VM with openbsd sending the carp.
The working setup is two VM, one openbsd sending the carp and one Debian/Linux running the python code.
There is a script that opens a socket and read from it the multicast (from Multicast in Python)
import socket
import struct
MCAST_GRP = '224.1.1.1'
MCAST_PORT = 1234
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('', MCAST_PORT))
mreq = struct.pack("4sl", socket.inet_aton(MCAST_GRP), socket.INADDR_ANY)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
while True:
print sock.recv(10240)
Everything is fine as long as I do not run parallel to the same script to another multicast group, but the ports are the same, for example
rtp://224.1.1.1:1234
rtp://224.1.1.2:1234
After starting the second script starts mess - the first script sees packets for the second and the second to first.
I tried to do as a mcast.py - a similar result.
Why is this happening and how to cure?
UPD Fix
-sock.bind(('', MCAST_PORT))
+sock.bind((MCAST_GRP, MCAST_PORT))
An application listening to all incoming connections on a port will get all messages to that port, no matter which application initiated multicast group membership. To mitigate this, have every application listen to the multicast address it's expecting data from, by specifying it as the first argument in the address tupel given to bind.
This following is a straightforward IPv4 UDP broadcast, followed by listening on all interfaces.
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, True)
sock.bind(("", 1337))
sock.sendto("hello world", ("255.255.255.255", 1337))
while True:
data, addr = sock.recvfrom(0x100)
print "received from {0}: {1!r}".format(addr, data)
I want to adjust this to send and receive both IPv4 and IPv6.
I've poked around and read as much as I can and believe the following is roughly the route I need to take:
Create an IPv6 socket.
Add the socket to a link or site local multicast group.
Send the UDP packets to the multicast address for the group in use.
Further info I have is that I may need to bind to several interfaces, and tell the socket using setsockopt() that it should also receive multicast packets. Lastly getaddrinfo() can be used across the board to gracefully "drop back" to IPv4 where IPv6 isn't available.
I have much of this implemented, but stumble primarily on the multicasting parts. A complete code example in Python, or vivid description of the constants and addresses needed are preferred.
Here's a link to python mcast demo, does both IPv4 and IPv6.
I'm currently asking a question over here that involves getting the multicast address of a received message, but the source code answers your question!
To listen:
# Initialise socket for IPv6 datagrams
sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
# Allows address to be reused
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# Binds to all interfaces on the given port
sock.bind(('', 8080))
# Allow messages from this socket to loop back for development
sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_LOOP, True)
# Construct message for joining multicast group
mreq = struct.pack("16s15s".encode('utf-8'), socket.inet_pton(socket.AF_INET6, "ff02::abcd:1"), (chr(0) * 16).encode('utf-8'))
sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mreq)
data, addr = sock.recvfrom(1024)
and to send:
# Create ipv6 datagram socket
sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
# Allow own messages to be sent back (for local testing)
sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_LOOP, True)
sock.sendto("hello world".encode('utf-8'), ("ff02::abcd:1", 8080))
This is for python3.6, with python 2.7 I don't think the encodes are necessary. Also in the struct.pack line, I've seen variations of "16s15s" such as "4s", but I don't know what it is and what I have worked for me!