How to access Flask app from other networks? [duplicate] - python

This question already has answers here:
Configure Flask dev server to be visible across the network
(17 answers)
Closed 5 years ago.
I am trying to create a Flask app (using Python 2.7) that I can access from across networks, as the title says. I have managed to get the app up and running, and it works successfully all across the Wi-Fi network of my computer where the app is running. I have been accessing it using my internal IP address and port 8000. Whenever I connect from my phone, which is connected to the Wi-Fi, it works. However, when I switch to cellular data and connect from that, it doesn't work, and instead says "took too long to respond". The code for the app itself is as follows:
from flask import Flask, render_template
from GradeScraper import scrapeforgrades
app = Flask(__name__)
#app.route('/')
def home():
scrapeforgrades()
return render_template("Grades.html")
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8000, debug=True)
GradeScraper is just a web scraper I have written, to be called in the app. I don't believe that file is the reason for my problems.
I have also tried connecting to the app from my external IP address, but it says "refused to connect". I went to this StackOverflow page I found, and the answer said something about security settings. I didn't understand at all how to change those. The person who asked the question commented at the end "I played around with security settings and finally got it working" which leads me to the conclusion that I should do the same. Unfortunately, I have no idea how to do that. Could anybody point me in the right direction? I'll provide any and all extra information needed.
Thanks,
Me

