Is it possible to run python SimpleHTTPServer on localhost only? - python

I have a vpn connection and when I'm running python -m SimpleHTTPServer, it serves on 0.0.0.0:8000, which means it can be accessed via localhost and via my real ip.
I don't want robots to scan me and interested that the server will be accessed only via localhost.
Is it possible?
python -m SimpleHTTPServer 127.0.0.1:8000 # doesn't work.
Any other simple http server which can be executed instantly using the command line is also welcome.

In Python versions 3.4 and higher, the http.server module accepts a bind parameter.
According to the docs:
python -m http.server 8000
By default, server binds itself to all interfaces. The option
-b/--bind specifies a specific address to which it should bind. For example, the following command causes the server to bind to localhost
only:
python -m http.server 8000 --bind 127.0.0.1
New in version 3.4: --bind argument was introduced.

As #sberry explained, simply doing it by using the nice python -m ... method won't be possible, because the IP address is hardcoded in the implementation of the BaseHttpServer.test function.
A way of doing it from the command line without writing code to a file first would be
python -c 'import BaseHTTPServer as bhs, SimpleHTTPServer as shs; bhs.HTTPServer(("127.0.0.1", 8888), shs.SimpleHTTPRequestHandler).serve_forever()'
If that still counts as a one liner depends on your terminal width ;-) It's certainly not very easy to remember.

If you read the source you will see that only the port can be overridden on the command line. If you want to change the host it is served on, you will need to implement the test() method of the SimpleHTTPServer and BaseHTTPServer yourself. But that should be really easy.
Here is how you can do it, pretty easily:
import sys
from SimpleHTTPServer import SimpleHTTPRequestHandler
import BaseHTTPServer
def test(HandlerClass=SimpleHTTPRequestHandler,
ServerClass=BaseHTTPServer.HTTPServer):
protocol = "HTTP/1.0"
host = ''
port = 8000
if len(sys.argv) > 1:
arg = sys.argv[1]
if ':' in arg:
host, port = arg.split(':')
port = int(port)
else:
try:
port = int(sys.argv[1])
except:
host = sys.argv[1]
server_address = (host, port)
HandlerClass.protocol_version = protocol
httpd = ServerClass(server_address, HandlerClass)
sa = httpd.socket.getsockname()
print "Serving HTTP on", sa[0], "port", sa[1], "..."
httpd.serve_forever()
if __name__ == "__main__":
test()
And to use it:
> python server.py 127.0.0.1
Serving HTTP on 127.0.0.1 port 8000 ...
> python server.py 127.0.0.1:9000
Serving HTTP on 127.0.0.1 port 9000 ...
> python server.py 8080
Serving HTTP on 0.0.0.0 port 8080 ...

Related

Python -m http.server 443 -- with SSL?

Is it possible to create a temporary Python3 HTTP server with an SSL certificate? For example:
$ python3 -m http.server 443 --certificate /path/to/cert
Not from the command line, but it's pretty straightforward to write a simple script to do so.
from http.server import HTTPServer, BaseHTTPRequestHandler
import ssl
httpd = HTTPServer(('localhost', 4443), BaseHTTPRequestHandler)
httpd.socket = ssl.wrap_socket(
httpd.socket,
keyfile="path/to/key.pem",
certfile='path/to/cert.pem',
server_side=True)
httpd.serve_forever()
Credit
If you are not restricted to the standard library and can install pip packages, there are also a number of other options, for example you can install uwsgi, which accepts command line options.
Actually no, but there is an implementation that uses the same package with ssl.
You should try it.
The script is written using Python 2 but it is pretty easy to implement again with Python 3 since it is 5 lines.
The http.server is the Python 3 is the equivalent to SimpleHTTPServer from Python 2.
import BaseHTTPServer, SimpleHTTPServer
import ssl
httpd = BaseHTTPServer.HTTPServer(('localhost', 4443), SimpleHTTPServer.SimpleHTTPRequestHandler)
httpd.socket = ssl.wrap_socket (httpd.socket, certfile='./server.pem', server_side=True)
httpd.serve_forever()
Script credits to dergachev
Here is what you are looking for.
# WEBSERVER with SSL support
# Create certificate files ca_key.pem and ca_cert.pem and they should be in the same folder
# Output when client connects:
# Web Server at => 192.168.1.100:4443
# 192.168.1.22 - - [12/Feb/2022 02:32:56] "GET /default.html HTTP/1.1" 200 -
import http.server
import ssl
HOST = '192.168.1.100'
PORT = 4443
Handler = http.server.SimpleHTTPRequestHandler
with http.server.HTTPServer((HOST, PORT), Handler) as httpd:
print("Web Server listening at => " + HOST + ":" + str(PORT))
sslcontext = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
sslcontext.load_cert_chain(keyfile="ca_key.pem", certfile="ca_cert.pem")
httpd.socket = sslcontext.wrap_socket(httpd.socket, server_side=True)
httpd.serve_forever()

