how to limit page access to localhost in Python? - python

Using Python's SimpleHTTPServer, how can I make it so that the server only responds to requests that come from the local machine?
Is there a language-agnostic way to do this? Maybe by using a specific port that is not open to the public, or by telling the firewall not to allow access to that port from outside?
This question is similar to this one, but specific to a server written with Python's SimpleHTTPServer.

You could use the loopback interface. localhost or 127.0.0.1 refers to the local address, bypasses the full networking stack, and is not accessible via the network. See wikipedia
Take the SimpleHTTPServer example.
import SimpleHTTPServer
import SocketServer
PORT = 8000
Handler = SimpleHTTPServer.SimpleHTTPRequestHandler
httpd = SocketServer.TCPServer(("", PORT), Handler)
print "serving at port", PORT
httpd.serve_forever()
We can bind to a specific address, you could use the address assigned to your machine/interface, or in your case, the loopback device.
httpd = SocketServer.TCPServer(("127.0.0.1", PORT), Handler)
You can then access the server at http://127.0.0.1:8000/ or http://localhost:8000/. The server will not be accessible using your machines assigned IP address, both from your local machine and via the network.
The following may provide additional information
ideas on specifying bind address from command line
you might be able to programatically/dynamically filter connections by building on the example here

Related

How to allow or deny remote connections in Python's SocketServer?

I'm creating an extremely simple Vega visualization viewer: it's a one file module that serves a base HTML page containing just the Vega graphic and an HTML5 EventSource of updates. The user (me) is working in a Python shell through ssh, creates an object representing the viewer, which prints its IP and port for the user to paste into their (my) web browser. This HTTP server doesn't serve files or take input from clients, so I don't see any security concerns.
The part I'm unsure of is how to set (host, port) such that my web browser can find the HTTP server running in the remote Python. I've been experimenting all afternoon, and I don't know if I'm misunderstanding what's supposed to happen or if the servers I use have changed their access policies.
Here's a minimal example:
import SimpleHTTPServer
import SocketServer
Handler = SimpleHTTPServer.SimpleHTTPRequestHandler
httpd = SocketServer.TCPServer((host, port), Handler)
print(httpd.server_address)
httpd.serve_forever()
If I'm running this locally and want to ensure that outside viewers cannot access it, do I set host to "127.0.0.1" because that means a client would have to access it as 127.0.0.1, which can only happen locally? In this case, port can be 0 to get any open port.
If I'm running this remotely want to to ensure that outside viewers can access it, do I set host to "" or "0.0.0.0" because that means that a client can access it as any address that makes its way to the server? In this case, I might not be able to set port to 0 because many of those ports might be blocked, or is the OS smarter about this?
Basically, how is access control in Python's SocketServer supposed to work?
This is basic TCP. Nothing to do with Python.
If you listen at 127.0.0.1, only clients running in the same host can connect.
If you listen at 0.0.0.0, anybody can connect, firewalls permitting.

Sending a http get request to a server with known public ip

