aboutsummaryrefslogtreecommitdiffstats
path: root/fg21sim/webui/utils.py
blob: bf62525bc3123619088261dd01779395b2b1edb3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# Copyright (c) 2016 Weitian LI <liweitianux@live.com>
# MIT license

"""
Utilities for the Web UI
------------------------

get_host_ip :
    Get the IP address of the host extracted from the input URL.

get_local_ip :
    Get the local IP address of this machine.

ip_in_network :
    Whether the IP address is contained in the network?
"""


import ipaddress
import socket
from urllib.parse import urlparse


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


def ip_in_network(ip, network):
    """
    Check whether the IP address is contained in the network?

    Parameters
    ----------
    ip : `~ipaddress.IPv4Address`, str
        An `~ipaddress.IPv4Address` instance or a string of the IPv4 address
    network : `~ipaddress.IPv4Network`, str
        An `~ipaddress.IPv4Network` instance or a string of the IPv4 network,
        which is generally written in the CIDR format.

    Raises
    ------
    ValueError :
        Input IP or network is invalid.
    """
    if not isinstance(ip, ipaddress.IPv4Address):
        ip = ipaddress.IPv4Address(ip)
    if not isinstance(network, ipaddress.IPv4Network):
        network = ipaddress.IPv4Network(network)
    return ip in network