Python raw multicast - python

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.

Related

Multicast from tcp replay seen by wireshark but not by application

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.

How to set multicast address to receive from directly

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.

python multicast with windows 2012 server receiver fail

Python multicast receiver running on windows 2012 server is not getting udp traffic. I inspected traffic and I see the udp traffic is coming across. I have a firewall udp rule for the multicast group with edge traversal allowed. I get no firewall block events. This same code works with windows 2008 server client.
On server (linux ubuntu):
PORT = 12345
import sys, os, time, socket, struct
from socket import gethostname
mc_ttl = 1
mc_group = '224.7.7.7'
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.settimeout(0.2)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL,
struct.pack('b', mc_ttl))
d = "my data"
while True:
sock.sendto(d, (mc_group, PORT))
on Client (windows 2012 server):
PORT = 12345
import sys, os, time, socket, struct
from socket import gethostname
mc_group = '224.7.7.7'
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('', PORT))
mreq = struct.pack("4sl", socket.inet_aton(mc_group), socket.INADDR_ANY)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
while True:
print sock.recv(10240)
Note the above code works on windows 2008 server. After doing some searching I saw that theres some issues with INADDR_ANY binding to wrong address (and the requisite advice against binding to ''). Inspecting incoming udp traffic on windows client I see the multicast traffic but reciever doesn't get it.
I tried the following after reading this post. Which also did not work.
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
grp = socket.inet_aton(mc_group)
ip = socket.gethostbyname(socket.gethostname())
iface = socket.inet_aton(ip)
mreq = grp + iface
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
sock.bind((ip, PORT))
Anyone successfully implemented receiver on windows 2012 server?
I updated the response on the other post to be a bit more explicit. Using socket.gethostbyname() is still getting the default interface, so you'll have to use socket.gethostbyname_ex() to get the extended list then select which interface you want.
Take a look at the difference:
socket.gethostbyname(socket.gethostname())
# "169.254.80.80"
socket.gethostbyname_ex(socket.gethostname())
# ("PCName", [], ["169.254.80.80", "192.168.1.10"])
In the above example, we would want to skip over the first 169.254 link-local address and select the desired 192.168.1.10 address. If socket.gethostbyname() was used in the above example, it would have been the link-local (169.254.*) address that would have been selected and your code wouldn't be doing much.
socket.gethostbyname_ex(socket.gethostname())[2][1]
# "192.168.1.10"

Python service discovery: Advertise a service across a local network

I have a "server" python script running on one of the local network machines, which waits for clients to connect, and passes them some work to do. The server and client code have both been written, and are working as expected...
The problem is, this server might be running from any machine in the local network, so I can't hard code the address in the script... I immediately wondered if I can make a machine advertise about its existence, and clients can respond to that. Is that doable in Python with the standard library? I really don't have time to download twisted or tornado and learn about them, unfortunately, so I need something simple.
I tried to think more about it, and realized I can have a single static IP machine where servers register/unregister from and clients can look for servers from there. Kind of like a torrent tracker, I think. This'll have to do if I can't do the service advertising approach easily.
An easy way to do service announcement/discovery on the local network is by broadcasting UDP packets.
Constants:
PORT = 50000
MAGIC = "fna349fn" #to make sure we don't confuse or get confused by other programs
Announcement:
from time import sleep
from socket import socket, AF_INET, SOCK_DGRAM, SOL_SOCKET, SO_BROADCAST, gethostbyname, gethostname
s = socket(AF_INET, SOCK_DGRAM) #create UDP socket
s.bind(('', 0))
s.setsockopt(SOL_SOCKET, SO_BROADCAST, 1) #this is a broadcast socket
my_ip= gethostbyname(gethostname()) #get our IP. Be careful if you have multiple network interfaces or IPs
while 1:
data = MAGIC+my_ip
s.sendto(data, ('<broadcast>', PORT))
print "sent service announcement"
sleep(5)
Discovery:
from socket import socket, AF_INET, SOCK_DGRAM
s = socket(AF_INET, SOCK_DGRAM) #create UDP socket
s.bind(('', PORT))
while 1:
data, addr = s.recvfrom(1024) #wait for a packet
if data.startswith(MAGIC):
print "got service announcement from", data[len(MAGIC):]
This code was adapted from the demo on python.org

Duplicate packets in Python multicast receiver

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.

Categories

Resources