I have a server running by using python's base http server. The host name used is '127.0.0.1' the local host, and the port number is set to 8000. I have the public ip address of the computer operating this server.
If I wanted to send a http get request to this from another computer, what would I type into my browser?
Sounds like you've got your server process running on the wrong interface. 127.0.0.1 is not a hostname but an IP address, specifically the local loopback address. It is not reachable from any other machine (unless something's gone tragically wrong with your network configuration).
You can run anything you like on the 127.0.0.1 interface, and no one else can directly connect to it from a remote machine. That's pretty much the point --- it's for testing programs that use the Internet Protocol, and (in recent years) for starting single-user servers without worrying about security. (Python 2's SimpleHTTPServer does this, as do some personal wikis, and I think iPython Notebook.)
The public address for the host running your Web server is a completely unrelated network interface, with its own hardware and its own port 8000. It doesn't know or care that you've got something listening on some other interface's port 8000, so it should refuse attempts to connect to that port.
Since you didn't post any code, I have no idea what you need to change to get your server running on the correct interface. Assuming you've more or less followed the example in the BaseHTTPServer.HTTPServer docs:
def run(
server_class=BaseHTTPServer.HTTPServer,
handler_class=BaseHTTPServer.BaseHTTPRequestHandler,
):
server_address = ('', 8000) # <----= Replace the string.
httpd = server_class(server_address, handler_class)
httpd.serve_forever()
That server_address tuple is a string containing the IP address ('1.2.101.202' or whatever), followed by an integer port number. So replace the string with your host machine's public-facing IP address.
Note that port 8000 is outside the reserved range (0 up to but not including 1024), so it's possible that some unrelated service is already using that port. (Numerous applications are already squatting port 8000.) If so, you'll just have to choose another port number. You can chose anything from 1024 up to but not including 65536, but as with 8000, someone else might already be using it.
Depending on your operating system and its security setup, you might not have permission to open a socket that listens on an arbitrary port number. If so, that's between you and your ISP or sysadmin.
http://yourip:port/func
yourip is your public ip.
port is 8080
func is your registered function.
and also make sure you port is opened

socket.error:[errno 99] cannot assign requested address and namespace in python

My server software says errno99: cannot assign requested address while using an ip address other than 127.0.0.1 for binding.
But if the IP address is 127.0.0.1 it works.
Is it related to namespaces?
I am executing my server and client codes in another python program by calling execfile().
I am actually editing the mininet source code.I edited net.py and inside that I used execfile('server.py') execfile('client1.py') and execfile('client2.py').So as soon as "sudo mn --topo single,3" is called along with the creation of 3 hosts my server and client codes will get executed.I have given my server and client codes below.
#server code
import select
import socket
import sys
backlog = 5
size = 1024
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(("10.0.0.1",9999))
server.listen(backlog)
input = [server]
running = 1
while running:
inputready,outputready,exceptready = select.select(input,[],[])
for s in inputready:
if s == server:
client, address = server.accept()
input.append(client)
else:
l = s.recv(1024)
sys.stdout.write(l)
server.close()
#client code
import socket
import select
import sys
import time
while(1) :
s,addr=server1.accept()
data=int(s.recv(4))
s = socket.socket()
s.connect(("10.0.0.1",9999))
while (1):
f=open ("hello1.txt", "rb")
l = f.read(1024)
s.send(l)
l = f.read(1024)
time.sleep(5)
s.close()
Stripping things down to basics this is what you would want to test with:
import socket
server = socket.socket()
server.bind(("10.0.0.1", 6677))
server.listen(4)
client_socket, client_address = server.accept()
print(client_address, "has connected")
while True:
recvieved_data = client_socket.recv(1024)
print(recvieved_data)
This works assuming a few things:
Your local IP address (on the server) is 10.0.0.1 (This video shows you how)
No other software is listening on port 6677
Also note the basic concept of IP addresses:
Try the following, open the start menu, in the "search" field type cmd and press enter.
Once the black console opens up type ping www.google.com and this should give you and IP address for google. This address is googles local IP and they bind to that and obviously you can not bind to an IP address owned by google.
With that in mind, you own your own set of IP addresses.
First you have the local IP of the server, but then you have the local IP of your house.
In the below picture 192.168.1.50 is the local IP of the server which you can bind to.
You still own 83.55.102.40 but the problem is that it's owned by the Router and not your server. So even if you visit http://whatsmyip.com and that tells you that your IP is 83.55.102.40 that is not the case because it can only see where you're coming from.. and you're accessing your internet from a router.
In order for your friends to access your server (which is bound to 192.168.1.50) you need to forward port 6677 to 192.168.1.50 and this is done in your router.
Assuming you are behind one.
If you're in school there's other dilemmas and routers in the way most likely.
This error will also appear if you try to connect to an exposed port from within a Docker container, when nothing is actively serving the port.
On a host where nothing is listening/bound to that port you'd get a No connection could be made because the target machine actively refused it error instead when making a request to a local URL that is not served, eg: localhost:5000. However, if you start a container that binds to the port, but there is no server running inside of it actually serving the port, any requests to that port on localhost will result in:
[Errno 99] Cannot assign requested address (if called from within the container), or
[Errno 0] Error (if called from outside of the container).
You can reproduce this error and the behaviour described above as follows:
Start a dummy container (note: this will pull the python image if not found locally):
docker run --name serv1 -p 5000:5000 -dit python
Then for [Errno 0] Error enter a Python console on host, while for [Errno 99] Cannot assign requested address access a Python console on the container by calling:
docker exec -it -u 0 serv1 python
And then in either case call:
import urllib.request
urllib.request.urlopen('https://localhost:5000')
I concluded with treating either of these errors as equivalent to No connection could be made because the target machine actively refused it rather than trying to fix their cause - although please advise if that's a bad idea.
I've spent over a day figuring this one out, given that all resources and answers I could find on the [Errno 99] Cannot assign requested address point in the direction of binding to an occupied port, connecting to an invalid IP, sysctl conflicts, docker network issues, TIME_WAIT being incorrect, and many more things. Therefore I wanted to leave this answer here, despite not being a direct answer to the question at hand, given that it can be a common cause for the error described in this question.
Try like this:
server.bind(("0.0.0.0", 6677))
When you bind localhost or 127.0.0.1, it means you can only connect to your service from local.
You cannot bind 10.0.0.1 because it not belong to you, you can only bind ip owned by your computer
You can bind 0.0.0.0 because it means all ip on your computer, so any ip can connect to your service if they can connect to any of your ip
This is not directly answering the question, but is a debugging direction in case above solutions failed.
When you are not on a native environment, let's say you are on a VM or WSL, the inside network might not be transparent to external computer due to NATing. So make sure you can ping the IP from wherever you are trying to bind. If not, then consider switching to the correct environment or consider network bridging.
If you are looking for a WSL2 specific solution, you may try this link:
Bridging WSL2 network adapter with Windows
In Virtual Box you may change Network Adapter -> Attached To: Bridged Adapter.
The other consideration is if you are trying to bind to a port <1023 you need admin privilege.
This was what I need on a remote VM:
jupyter notebook --ip=0.0.0.0 --port=8888
Copied from here

socket programing cant connect to another network

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())).

