I'm trying from my virtual machine to bind my socket in python to the address of my other virtual machine so that I could sniff the frames that are exchanged by the two. So here's my code
import socket
UDP_IP = "fe80:849b:21f4:624c:d70b"
UDP_PORT = 61627
sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR,1)
sock.bind((UDP_IP, UDP_PORT))
while True:
data, addr = sock.recvfrom(1024)
print(data)
When I try to execute my python, I get an error message :
sock.bind((UDP_IP, UDP_PORT))
socket.error: [Error 22] Invalid argument
What am I doing wrong, thanks in advance !
I bet, you had found the answer already, but nevertheless on the first glance I see two issues with your code:
In IPv6 fe80::/10 address block is reserved for Link-local addresses. These addresses are valid for local subnet only, therefore they are used with scope suffixes like %eth0 to specify proper scope. Where eth0 is a name of the network interface for which the IPv6 address is valid.
So for my MacOS laptop UDP_IP address could look like:
UDP_IP = "fe80:849b:21f4:624c:d70b%en0"
Next, specifying (UDP_IP, UDP_PORT) tuple is absolutely valid for IPv4 but for IPv6 this tuple should also contain flow_info and scope_id fields. Sometimes, flow_info and scope_id could be omitted or missed: (UDP_IP, UDP_PORT, 0, 0). It may work sometimes, but it's not the right way to use in the code.
So, these fields can be fetched via socket.getaddrinfo(IP, PORT) which returns a list of tuples for each address family and socket_kind. Filter them with something like that:
for ainfo in socket.getaddrinfo(UDP_IP, UDP_PORT):
if ainfo[0].name == 'AF_INET6' and ainfo[1].name == 'SOCK_DGRAM':
target_address = ainfo[4]
break
sock.bind(target_address)
I'm not sure, if I wrote the sample code right, as I didn't test it, check it before usage.
Related
I am new to python programming. I have the task to read the broadcast feed on UDP port 4012.I have code of visual basic and it is working fine. The code is as follows.
#Dim receivingUdpClient As New UdpClient(4012)
#Dim RemoteIpEndPoint As New IPEndPoint(IPAddress.Any, 0)
#receiveBytes = receivingUdpClient.Receive(RemoteIpEndPoint)
#returnData = Encoding.ASCII.GetString(receiveBytes)
#Dim TestArray() As String = Split(returnData, ";")
I made the following program in python to read the broadcast feed on UPD port 4012, but was unable to achieve it with the following python program. The program is working and shows the cmd window message "waiting for 4012 localhost from 4012".
Can anybody help me out with this? If the code is correct then, how can i checked resolve this issue? i also want to read good material about socket programming in python specially about the UDP socket Broad Cast reading, if anybody can recommend any video or material for read.
import socket
s=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udp_host = 'localhost'
udp_port = 4012
s.connect((udp_host,udp_port))
print("waiting for 4012",udp_host, "from" ,udp_port)
data , addr= s.recvfrom(1024)
print("Received Messages: ", data ,"from", addr)
You should use broadcast IP to listen.
Currently you are listening 'localhost', but broadcast IP is usually your subnet maximum IP (for 255.255.255.0 mask it is IP with number 255 in last octet)
You need to get right IP from somewhere. Manually you can do it with ifconfig on *nix, or ipconfig on Win:
inet 192.168.100.7 netmask 0xffffff00 broadcast 192.168.100.255
so you need 192.168.100.255
Also, easy way is to listen all IP's. To listen all IP's you could bind socket to '0.0.0.0' or just ''. But in this case you'll catch both broadcast and direct packets.
import socket
s=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udp_host = ''
udp_port = 4012
s.connect((udp_host,udp_port))
print("waiting for 4012",udp_host, "from" ,udp_port)
data , addr= s.recvfrom(1024)
print("Received Messages: ", data ,"from", addr)
this snippet is something i use quite often do create basic socket server stuff...
socket_config = {
'udp_ip_address': 'your.ip.here.bla',
'udp_port_no': '6789',
'max_send_size': '1024'
}
#
# socket creation
#
serverSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
serverSock.bind((socket_config['udp_ip_address'],
int(socket_config['udp_port_no'])))
def receive_loop():
# eternal loop starts here
while True:
data, addr = serverSock.recvfrom(int(socket_config['max_send_size']))
data = data.decode('utf-8')
logger.debug("Message:" + data)
I want to find out my computer’s IP address which other online services access. I have tried following pieces of code from Finding local IP addresses using Python's stdlib
import socket
print("\nYour IP Address is: ",end="")
print(socket.gethostbyname(socket.gethostname()))
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("8.8.8.8", 80))
print(s.getsockname()[0])
s.close()
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
# doesn't even have to be reachable
s.connect(('10.255.255.255', 1))
IP = s.getsockname()[0]
except:
IP = '127.0.0.1'
finally:
s.close()
print(IP)
However, the first two return: 10.105.220.74 and the third returns 127.0.1.1.
However, 192.31.105.231 is returned when using https://get-myip.com/ and https://www.iplocation.net/find-ip-address.
https://whatismyipaddress.com/ returns: IPv6:
2607:f140:6000:17:f0b8:ba78:a9df:213 IPv4: Not detected
Note that I slightly adjusted the IP addresses for privacy reasons.
Thank you for your help!
Facts & context elements:
I need to capture data (latitude,longitude) coming out of a GPS device rework them and make them suitable for another application (QGIS). To this end I've tried to perform (What I thought at first would be a simple one) a python based module.
According to wire shark analysis.
Source Destination Protocol length info
192.168.0.1 225.2.5.1 UPD 136 source port : 1045 destination port:6495
I've tried this code found on various sources, like this one.
import socket
import os
UDP_IP = "225.2.5.1"
UDP_PORT = 6495
sock = socket.socket(socket.AF_INET, # Internet
socket.SOCK_DGRAM) # UDP
sock.bind((UDP_IP, UDP_PORT))
while True:
data, addr = sock.recvfrom(4096) # buffer size is 1024 bytes
print "received message:", data
os.system("pause")
The problem
This code doesn't work for me.The console windows whether collapse (despite the os.system("pause") or run indefinitely. As I'm not very skilled in python programming nor networking I've tested the provided code with the other IP address and port. As no result came from it I've also started to mix both of them. And finally, gave up and decided to share my issue with the community.
The aim :
I need to be able to access the data contains in this UDP frame with python 2.7 save them in a variable (data) for the next step of my programming project.
Thanks for reading and for your help
You should start your python program from the windows cmd-console or powershell, not from the explorer, then the window stays open and you see error messages. Remove the indentation error and the last line. Be sure, that your computer has the given IP-address. Bind your socket to any address:
import socket
UDP_IP = "0.0.0.0"
UDP_PORT = 6495
sock = socket.socket(socket.AF_INET, # Internet
socket.SOCK_DGRAM) # UDP
sock.bind((UDP_IP, UDP_PORT))
while True:
data, addr = sock.recvfrom(4096)
print "received message:", data
I have a server with two separate Ethernet connections. When I bind a socket in python it defaults to one of the two networks. How do I pull a multicast stream from the second network in Python? I have tried calling bind using the server's IP address on the second network, but that hasn't worked.
I recommend you don't use INADDR_ANY. In production multicast environments you want to be very specific with your multicast sockets and don't want to be doing things like sending igmp joins out all interfaces. This leads to hack-job workarounds when things aren't working like "route add -host 239.1.1.1 dev eth3" to get multicast joins going correctly depending on the system in question. Use this instead:
def joinMcast(mcast_addr,port,if_ip):
"""
Returns a live multicast socket
mcast_addr is a dotted string format of the multicast group
port is an integer of the UDP port you want to receive
if_ip is a dotted string format of the interface you will use
"""
#create a UDP socket
mcastsock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
#allow other sockets to bind this port too
mcastsock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
#explicitly join the multicast group on the interface specified
mcastsock.setsockopt(socket.SOL_IP,socket.IP_ADD_MEMBERSHIP,
socket.inet_aton(mcast_addr)+socket.inet_aton(if_ip))
#finally bind the socket to start getting data into your socket
mcastsock.bind((mcast_addr,port))
return mcastsock
In the mcastsock.bind you can also use '' instead of the address string, but I advise against this. With '', if you have another socket using the same port, both sockets will get eachothers data.
When binding your socket, try the values mentioned here:
For IPv4 addresses, two special forms
are accepted instead of a host
address: the empty string represents
INADDR_ANY, and the string
'' represents
INADDR_BROADCAST.
INADDR_ANY is also known as the wildcard address:
Sockets with wildcarded local addresses may receive messages directed to the specified port number and addressed to any of the possible addresses assigned to a host`
More here.
I figured it out. It turns out that the piece I was missing was adding the interface to the mreq structure that is used in adding membership to a multicast group.
For IPv4, the index of the network interface is the IP address; for IPv6 the index of the network interface is returned by the method socket.getaddrinfo.
The code below shows how to listen to multicast on all network interfaces:
from socket import AF_INET6, AF_INET
import socket
import struct
# Bugfix for Python 3.6 for Windows ... missing IPPROTO_IPV6 constant
if not hasattr(socket, 'IPPROTO_IPV6'):
socket.IPPROTO_IPV6 = 41
multicast_address = {
AF_INET: ["224.0.1.187"],
AF_INET6: ["FF00::FD"]
}
multicast_port = 5683
addr_info = socket.getaddrinfo('', None) # get all ip
for addr in addr_info:
family = addr[0]
local_address = addr[4][0]
sock = socket.socket(family, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((local_address, multicast_port))
if family == AF_INET:
for multicast_group in multicast_address[family]:
sock.setsockopt(
socket.IPPROTO_IP,
socket.IP_ADD_MEMBERSHIP,
socket.inet_aton(multicast_group) + socket.inet_aton(local_address)
)
elif family == AF_INET6:
for multicast_group in multicast_address[family]:
ipv6mr_interface = struct.pack('i', addr[4][3])
ipv6_mreq = socket.inet_pton(socket.AF_INET6, multicast_group) + ipv6mr_interface
sock.setsockopt(
socket.IPPROTO_IPV6,
socket.IPV6_JOIN_GROUP,
ipv6_mreq
)
# _transport, _protocol = await loop.create_datagram_endpoint(
# lambda: protocol_factory(), sock=sock)
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!