aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAaron LI <aaronly.me@outlook.com>2016-11-03 17:41:06 +0800
committerAaron LI <aaronly.me@outlook.com>2016-11-03 17:41:06 +0800
commit8d653b602b8e75011e031a4018625dd4ab203da0 (patch)
tree8734c90a813f42e6c418388e14d7c708f501a4d8
parenta28ad462495b2a41ce5a1c2501dab3678cf3c22f (diff)
downloadfg21sim-8d653b602b8e75011e031a4018625dd4ab203da0.tar.bz2
webui: Add "utils.py" to get the IP address
FIXME/TODO: How to determine the WebSocket origin is in the same subnet as the server? An additional network mask required to determine this. How does this additional mask passed?
-rw-r--r--fg21sim/webui/utils.py72
-rw-r--r--fg21sim/webui/websocket.py24
2 files changed, 85 insertions, 11 deletions
diff --git a/fg21sim/webui/utils.py b/fg21sim/webui/utils.py
new file mode 100644
index 0000000..1cea69f
--- /dev/null
+++ b/fg21sim/webui/utils.py
@@ -0,0 +1,72 @@
+# Copyright (c) 2016 Weitian LI <liweitianux@live.com>
+# MIT license
+
+"""
+Utilities for the Web UI
+"""
+
+
+from urllib.parse import urlparse
+import socket
+
+
+def get_host_ip(url):
+ """
+ This function parses the input URL to get the hostname (or an IP),
+ then the hostname is further resolved to its IP address.
+
+ Parameters
+ ----------
+ url : str
+ An URL string, which generally has the following format:
+ ``scheme://netloc/path;parameters?query#fragment``
+ while the ``netloc`` may look like ``user:pass@example.com:port``
+
+ Returns
+ -------
+ ip : str
+ An IPv4 address string.
+ If something wrong happens (e.g., ``gaierror``), then ``None``
+ is returned.
+ """
+ netloc = urlparse(url).netloc
+ hostname = netloc.split("@")[-1].split(":")[0]
+ try:
+ ip = socket.gethostbyname(hostname)
+ except socket.gaierror:
+ ip = None
+ return ip
+
+
+def get_local_ip(host="localhost", timeout=3.0):
+ """
+ Get the local IP address of this machine where this script runs.
+
+ A dummy socket will be created and connects to the given host, then
+ the valid local IP address used in this connection can be obtained.
+
+ Parameters
+ ----------
+ host : str
+ The host to which will be connected by a dummy socket, in order
+ to determine the valid IP address.
+ timeout : float
+ Timeout (in seconds) on the blocking socket operations (e.g.,
+ ``connect()``)
+
+ Returns
+ -------
+ ip : str
+ The local IPv4 address of this machine as a string.
+ If something wrong happens (e.g., ``gaierror``), then ``None``
+ is returned.
+ """
+ with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
+ try:
+ s.settimeout(timeout)
+ # Use 0 as the port will let OS determine the free port
+ s.connect((host, 0))
+ ip = s.getsockname()[0]
+ except (socket.gaierror, socket.timeout):
+ ip = None
+ return ip
diff --git a/fg21sim/webui/websocket.py b/fg21sim/webui/websocket.py
index 5b9d5ea..0677f83 100644
--- a/fg21sim/webui/websocket.py
+++ b/fg21sim/webui/websocket.py
@@ -17,11 +17,12 @@ References
http://caniuse.com/#feat=websockets
"""
-from urllib.parse import urlparse
import logging
import tornado.websocket
+from .utils import get_host_ip
+
logger = logging.getLogger(__name__)
@@ -63,6 +64,7 @@ class FG21simWSHandler(tornado.websocket.WebSocketHandler):
def on_close(self):
"""Invoked when a new WebSocket is closed by the client."""
+ code, reason = None, None
if hasattr(self, "close_code"):
code = self.close_code
if hasattr(self, "close_reason"):
@@ -84,15 +86,15 @@ class FG21simWSHandler(tornado.websocket.WebSocketHandler):
Currently, only allow access from the ``localhost``
(i.e., 127.0.0.1) and local LAN.
"""
- logger.info("WebSocket: {0}: access origin: {1}".format(
- self.name, origin))
- # NOTE: `urlparse`: `scheme://netloc/path;parameters?query#fragment`
- netloc = urlparse(origin).netloc
- # NOTE: `netloc` example: `user:pass@example.com:8080`
- host = netloc.split("@")[-1].split(":")[0]
- if host in ["localhost", "127.0.0.1"]:
+ logger.info("WebSocket: {0}: origin: {1}".format(self.name, origin))
+ ip = get_host_ip(url=origin)
+ if ip == "127.0.0.1":
self.from_localhost = True
- logger.info("WebSocket: %s: access from localhost" % self.name)
+ logger.info("WebSocket: %s: origin is localhost" % self.name)
return True
- # XXX/TODO: check whether from the local LAN ??
- return False
+ else:
+ self.from_localhost = False
+ # FIXME/TODO: check whether from local LAN (or in same subnet)??
+ logger.error("WebSocket: %s: " % self.name +
+ "ONLY allow access from localhost at the moment :(")
+ return False