SocketServer doesn't work on Linux

I wrote a simple python script using the SocketServer, it works well on Windows, but when I execute it on a remote Linux machine(Ubuntu), it doesn't work at all..
The script is like below:
#-*-coding:utf-8-*-
import SocketServer
class MyHandler(SocketServer.BaseRequestHandler):
def handle(self):
data_rcv = self.request.recv(1024).strip()
print data_rcv
myServer = SocketServer.ThreadingTCPServer(('127.0.0.1', 7777), MyHandler)
myServer.serve_forever()
I upload it to the remote machine by SSH, and then run the command python server.py on the remote machine, and try to access to xxx.xxx.xxx.xxx:7777/test with my browser, but nothing is printed on the remote machine's teminal...any ideas?
UPDATE: Problem solved, it's a firewall issue, thanks you all.
You are binding the server to 127.0.0.1, the IP address for localhost. This means the server will only accept connections originating from the same machine; it won't recognize ones coming from another machine.
You need to either bind to your external IP address, or bind to a wildcard address (i.e. don't bind to any particular IP address, just a port). Try:
myServer = SocketServer.ThreadingTCPServer(('0.0.0.0', 7777), MyHandler)
You are binding to 127.0.0.1:7777 but then trying to access it through the servers external IP (I'll use your placeholder - xxx.xxx.xxx.xxx). 127.0.0.1:7777 and xxx.xxx.xxx.xxx:7777 are different ports and can be bound by different processes IIRC.
If that doesn't fix it, check your firewall, many hosts set up firewalls that block everything but the handful you are likely to use
Try with telnet or nc first, telnet to your public ip with your port and see what response you get. Also, why are accessing /test from the browser? I don't see that part in the code. I hope you have taken care of that.

Categories

Resources