Host command and ifconfig giving different ips

I am using server(server_name.corp.com) inside a corporate company. On the server i am running a flask server to listen on 0.0.0.0:5000.
servers are not exposed to outside world but accessible via vpns.
Now when i run host server_name.corp.com in the box i get some ip1(10.*.*.*)
When i run ifconfig in the box it gives me ip2(10.*.*.*).
Also if i run ping server_name.corp.com in same box i get ip2.
Also i can ssh into server with ip1 not ip2
I am able to access the flask server at ip1:5000 but not on ip2:5000.
I am not into networking so fully confused on why there are 2 different ips and why i can access ip1:5000 from browser not ip2:5000.
Also what is equivalent of host command in python ( how to get ip1 from python. I am using socktet.gethostbyname(server_name.corp.com) which gives me ip2)
As far as I can tell, you have some kind of routing configured that allows external connections to the server by hostname (or ip1), but it does not allow connection by ip2. And there is nothing unusual in this. Probably, the system administrator can advise why it is done just like this. Assuming that there are no assynchronous network routes, the following function can help to determine public ip of server:
import socket
def get_ip():
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.connect(("8.8.8.8", 80))
local_address = sock.getsockname()
sock.close()
local_address = local_address[0]
except OSError:
local_address = socket.gethostbyname(socket.gethostname())
return local_address
Not quite clear about the network status by your statements, I can only tell that if you want to get ip1 by python, you could use standard lib subprocess, which usually be used to execute os command. (See subprocess.Popen)

building a server, telnet localhost 8888 showing blank screen

