I'm developing a simple Flask based server that can communicate with peer applications (other similar servers) on internet. The application can be behind a NAT. So I'm trying to resolve the external IP and port through a stun server by using pystun.
import stun
nat_type,external_ip,external_port=stun.get_ip_info()
The port returned is 54320. Problem is when I try http://external_ip:54320 the request is not reaching the Flask app. http://external_ip:5000 is also not working, 5000 being the internal port used (I know this should not work, but tried it anyways). There are no firewalls. I have run Flask with host="0.0.0.0".
to add.. i dont want to do explicit port mapping in the router.. is there a way flask can listen to a port that is accessible from external addresses and figure out external port through stun?
It is very difficult to host a server behind a NAT without doing an explicit port mapping. The NAT is also acting as a firewall. The node behind the NAT can make outbound TCP connections, but the NAT will block any inbound connections.
STUN doesn't help here because it only helps nodes behind NATs discover their own port mappings. To allow connection to be established after STUN, you typically have to do a hole punching step, which involves both endpoints simultaneously trying to connect to each other.
The one idea you could try is to use UPNP, which is a protocol that many NATs support for dynamically creating port mappings. There's some opens source libraries that might work.
But the easier solution is to just configure your NAT to have an explicitly port mapping. (e.g. port 50000 maps to your PC's internal IP address at a specific port).
Related
I have a raspberry pi, which is setup as a audio streaming server. I have used websockets and python as programming language. The client can listen to the live audio stream by connecting to the server hosted on raspberry pi. The system works well in localhost environment. Now, I want to access the server from the internet and by searching I got to know about STUN. I tried to use pystun but I couldn't get the proper port for NAT punching. So can anyone help me to implement STUN?
Note: server is listening at localhost:8000
Just Googling for STUN Python resulted in this:
https://pypi.python.org/pypi/pystun
Go to the bottom of that page and you'll find a link to the source code. Unpack it and the core STUN code is in the __init__.py file.
Back to your audio server. If it's a true client/server protocol and using only a single port for all communications, you don't need STUN per se. You just need to open a port on your NAT such that any client from the outside world can connect. If the protocol is more complicated (ports are dynamically negotiated in a peer to peer style), then you will need something like STUN on top of a signaling protocol service that is directly connected to the Internet.
NAT punching is used for peer-to-peer (P2P) communication and your audio streaming server seems to be a client-server implementation.
How and if this is going to work heavily depends on your NAT device (which kind of NAT is implemented). Chances are high that your NAT device has short timeouts and you need to punch holes for every client connection (from your raspberry pi).
As you stated you're using WebSockets and these are always TCP, pystun isn't going to work because pystun only supports UDP.
I'd suggest to create a port forwarding in your NAT device, tunnel your traffic using a P2P VPN or host your audio streaming server on a different network.
I am hosting a http server on Python using BaseHTTPServer module.
I want to understand why it's required to specify the IP on which you are hosting the http server, like 127.0.0.1/192.168.0.1 or whatever. [might be a general http server concept, and not specific to Python]
Why can't it be like anybody who knows the IP of the machine could connect to the http server?
I face problems in case when my http server is connected to two networks at the same time, and I want to serve the http server on both the networks. And often my IP changes on-the-fly when I switch from hotspot mode on the http server machine, to connecting to another wifi router.
You must specify the IP address of the server, mainly because the underlying system calls for listening on a socket requires it. At a lower level you declare what pair (IP address, port) you want to use, listen on it and accept incoming connexions.
Another reason is that professional grade server often have multiple network interfaces and multiple IP addresses, and some services only need to listen on some interface addresses.
Hopefully, there are special addresses:
localhost or 127.0.0.1 is the loopback address, only accessible from local machine. It is currently used for tests of local services
0.0.0.0 (any) is a special address used to declare that you want to listen to all the local interfaces. I think that it is what you want here.
Try running it on 0.0.0.0, this accepts connections from all interfaces. Explicitly specifying the IP is a good practice in general (load balancing, caching servers, security, internal netwrok-only micro services, etc), but judging by your story this is not a production server, but some internal LAN application.
I want to build a peer to peer chat engine that runs over the Internet. So far my code works on a local network but not further. This is due to the fact that listening on sockets using python sockets does not make them available outside of the LAN.
It is acceptable for IPs to be shared knowledge, ie it is ok for the other person to need to know my IP address (and a port on which I am listening) to connect to me.
How does one tell the router to open a socket to the outside world? Presumably this can be done as p2p software such as BitTorrent must do it for communication between clients.
As you have mentioned you have to open a specific port on the router and use that port for communication. As there are many router manufacturers each with a variety of models I suggest you to check the manual for the router you want to use.
for the code, you may check if your code works on LAN and then see if the router let's you white-list some ports. you may find many simple examples online.
this is a code i played sometime ago:
http://www.mediafire.com/download/vef4q4prkr7be2e/python.socket.zip
if you don't want users to mess up with ports and router settings and such, first alternative i can think of is this:
you setup an REST API, in one interface one is able to retrieve the messages providing (chatRoomName, FromTimestamp, ToTimestamp[,optionally chatRoomPassWord]) but this has nothing to do with sockets, you have to use simple HTTP requests(urllib/urllib2). Of course there might exist some workaround for this such as an always-white-listed port(like 80 for browsers, 22 for SSH) but you have to search for such exceptions.
note that ports up to 1024 require special privileges(admin/sudo) to be used.
p.s. in traditional implementation other party(client) have to know your (ip, port) duo to be able to connect to the you(server).
My server has 3 ip addresses, 127.0.0.1, 192.168.0.100 and an internet ip address. I'm going to run a service written by python on this server, but I don't want it to expose on internet.
I'm using BaseHTTPRequestHandler class to implement this service, so how to bind only 127.0.0.1 and 192.168.0.100 but not the other one?
Generally, routers have an option where you can allow servers to be visible or not visible. If on the router you set you server to not be visible, then your server will not be accessible through the internet.
I think you have two choices.
1) Listen to all interfaces, but override BaseHTTPRequestHandler.init to check the client address and drop the connection if it comes from an undesired interface
2) Create multiple sockets, one per address you want to listen on. SocketServer.serve_forever() is blocking, so you will either need to use one thread per address or switch to a more sophisticated framework like twisted.
I am building python p2p application like p2p instant messenger. I am communicating with other peers using TCP/IP connection. I do not want client to do port forwarding.
When application starts it should check whether port is forwarded to router if not it should forward it to router.
Is it possible to programaticaly forward the port to router. Or how can I use port 80 for p2p communication as its used by browsers.
You may find the post and files listed here helpful. This person implemented a Nat PMP library in Python.
http://blog.yimingliu.com/2008/01/07/nat-pmp-client-library-for-python/
If you want to use port 80 for p2p communication, you will simply just need to write your own protocol in HTTP and connect over port 80.