For a start probably (hopefully!) your router is blocking all incoming connections; even if it didn't, your computer's "internal IP Address" (the one you connect to via WiFi) is not only unreachable from outside your network, but also unroutable (in other words, your cellular's operator network has no idea how to find it).
You should look for a NAT (network Address translation) function in your router, pick an external port (any port will do - I recommend one above 1024) and map that port to your computer's IP address, port 8000.
IF you don't know what you're doing, that is however A Really Bad Idea - you will be immediately targeted by port scanners looking for vulnerabilities.
To expand on the topic...
your Computer's IP will be something like 192.168.1.101, while your router may be something like 192.168.1.1 - the 192.168/16 space is deemed a "private IP space" and unroutable from the "public IP" space (the one where all external services live - for example, from my location, google.com maps to 172.17.6.46.
Your phone has two radios (and thus, logically, not physically, 2 NICs): the WiFi (which will get an address from the DHCP server in your router: something like 192.168.1.102) and the LTE/4G radio (which will have an IP address of choice from your provider - something like 174.94.66.23, or, possibly, an IPv6): the former can get to your local server, but the latter can't.
Your ISP will have assigned to your router's WAN port one of these "public IPs" form its pool (they usually rotate them, unless you paid for a static IP address) - that one is what you need to find out (http://formyip.com being the easiest way) and then point to it from your phone (or an external computer or whatever).
The matter is complicated and, as mentioned, dangerous for the novice - educate yourself about routing and NAT: just be aware that opening up your network and keeping a server running on the public network is pretty scary stuff these days (I wouldn't do it, and I used to be at Google and I am now with another "large well-known" corporation :)
Alternatively, if your router allows, you could setup an OpenVPN connection: that is more secure, but an altogether other level of complexity.
Hope this helps.

Related

Use python to naively find an Arduino's IP address from another PC on the local network

I have a ESP8266 Nodemcu device running a local HTTP server. I followed the quick-start instructions here.
My goal is to have a large number of these devices running in sync. To do that, I wrote this script:
#!/usr/bin/env python
import time
import sys
import socket
import requests
def myFunction():
#This is what I have right now...
ipAddresses = ["192.168.1.43", "192.168.1.44"]
#
#Instead, I need to search the local network for all the arduinos [ESP8266s] and append their address to the array.
#
for address in ipAddresses:
TurnOnLED(address)
def TurnOnLED(address):
try:
r = requests.post('http://' + address + '/LedON')
r.close()
except requests.exceptions.ConnectionError:
pass
#Main
def Main():
try:
print("Press CTRL-C to stop.")
while ON:
myFunction()
time.sleep(60)
except KeyboardInterrupt:
sys.exit(0)
if __name__ == "__main__":
Main()
This works, and allows me to control all of my devices from my desktop PC. My difficulty is with finding each IP address dynamically. I considered assigning a static IP address, but I would like them to be retail-optimized, so I cannot guarantee any particular IP address being unused out-of-the-box.
For the same reason, I want to be able to install the same arduino code on all of them. This is what I mean by naive. I want my python script to find the IP address of each device over the local network without any [unique] 'help' from the devices themselves. I want to install the same code on each device, and have my script find them all without any additional set up.
My first attempt was using the socket python module and looking for every hostname that began with "ESP-" since those are the first four characters of the factory hostname on all the boards. My query consistently turned up nothing, though.
This answer here has some good information, but my solution runs on a Macintosh, and I will not have the full host name, only "ESP-".
So, now that I know what are the constraints, and what is just what is in the tutorial, here are my 2 cents (keep in mind that I too, am just a hobbyist about everything that has "voltage". And not even a good one).
1st strategy : PC is server
So, if I assume that your devices are, for example, temperature sensors, and you want to frequently grab all the temperatures, then, one strategy could be that those devices all connect, every minute, to the server, report the temperature, and disconnect. For example, using a HTTPS request to do so.
So host the server on your PC, and have your devices behave as clients
# Example request from micropython
import urequests
rep = urequests.get(URL)
print(rep.text)
response.close()
2nd strategy : a third party is server
A variant of that strategy is to have a sort of central data repository, that acts as a server. So, I mean, your PC is not the server, nor any ESP, but another machine (which could be one ESP, a rasppi, or even a droplet or EC2 instance in the cloud, doesn't matter. As long as you can host a backend on it).
So, ESP8266 are clients of that server. And so is your PC. So that server has to be able to answer to request "set value from client", and "get value for the PC".
The drawback of those first 2 strategies, is that they are ok when the devices are the one sending data. It fits less if they are (as in your led example, but I surmise that was just an example) the ones receiving mostly the data. Because then, you would have to wait for the ESP to connect to have it get the message "you need to switch on the led".
3rd strategy : central registry
Or you can have it both way. That is keep your current architecture. When your PC wants something from the ESP8266, it has to connect to them, that are servers, and send it request.
But, in parallel to that, ESP8266 also behave as clients to register themselves in a central directory, which could be on the PC, or on a 3rd party. The objective of that central directory is not to gather the data from the ESP8266. Just to gather a uptodate list of them. Each minute they, in parallel with their server activity, the ESP8266 send a message "I am alive" to this central dircetory. And then the PC (that could be, or not, hosting that central directory) just need to get all IP associated with a not too old "I am alive" message, to get a list of IP.
4th strategy : ARP
Once your PC is on, it could scan the network, using an ARP request, with scapy. Search for "scanning local network with scapy".
For example here is a tutorial
From there, you get a list of IP. Associated with MAC address. And now, you need to know which ones are the ESP8266. You can here also apply several ideas. For example, you may use the MAC address to find guess which one are the ESP8266. Or you may simply try a dummy request on all found IP, to check which one are the ESP8266 (using a specific API of the server code of the ESP8266 you wrote)
Or you may decide to host the server on each ESP8266 on a specific port, like 8123, so that you can quickly rule out devices whose port 8123 is not listening.
5th strategy : don't reinvent the wheel
The best strategy is clearly a mix between my second and my third. Having a directory, and a 3rd party handling messages. But that is reinventing message brokers.
There is one well known middleware, fitted for ESP8266 (I mean, for IoT low profile devices), that is MQTT.
That needs some more tutorial reading and long trial and error on your behalf. You can start here for example. But that is just the 1st example I found on Google searching "MQTT ESP8266 micropython". There are zillions resources on that.
It may seem to be not the easiest way (compared to just copy and paste some code that list all the alive IP on a network). But in the long run, I you intend to have many ESP8266, so many of them that you can't afford to assign them static IP and simply list their IP, you probably really need a message broker like that, a preferably, not one that your reinvent

What would be the best way to transmit data from one python script to another, without them being on the same computer?

I am attempting to create a basic chatroom in python, and I would like to know how I could transmit data from one script to another, preferably without using google drive. If needed to, I could create a webserver on Replit, but I don't do well with HTML or PHP.
Side note: I can't port forward, as my google wifi doesn't accept any level of port forwarding.
I would send messages of about 50 characters every couple seconds
Since you mention port forwarding, I assume you want two chat clients that run on different local networks to talk to each other, for example your own and the chat client of a friend in a remote location, over the internet.
If you (or your counterpart) cannot set up port forwarding, then direct communication between the script on your computer and theirs is hard, if not impossible. The solution is to set up a third computer or service on the internet that can be reached by both clients and use it for relaying messages between them.
A network is typically protected by a firewall of sorts and will typically be behind a router that performs network address translation (NAT) to help multiple devices on a network to simultaneously access services on the internet, whilst all using the same IP address on the internet. Port forwarding fits into that by connecting a specific port from the outside directly to a port on a machine on the inside - without that, an outside computer might be able to reach your IP address, but they could never connect to a computer or program on the inside of the network, as the router wouldn't know what computer to contact, also the firewall might disallow the connection to begin with.
But if your computer on the inside establishes a connection with an accessible server on the internet, expecting a response, that creates a temporary conduit through the router and firewall that can be used by the server to send messages (look up 'hole punching' for more information). And if both computers do this, the server can relay message between both clients. Only the server then needs to run in an environment that doesn't have firewall restrictions or NAT that prevent this.
You could write a simple Python server, that accepts incoming connections and can send several responses and a simple client that connects to it, identifying itself and joining a chatroom, or having a direct conversation with another connected client. There are many techniques that would allow you to do this, but I think web sockets might be a good starting point, as long as you don't plan to do advanced fast or high volume stuff that would require something like a UDP connection.
A library like websockets could be a good starting point, but you may want to start out by figuring out where you would have this service hosted first, since there may be limitations on what you're able and allowed to do.
Also, if all you're looking to do is send simple messages, you may want to stay away from writing your own server an protocols at all - have a look around for open source message servers written in a language you are comfortable with, or that just work out of the box without any development, in which case the language doesn't even really matter, as long as you can connect to it and exchange messages from Python.

Isn't it dangerous to run a Flask app in debug mode on 0.0.0.0?

Configure Flask dev server to be visible across the network
Meaning it runs on my PC's IP address visible to the entire internet and arbitrary Python code can be run via my Flask app?
The direct answer is: yes, it is unsafe. But then again, so is driving a car or eating at a new restaurant with bad reviews.
The point is evaluating the risk. Things to consider:
Are you launching this on a home network? In which case, your router almost certainly comes with its own firewall (and I only don't make the assertion because I can't possibly cover every single case). The server will not be accessible outside of the home network. Maybe there's a malicious housemate harbouring resent and waiting to pounce?
Are you launching on an intranet network? This would be accessible to everyone on the network. The vast majority of people won't be scanning the network for open ports, but you can't rule it out. Low risk., but it could happen that someone finds it.
Are you running this on a server with a dedicated IP (not an internal IP like 10.0.0.x or 192.168.x.x)? Is the particular port you're running on open to the wider internet e.g. no firewall or special rules for that port? In which case, expect to get requests.
Can someone landing on the site actually do something malicious? The whole point of having a web server is for other people to access it. If discovering your app is enough to be a real concern then it's just broken and you should be testing your fears on localhost.

I have get really confused in IP types with sockets (empty string, 'local host', etc...)

Im using python.
I dont understand the purpose of empty string in IP to connect to if its not to connect between two Computers in the same LAN router.
My knowledge in network is close to zero, so when I reading in the internet somthing like this:
empty string represents INADDR_ANY, and the string ''
represents INADDR_BROADCAST
So if you please will be able to explain me, like you explain to a baby that dont know nothing - what is the purpose of any of the follows in the IP location in socket object:
broadcast
''
localhost
and if there is more, so I will be glad to know about them too. Tanks.
'localhost' (or '127.0.0.1') is used to connect with program on the same computer - ie. database viewer <-> local database server, Doom client <-> local Doom server. This way you don't have to write different method to connect to local server.
Computer can have more then one network card (NIC) and every NIC has own IP address. You can use this IP in program and then program will use only this one NIC to receive requests/connections. This way you may have server which receives requests only from LAN but not from Internet - it is very popular for databases used by web servers.
Empty string means '0.0.0.0' which means that program will receive requests from all NICs.

Python port forwarding

I'm developing a client-server game in python and I want to know more about port forwarding.
What I'm doing for instance is going to my router (192.168.0.1) and configure it to allow request for my real IP-adress to be redirected to my local adress 192.168.0.X. It works really well. But I'm wondering if I can do it by coding something automatically ?
I think skype works like a kind of p2p and I can see in my router that skype is automatically port forwarded to my pc adress. Can I do it in Python too?
There are different solutions here, but most are not trivial, and you'll have to do some reading, and you'll need some kind of fallback.
UPnP/IGD is the simplest. If your router supports it, and is configured to allow it, and you know how to write either low-level networking code or old-fashioned SOAP web service code, you can ask the router to assign you a port. If it responds with success, start using that port and you're basically done.
If you can run a (very low-bandwidth) server with a public address for all of your users, Hole punching may solve the problem.
Think about how a behind-the-NAT client talks to a public server. You make a request to some IP and port, but the server is seeing your router's IP, not yours (which is a good thing, because yours isn't accessible). When it replies, your router has to know to forward it to you—which it does just by remembering that you're the behind-the-NAT client that just sent a request to that server.
What if, instead of talking to a public server, you talk to some other peer behind his own separate NAT? Well, Your router doesn't know the difference; as long as you get a response from the same place, it'll get through. But how do you get a response, when your message isn't going to get through his NAT? He does the same thing, of course. One of the messages may get lost, but the other one will get through, and then you're both set and can communicate. You will need to send keep-alives regularly so the router doesn't forget you were communicating, but other than that, there's really nothing tricky.
The only problem is that you need to know the public IP address for the other peer, and the port that he's expecting you to come from, and he needs to know the same about you. That's why you need a server—to act as an introducer between peers.
Hole punching will work with UDP from most home networks. It won't work with TCP from many home networks, or with either UDP or TCP from many corporate networks. (Also, in corporate networks, you may have multiple layers of NATs, which means you need introducers at every interface rather than just one on the internet, or symmetric NATs, which can't be punched.)
You can use STUN (or similar) services like ICE or TURN. This only works if there is an ICE, TURN, etc. service to use—which is generally not the case for two peers on different home NATs, unless you deploy your own server and build an introducer to help out, and if you're going to do that, you can just use hole punching. But in a corporate environment, this can be the best way to provide connectivity for P2P apps.
Finally, you can make the user configure port-forwarding manually and enter the forwarded port number into your problem. This is not ideal, but you should always provide it as a fallback (except maybe for apps meant only for corporate deployment), because nothing else is going to work for all of your users.
I believe Skype uses all of these. If you enable UPnP, it tries to IGD your router. Or you can configure it to use a TURN server. Or you can just enter a specific port that you've forwarded manually. If you do none of the above, it tries to use UDP hole punching, with an introducer that Skype runs.
So your application needs to do TCP/UDP networking if I understand correctly. That means that at least one of the connecting clients needs a properly open port, and if both of them is behind NAT (a router) and have no configured open ports, your clients cannot connect.
There are several possible solutions for this, but not all are reliable: UPnP, as suggested here, can open ports on demand but isn't supported (or enabled) on all routers (and it is a security threat), and P2P solutions are complex and still require open ports on some clients.
The only reliable solution is to have a dedicated server that all clients can connect to that will negotiate the connections, and possibly proxy between them.
You could look at something like this (assuming your router supports it): http://en.wikipedia.org/wiki/Universal_Plug_and_Play#NAT_traversal
For implementing port forwarding using python, there's a fantastic ActriveState recipe that does asynchronous port forwarding server using only Python standard library (socket, syncope). Look at
http://code.activestate.com/recipes/483732-asynchronous-port-forwarding/

Categories

Resources