so I'm trying to get through this tutorial here .
I started by running the code in a file here:
import socket
HOST, PORT = '', 8888
listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
listen_socket.bind((HOST, PORT))
listen_socket.listen(1)
print('Serving HTTP on port %s ...' % PORT)
while True:
client_connection, client_address = listen_socket.accept()
request = client_connection.recv(1024)
print(request.decode('utf-8'))
http_response = """\
HTTP/1.1 200 OK
Hello, World!
"""
client_connection.sendall(bytes(http_response, 'utf-8'))
client_connection.close()
then in the next part, it tells me to enter this line on the same computer.
$ telnet localhost 8888
I have webserver1.py running on a different cmd window (in windows). when I run this line though I get a blank screen instead of
$ telnet localhost 8888
Trying 127.0.0.1 …
Connected to localhost.
like I'm supposed to. Does anyone know why? How to fix it? I tried googling telnet localhost 8888 to no avail, I couldn't find a situation where this happened before.
so uh... unless there's an http daemon running/listening on that port, which couldn't happen anyway because of how ports typically work (but not always), that's actually about as far as that exercise will go.
The result you had was correct, based on the output you got after running telnet from another cmd session while that python script was running in the background. However, the windows oobe version of telnet is weaksauce. Using it to send additional commands to communicate with the server once a successful connection is established is kinda booty.
The script invokes the python interpreter (shoulda used #!/usr/bin/env python... just saying) and uses a few objects from the socket lib to open a socket on port 8888 on the localhost (the computer you're currently logged into).
That's it, nothing more. I ran through the exercise too, and gisted it # https://gist.github.com/mackmoe/09de098b3df5c45adf7a17b764a1eec4
Just my 2 cents here:
If you want to setup a server for the experience (and for free), just grab virtualbox, a linux server iso and use one of digital ocean's walkthroughs. Like the one # https://www.digitalocean.com/community/tutorials/how-to-install-linux-apache-mysql-php-lamp-stack-on-ubuntu-16-04
Hope That Helps Friend!

Python's SocketServer won''t handshake

The problem
I am trying to use the SocketServer that ships with Python but I have some issues in the handshake phase. The handshake works fine as long as I use localhost or 127.0.0.1. However when I put the IP of my eth0 card it just won't handshake. I test the official example code found here:
import SocketServer
class MyTCPHandler(SocketServer.BaseRequestHandler):
def handle(self):
self.data = self.request.recv(1024).strip()
print "{} wrote:".format(self.client_address[0])
print self.data
self.request.sendall(self.data.upper())
if __name__ == "__main__":
HOST, PORT = "localhost", 9999
server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler)
server.serve_forever()
Terminal snippet:
manos#box:~$ netcat 10.2.203.26 9999
manos#box:~$
manos#box:~$ netcat localhost 9999
test
As you see in the snippet, trying to connect to 10.2.293.26 which is the IP of my network card doesn't work. As soon as I try to connect to localhost, it works fine!
On Wireshark I get a [RST, ACK] after the first SYN being sent from the client to the server (in the initial handshake phase).
Works fine with telnet
My first guess was that this was a router resetting the connection. However that is not the case since I can telnet fine:
Terminal 1:
manos#box:~/tmp/test$ netcat -l 9999
(waiting)
test
Terminal 2:
manos#box:~$ netcat 10.2.203.26 9999
test
You're binding to localhost, which doesn't allow specifying the IP address/es of the machine's interface/s as the destination on the connecting host.
You should specify 0.0.0.0 or the empty string as the machine's address in the bind operation (the HOST argument in your example) in order to allow the remote host to specify any of the machine's IP addresses as the destination.
For more information about the difference between localhost, 127.0.0.1 and 0.0.0.0 refer to this answer or to this one.

Python socket on Windows 7 is not accessible from another machine

I'm trying to create a Python program that will listen on a socket. I'm using Windows 7 with Python 2.7. Whatever I do, the socket seems to be accessible from the local machine but not from elsewhere on the network.
I've got the following code:
from werkzeug.wrappers import Request, Response
#Request.application
def application(request):
return Response('Hello World!')
if __name__ == '__main__':
from werkzeug.serving import run_simple
# Using empty string or the machine's real IP address here
# gives the same problem
run_simple('0.0.0.0', 4000, application)
If I connect from the local machine I see the response fine. If I execute
$ curl 'http://192.168.1.1:4000/'
from another (linux) box on the network, the curl hangs for a long time before timing out. Wireshark shows that I receive a SYN packet to port 4000 but don't see it ACKed.
I've tried making sure packets to this port are allowed through the firewall (the fact that I see the SYNs in Wireshark suggests this is not the problem). I've tried setting Python to run as administrator (and I've checked that ctypes.windll.shell32.IsUserAnAdmin() returns true). This isn't just Werkzeug, I've tried with SocketServer from the Python standard library as well.
Running Windows Apache on the same port works fine from across the network, which suggests there's no problem with the network or firewall or with my curl request.
netstat -an shows:
TCP 0.0.0.0:4000 0.0.0.0:0 LISTENING
Edit: I've tried with the following minimal code. On the server side (Windows 7):
import socket
s = socket.socket()
s.bind(('', 8080))
s.listen(1)
remotesock, addr = s.accept()
And on the linux client:
import socket
s = socket.socket()
s.connect('192.168.1.1', 8080)
This hangs until timeout, as with the curl.
I believe the problem is due to your address binding. Python does not allow sockets bound to localhost (or 0.0.0.0) to be visible from the outside world. Change the binding to your actual IP Address.
EDIT: Showing example code
Change your code to this
import socket
s = socket.socket()
s.bind(('192.168.1.1', 8080)) # assumes your machine's IP address is 192.168.1.1
s.listen(1)
remotesock, addr = s.accept()

Categories