Python - UDP socket bind() to the correct address - python

I can't understand why if I create a socket in this way
from socket import *
s = socket(AF_INET, SOCK_DGRAM)
s.bind(("192.168.1.10",26000))
print s.recvfrom(4096)[0]
and I try to send to it a broadcast packet like this
from socket import *
s = socket(AF_INET, SOCK_DGRAM)
s.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
s.sendto("hey!", ("<broadcast>", 26000))
it doesn't work (it hangs on the recvfrom()) but if I try to bind it to "0.0.0.0" it receives the packet correctly.
I know that 0.0.0.0 means that every address on every interface will be listening on that port, but why binding directly to an address makes it don't receive the packet?
Operating system: OSX 10.9.2, Python version: 2.7.6
Even if I'm not running Linux, I tried binding the socket to the subnet broadcast address anyway, same results.

If the operating system is Linux then try to bind socket to the subnet broadcast address.
For example, if your ifconfig settings are inet addr:192.168.0.62 Bcast:192.168.0.255 Mask:255.255.255.0then bind your receiver socket to 192.168.0.255. On Linux you won't be able to use your regular IP address
There is a previous discussion on the topic here

In order to Listen to Broadcast packets you need to use the following.
sock.bind(("<broadcast>", port_num))
or
sock.bind(("", port_num))

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.

change your ip in bind socket

I am trying to change my IP while I use bind in socket but it gives me an error:
socket.error: [Errno 10049] The requested address is not valid in its
context
You didn't include any code so I assume you did it like so:
import socket
sock = socket.socket()
#The port and IP are for the sake of example
sock.bind(('1.2.3.4', 1200))
You can't do that. When you bind a socket to an IP and port you "say" to that socket to listen and wait until somebody send something to that port. Of course you can't listen to a port on some other computer so it gives you an error.
If you still wish to change your IP you can use Scapy: http://www.secdev.org/projects/scapy/
This tool very complex but here is the most basic way to change your IP:
from scapy.all import *
#again the IP is only for the sake of example
MyPack = IP(src='1.2.3.4', dst='www.google.com')
send(MyPack)
Congratulations! you have sent a packet with a different IP (pretty sure it's illegal though)

Listen for all incoming traffic on port

With python, I have compiled the following script:
from socket import *
socket = socket(AF_INET, SOCK_DGRAM)
socket.bind(("127.0.0.1", 80))
while True:
data, addr = socket.recvfrom(1024)
print addr[1]
It is supposed to receive all incoming traffic from port 80. However, if I load a webpage, it does not lot anything. Is there a problem with my script?
If you truly want to listen to all incoming traffic on all interfaces, perhaps try to bind to 0.0.0.0 instead of 127.0.0.1?
And as just stated, your socket pairing is a bit odd. This should get you started:
from socket import *
s = socket(AF_INET, SOCK_STREAM)
s.bind(('0.0.0.0', 80))
s.listen(1)
while True:
print s.accept()[1]
There seem to be some misconceptions here, and wanted to make clear for future visitors. When you visit a website you don't send packets out of port 80, you send packets from a random port to the port 80 of a different machine. In this case you are expecting to have packets on your port 80 when you are visiting website: this can't happen. This would only apply if you are hosting a website or listening on that port.

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

Sharing UDP broadcast reception -- python example

I have a UDP broadcast of some data. I'm able to open the following client in python 2.6.1, under OSX 10.6.8, and it works. I can catch the data, all is well.
But: this code "consumes" the port, in that I can't open another one, the 2nd attempt to bind fails... and I must allow for more than one listener. Here's the code that opens the port:
import select, socket
port = 58083 # port msg is broadcast upon
# Create listening port
# ---------------------
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
s.bind(('', port))
except:
print 'failure to bind'
s.close()
raise
s.setblocking(0)
...Since UDP is intended for broadcast to multiple clients (among other things), I assume I'm doing something wrong. I just can't figure out what.
I found an example on activestate that suggested:
s.bind(('<broadcast>',port))
...but that simply fails every time. Binding to 0.0.0.0 works, but also suffers from the "one client" problem. Binding to the local IP (e.g. 192.168.1.100) doesn't work at all. Removing the bind doesn't work at all.
Anyone?
If you need multiple processes to listen on 58083, you need to set SO_REUSEADDR on the socket before socket.bind()
import select, socket
port = 58083 # port msg is broadcast upon
# Create listening port
# ---------------------
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # Allow other processes to
# bind to port
try:
s.bind(('0.0.0.0', port))
except:
print 'failure to bind'
s.close()
raise
s.setblocking(0)
After adding an infinite loop at the bottom, and running this twice on my linux server (once as root, and the other as unpriv user), I see:
root#tsunami# lsof | grep 58083
python 25908 root 3u IPv4 284835 0t0 UDP *:58083
python 25945 mpenning 3u IPv4 284850 0t0 UDP *:58083
root#tsunami#

Categories

Resources