I need my own IP in a small script and in order not to hardcode it, I`ve found a piece of code from here(stackoverflow) that works.
This--
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
s.connect(("8.8.8.8", 80))
print(s.getsockname()[0])
--
What is not clear for me is why it only works on UDP and not TCP? It has something to do with the google dns server? Thanks in advance.
This has nothing to do with Google and nothing to do with DNS.
All what this code does is to "connect" a UDP socket to an external IP, so that the OS kernel figures out which local IP address it needs to use in order to reach this external system. This is no real connection, i.e. there is no traffic involved but the OS kernel is only checking routing tables and local interfaces in order to decide which IP address to use as source in case one would actually use the socket to send data.
One could do the same with TCP. But in this case a real TCP connection would be established which means that actual traffic would be exchanged and that the connect would fail if the external system would not be reachable on this port (i.e. no listener, firewall in between etc).
With UDP instead connect will not produce any traffic and would fail only if no route to the destination IP address could be determined. This also means that an arbitrary external IP address and port could be used, i.e. ('1.1.1.1',11) would work the same as ('8.8.8.8',80).
Related
So far I have made a VERY basic client/server application that creates a TCP connection. I have a lot of programming experience, just never did this low-level stuff and especially nothing with networks. Note that all the prints are just to help me figuring out what is going on. One of the known issues is that jsonip sometimes gives me an IPv4 and sometimes v6, I don't know why but that doesn't matter for now, just to warn anyone who wants to recreate my code.
Server:
import socket
import requests
port = int(input("Enter port you want to open:\n"))
#todo: add errorhandling
print("Adding socket...")
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
hostname = socket.gethostname()
print(f"Hostname: {hostname}")
ip_address = socket.gethostbyname(hostname)
print(f"Host address: {ip_address}")
r = requests.get(r'http://jsonip.com')
public_ip_address = r.json()['ip']
s.bind((ip_address, port))
print("Is open for connections on IP: "+public_ip_address+" and Port: "+str(port))
s.listen(5)
print("Done initialisation, listening for incoming connections...")
while True:
clientsocket, address = s.accept()
print(f"Connection from {address} has been established")
clientsocket.send(bytes(f"You have connected to server: {hostname}", "utf-8"))
Client:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ip = input("Enter IP to connect to:\n")
port = int(input("Enter Port to connect to:\n"))
print(f"Connecting to server {ip} ...")
s.connect((ip, port))
msg = s.recv(1024)
print(msg.decode("utf-8"))
On my local machine: Open 20000 in my server.py, it tells me the host is 127.0.1.1, I then enter 127.0.1.1 into my client script and 20000, and they connect. So the Socket has been bound with the 127.0.1.1. (Side question: What is this IP address, is it like the internal IP address of processes in my PC or something? If running ip a on my other machine it is the first one shown of 2)
Using Virtmanager on my machine and running one Linux Server (command line only) and one normal Ubuntu, the server tells me the host is, again, 127.0.1.1 which I don't need to enter into the other VM to know it won't work, what does work however, is getting the IP-address of the Server via ip a, which in this case is 192.168.122.37, and when I enter this IP address into the client, it connects. But in the socket here I bind, again, the 127.0.1.1, so is it arbitrary what I put here? What SHOULD I bind here, the public, the weird or the 192. address?
The first thing I could not get to work was using 2 physical devices. When opening a server on my Linux machine, I cannot connect with my windows machine at all, no matter if I use my public, my 127. or my 192. IP-address. Now my end goal is doing this over the internet so I am walking myself up, describing here the steps I took to try and get where I want to be but here I hit a brick wall where I don't know what is wrong. Am I binding the wrong address on the server, is my router being a problem, is there something else wrong?
I also tried leaving my network using my friends pc a few countries over, but this also just results in a timeout (my theory is that the Router port he is trying to open is closed and I have now idea how I can make the router send data to his PC, which should be not impossible as firefox and every application using internet does it without me having to manually forward every port, I just don't know how). This is my end goal, creating a connection between my friends PC and mine, and this is how far I got (I wouldn't mind skipping the local network if it is not relevant for fixing the global connection problem), so, tl;dr: what did i do wrong, what do i need to bind and what do i need to do for the final result to work?
There are many questions to answer.
Addresses 127.X.X.X are reserved for the loopback interface, most common one is 127.0.0.1. The loopback is a virtual, but important interface and as you have probably guessed, it is usable on the local machine only. You cannot use 127.X.X.X address to make two hosts to communicate with each other.
Addresses 192.168.X.X (and also 10.X.X.X and 172.16-31.X.X.) are reserved for local LANs. They are not valid on the Internet.
You cannot use these addresses to make two hosts to communicate with each other over the public Internet (unless you create a tunnel, an advanced networking topic)
Almost everybody uses them, because we ran out of IPv4 addresses long time ago, they were difficult to get, expensive, etc. Also such hosts are isolated from the Internet, they can be reached only via a router that translates addresses. Such router feature is called NAT. A typical router has one valid Internet address and all connections to the Internet appear as coming from the router. If you contant a service like jsonip.com from a PC, you get your router's address, not your PC's address.
See also: Finding local IP addresses using Python's stdlib
To make your program working, make it to accept connections on all interfaces. See the first example in the socket docs. On Linux, use port numbers >= 1024. Ports < 1024 are reserved, not available to regular users.
Final point is that a firewall may prevent connections to your server. It depends on your system and setup.
I am writing a socket program to create a simple server.
When I write ip = socket.gethostbyname(socket.gethostname()) and then I print ip it prints 127.0.1.1
Why does this keep happening?
My device is connected to a mobile hotspot connection still the ip address remains of a local host.
I am using ubuntu 19.04 OS
The problem is that a host has multiple interfaces. It is not a problem is you use a true DNS or a carefully handwritten /etc/host file because then the system will look there to find the translation. But depending on the configuration, the host name can be bound to all the available interfaces, including the loopback one. And gethostbyname returns the address of the first of those interfaces in its own order.
To make sure of that, you should use gethostbyname_ex which returns a list of all the interfaces, and you should find the hostspot connected one, in addition to the loopback one.
How to set the source IP address for UDP multicast packages to something else than the interface IP?
I am trying to write a small router that selectively routes UDP SSDP packages from one network to another. The plan is to do it in python, although I am flexible on that.
It seems fairly easy to route SSDP NOTIFY messages: I receive them on one interface and decide which interface to re-broadcast them on. However the protocol for M-SEARCH messages require that the source IP is set to the original source of the message as any service that chooses to respond will respond with a unicast message to the source IP and port.
Example (heavily simplified):
Network A: 192.168.10.0/24
Network B: 192.168.11.0/24
My router application runs on a multihomed computer on 192.168.10.2 and 192.168.11.2.
A client on network A with IP 192.168.10.10 sends an M-SEARCH message:
Src IP/Port: 192.168.10.10 port 40000
Dst IP/Port: 239.255.255.250 port 1900
My "router application" on 192.168.10.2 receives the packet and would like to rebroadcast it on network B. However I cannot find any method in the socket API that allows me to set the source IP address. Only to pick the source interface.
Thus the rebroadcasted packet now looks like this:
Src IP/Port: 192.168.11.2 port xxxxx
Dst IP/Port: 239.255.255.250 port 1900
And now the receiving service is unable to unicast back to the client as the original IP and port are lost.
How to set the source IP address for UDP multicast packages to something else than the interface IP?
The only way I know of is to use a RAW socket and construct the IP headers manually. Note that use of RAW sockets is typically restricted to admin users on most platforms.
However I cannot find any method in the socket API that allows me to set the source IP address.
Because there isn't one.
And now the receiving service is unable to unicast back to the client as the original IP and port are lost.
Can't you just have your router remember the original source when it receives the M-SEARCH request, and when it receives the unicast reply then forward it to the original requester? That is how most routers usually work.
After allowing my raspberry pi to access port 9999 of my router socketname.bind(96.231.140.202,9999) in python gives me a cannot assign error
To port forward I used:
myfiosgateway.com/#/firewall/portforward (the same method
worked fo my apache server) and I have verified that 96.231.140.202 is my pub ip
You cannot bind to your public IP. Your router is doing that. You instead want to bind to your private IP and port forward traffic destined to 9999 to your bound IP on your pi, this address will fall into the rfc compliant private IP ranges, so it will most likely be something like 192.168.1.12 or something similar.
For example:
socketname.bind(0.0.0.0,9999) #the use of 0.0.0.0 will automatically find your available interface on that raspberry pi.
If you let me know exactly what socket library youa re using I can craft the exact code.
I recently wrote a client/server pair in python using sockets,but the problem is client doesn't connect to server on another network.I've tried port forwarding and making internal IP address static, a question which really bother's me is do i need External/Public IP address to make the client connect and if this is the case what to do when the ISP changes my External IP address. Please give some suggestions,thanks.
code:
PORT=8888
srvsock = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
srvsock.setsockopt( socket.SOL_SOCKET, socket.SO_REUSEADDR, 1 )
srvsock.bind( ('', PORT) )
srvsock.listen( 10 )
print 'server now listening on PORT '+str(PORT)
while 1:
clisock, (remhost, remport) = srvsock.accept()
dl_information_file="server.txt"
if os.path.exists(dl_information_file):
f=open('server.txt','rb')
read=f.read()
clisock.send( read )
f.close()
First of all, try to run both server and client from the same computer (connect to localhost)
If that works your problem is port forwarding related.
see: how to portforward
Are the client and server on a local network or is the client and server separated by the Internet?
If the server is running on a machine behind a NAT, you will have to do portforwarding on that and make sure that the machine's IP is static or that you update the client with the updated IP.
If the server is within your own network, you can use socket.gethostbyname(socket.getfqdn()) to get the IP of your interface (careful, you may have more than one) and use that IP to bind a socket.
You may also use WireShark to troubleshoot the connection - you can see what packets are making their way out of your client and what packets are making their way to your server.
Without further code and more information on the network, it's really hard to say any more - it could be the firewall, it could be the NAT, it could be a badly configured interface.
edit: It appears that you're binding the socket to '', which means it should be bound to the localhost port, meaning that the server listens for connections on the local loopback (127.0.0.1). This interface is not accessible to any other machine that the one which the server is running on.
You should use either a statically configured IP in a variable in your script, or that socket.gethostbyname(socket.getfqdn())).