When binding a UDP socket to ("", 1234) or ("0.0.0.0", 1234), is it possible to find out what IP-address it will actually send from?
As you can see in the code below, getsockname only tells me what I bound to. But when I send a packet, I can see that the IP-address is, in my case, 10.0.0.2.
Do I have to infer this address myself by looking at my network interfaces? If so, that is fine, but is there a robust way of doing so?
from socket import *
s = socket(AF_INET, SOCK_DGRAM)
s.bind(("", 1234))
print(s.getsockname()) # prints ("0.0.0.0", 1234)
s.sendto("hello", ("10.0.0.3", 1234)) # sends from 10.0.0.2
I've tried doing
import socket
print(socket.gethostbyname(socket.gethostname()))
but that doesn't seem to be very reliable (in the case where I expected 10.0.0.2, I got 127.0.1.1).
I realize that by binding to 0.0.0.0, I bind to all local network interfaces. Does that mean that my source IP-address will be determined by the routing tables when I try to send something? If so, can I still get that address in a robust way from Python?
The IP address used when sending will be determined by the routing table as the packet is sent.
There might be platform specific ways of querying that routing table, but a fairly portable way is to
connect() the socket first.
You can use another socket just for querying this information too. e.g.
from socket import *
s = socket(AF_INET, SOCK_DGRAM)
s.bind(("", 1234))
print(s.getsockname()) # prints ("0.0.0.0", 1234)
sq = socket(AF_INET, SOCK_DGRAM)
sq.connect(("10.0.0.3", 1234))
print(sq.getsockname()[0])
sq.close()
s.sendto("hello", ("10.0.0.3", 1234)) # sends from 10.0.0.2
This is more a usually-you-do-not-need-it answer. It may not correspond to your usecase.
Have alook at socket.gethostbyname_ex(socket.gethostname()). It shows all possible IP-addresses and the host name. You can receive from all of those since you did not bind to any specific one of those. They will be your source ip addresses.
It is not necessairy for you to know the exact address you send from. The receiver may see another one if it goes behind a NAT, into the internet or through a VPN.
The receiver will then know where the packet came from and can send answers.
#Joachim_Pileborg is also right. It is not usually done.
If you need a specific interface, bind to it. If not, you probaply do not need it.
Related
I would like to ask if there any way to to create a socket in Python, using:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
And then, extract the port which going to be generated by the OS, before using:
sock.connect((SERVER_IP, SERVER_PORT)
i.e. my goal is to find the source port of the first SYN packet which will be sent to the server, as part of the 3-way handshake, before actually executing the 3-way handshake.
Note: I figured out that finding out the generated port is possible using:
generated_port = sock.getsockname()[1]
But, unfortunately, the value of generated_port is set just after using sock.connect().
Any help will be much appreciated!
The local port is only available after the socket is bound to a local IP and port. If not explicitly done by calling bind this will be implicitly done doing connect. Therefore to get the local port before calling connect one has to explicitly call bind before that:
import socket
s = socket.socket()
s.bind(('0.0.0.0',0))
print(s.getsockname()[1])
s.connect((host,port))
Hy folks,
my problem: I want to start a (tftp) server for an non-existing IP-address.
the server is meant for USB/RNDIS where its IP-address by nature only is existing when there is actual network-traffic going on -- but I want to start the server 'early' (e.g. when Windows starts).
idea was to bind() the socket to 0.0.0.0 - and then to check each request for "valid" addresses.
problem with that approach: recfrom() only returns the source-address (client), but not the destination (server)!
how do I get the IP-address this client has talked to?
(I could of course check for the same subnet at least, but I need the real server-address this client was talking to!)
or, are there by chance any options to let bind() use a non-existing IP-address?
cheers.
p.s.
this is for the Python tftpy server...
-- at the moment I need to ping from client side when starting the server, which is quite meh...
There's no way to get the local address directly but there's a trick that will usually work for you.
Let's say that you just obtained a buffer and client address from recvfrom. Now you create a new auxiliary UDP socket, connect it to the client's address, and then use getsockname to obtain the local address on this new socket. (With UDP, connect doesn't actually send anything to the peer, it just does address resolution.)
So in this way, you can discover the IP address that the server system would use as source were it to send a datagram back to the client system. That's usually the same address that the client used to target the server.
>>> cbytes, caddr = server_sock.recvfrom(2048)
>>> print(caddr) # Client IP and port
('192.168.0.11', 38869)
>>> aux_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
>>> aux_socket.connect((caddr[0], 9999)) # Connect back to client (port doesn't matter)
>>> saddr = aux_socket.getsockname() # Get local IP and port (ignore port here too)
>>> print(saddr)
('192.168.0.12', 39753)
This works on linux. I'm not 100% sure it would work the same way on Windows but it seems reasonable to expect that it would.
I am trying to make a P2P chat without manually adding users IP Address.
These scripts would send and receive UTF-8 message with UDP packets by manually specifying IP address.
# Send
# Let's say this code is executed from PC1.
import socket
PC2_IP = '192.160.4.169' # IP address is not valid, it is just for example.
UDP_PORT = 5005
MESSAGE = "Hey there!"
sock = socket.socket(socket.AF_INET,
socket.SOCK_DGRAM)
sock.sendto(MESSAGE, (UDP_IP, UDP_PORT))
Now as example let's execute Receiver script from PC2.
# Receive
# Let's say this code is executed from PC2.
import socket
ip = socket.gethostbyname(socket.gethostname())
udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udp.bind((ip, 5005))
while True:
data, addr = udp.recvfrom(1024)
print data
This would work without any problems, The message would be received instantly after script executed.
But in theory how would i make a P2P chat without manually specifying IP addresses?
How would i make application get both users hostnames? Do i need to specify IP Addresses with socket.gethostbyname(socket.gethostname()) in both sender and reciever scripts?
If i need some extra necessary modules which one of them would it be? Can i use P2P module for sockets?
In the 1:1 case the first program doesn't need to know the address of anyone else. It just starts and waits. The second program needs to know the address of the first. As soon as it sends a "hello" the first program now knows the address of the second via recvfrom.
If you want no known addresses, well it stops being a Python question. Now you need to learn about autoconfiguration and network discovery protocols. Multicast? DNS Service Discovery? Bonjour?
That gets complicated real fast. There's a good reason why so many chat and chat-like Internet systems have a single server that everyone knows the address of.
Hope this helps.
maybe help this link P2P Berry Tella=BT
For this exist and python source(if need!)
Hope help you!
So, the very simple code that I'm trying to use is here: http://wiki.python.org/moin/UdpCommunication
(also here):
Sending:
import socket
UDP_IP = "127.0.0.1"
UDP_PORT = 5005
MESSAGE = "Hello, World!"
print "UDP target IP:", UDP_IP
print "UDP target port:", UDP_PORT
print "message:", MESSAGE
sock = socket.socket(socket.AF_INET, # Internet
socket.SOCK_DGRAM) # UDP
sock.sendto(MESSAGE, (UDP_IP, UDP_PORT))
Receiving:
import socket
UDP_IP = "127.0.0.1"
UDP_PORT = 5005
sock = socket.socket(socket.AF_INET, # Internet
socket.SOCK_DGRAM) # UDP
sock.bind((UDP_IP, UDP_PORT))
while True:
data, addr = sock.recvfrom(1024) # buffer size is 1024 bytes
print "received message:", data
The code works fine when I run both applications on my computer. I put the sending code on my laptop with:
UDP_IP="IP address for my computer"
Everything else is the same. Yet, nothing happens. What am I doing incorrectly? I used wireshark and determined that the packet is being sent and received; however, the python program isn't receiving the packet. I'm very confused.
Any help is much appreciated.
Thanks in advance.
Try binding to all local interfaces on the receiving side:
sock.bind(("", UDP_PORT)) # could also use "0.0.0.0"
Note that the behavior of operating systems is not entirely logical (nor consistent) in terms of binding when receiving UDP packets, especially for multicast traffic. This is the behavior you get:
Linux: Binding to a specific IP will filter the incoming UDP packets and only the ones targeted at this specific IP will get through the filter. This means for example that multicast UDP packets received by an interface with IP 192.168.1.100 will not be received when binding to IP 192.168.1.100. On Linux the normal bind does not bind to an interface. Use setsockopt(SO_BINDTODEVICE) for this. Binding to 0.0.0.0 (or "" on Python) will always receive all UDP packets received by the machine on all interfaces, regardless of the destination IP, so this is usually the most useful option on Linux.
Windows: Binding to a specific IP will bind to the interface belonging to this IP, pretty much like setsockopt(SO_BINDTODEVICE) does on Linux. Incoming UDP packets are not filtered by this IP, so multicast traffic can be received even when binding to a concrete IP. (This is probably the first time the Windows behavior seems more consistent to me than the Linux behavior.)
Python does not abstract these OS specific differences away for sockets (as it does in other areas). As long as you have no explicit reason not to do so I suggest to always bind to 0.0.0.0.
eventually figured out my issue and it was pretty complex and highly localized,
I had a very similar problem happen to me. I realize that you have already solved this problem, however I thought it would be good to share how I solved the issue for me.
The issue I found was with my firewall settings. I found that the packets were being blocked by Windows Firewall.
I too had used Wireshark which showed that packets were being sent and received. It is important to note that Wireshark grabs packets at a much lower level than a Python application.
By running my code locally with a listener on one port and a client on another port on the same PC, the firewall wasn't blocking the packets. When I moved to interfacing with an external machine, the firewall rules came into play blocking the incoming packets.
Changing the firewall policy fixed this issue. There are numerous ways and inherent security risks to changing the firewall to make this work so I will leave that part up to the IT professionals. :-)
Make sure that the server port is open while trying to execute recvfrom call. If the destination port from which the socket reading was down then we get this error.
I got the same error and fixed by reading this link - http://www.linuxsa.org.au/mailing-list/2001-04/668.html
So if I want to send a message AND receive a response then how would the code look? Like this?
import socket
UDP_IP = "127.0.0.1"
UDP_PORT = 5005
MESSAGE = "Hello, World!"
sock = socket.socket(socket.AF_INET, # Internet
socket.SOCK_DGRAM) # UDP
sock.sendto(MESSAGE, (UDP_IP, UDP_PORT))
sock.bind((UDP_IP, UDP_PORT))
while True:
data, addr = sock.recvfrom(1024) # buffer size is 1024 bytes
print "received message:", data
I'd like to send a specific UDP broadcast packet. Unfortunately, I need to send the UDP packets from a very specific port.
Let's say I broadcast via UDP "BLABLAH". The server will only answer if my incoming packet source port was 1444; if not, then the packet is discarded.
My broadcast socket setup looks like this:
s = socket(AF_INET,SOCK_DGRAM)
s.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
How can I then set the source port in Python?
You need to bind the socket to the specific port you want to send from. The bind method takes an address tuple, much like connect, though you can use the wildcard address. For example:
s.bind(('0.0.0.0', 1444))
Use s.bind(('', port)).