Coverage for mfutil/net.py: 71%
87 statements
« prev ^ index » next coverage.py v7.6.1, created at 2025-03-12 03:03 +0000
« prev ^ index » next coverage.py v7.6.1, created at 2025-03-12 03:03 +0000
1"""Utility functions around network."""
3import logging
4import socket
5import netifaces
8def __get_logger():
9 return logging.getLogger("mfutil.net")
12def get_ip_for_hostname(hostname, ignore_hostnames_list=["AUTO"]):
13 """Get the IP of a given hostname.
15 Args:
16 hostname (string): hostname to find.
17 ignore_hostnames_list (list of strings): special hostname values which
18 won't be lookup ip (if the given hostname is in this list, this
19 function will return the given hostname without any modification).
20 Returns:
21 (string) IP of the given hostname (or None if we can't find it).
23 """
24 if hostname in ignore_hostnames_list:
25 return hostname
26 if hostname in ("127.0.0.1", "localhost", "localhost.localdomain"):
27 return "127.0.0.1"
28 try:
29 infos = socket.getaddrinfo(hostname, 80, 0, 0, socket.IPPROTO_TCP)
30 except Exception:
31 return None
32 for (family, sockettype, proto, canonname, sockaddr) in infos:
33 if sockaddr is None or len(sockaddr) != 2:
34 continue
35 tmp = sockaddr[0]
36 if '.' not in tmp:
37 # we don't want ipv6
38 continue
39 return tmp
40 return None
43def get_simple_hostname():
44 """Return the "simple" hostname of the server.
46 "simple" hostname means "without network domain", so without any dot
47 in the hostname.
49 Returns:
50 string: the "simple" hostname of the server.
52 """
53 return socket.gethostname().split('.')[0]
56def _get_domainname_from_resolv_conf(resolv_conf_file="/etc/resolv.conf"):
57 with open(resolv_conf_file, "r") as f:
58 lines = f.readlines()
59 for line in lines:
60 tmp = line.strip()
61 if tmp.startswith("domain"):
62 cols = tmp.split()
63 if len(cols) >= 2:
64 return cols[1]
65 return None
68def get_domainname(use_resolv_conf=True, resolv_conf_file="/etc/resolv.conf"):
69 """Get the domain name of the server.
71 The domain name does not include the hostname.
73 We try first with the getfqdn method then with the resolv.conf file because
74 the domain can be found here.
76 Args:
77 use_resolv_conf (boolean): if set to True, we use the resolv.conf file.
78 resolv_conf_file (string): full path of the resolv.conf file (useful
79 for unit testing).
81 Returns:
82 string: the domain name of the server (or None if we can't find it)
84 """
85 tmp = socket.getfqdn(get_simple_hostname())
86 if '.' in tmp:
87 return ".".join(tmp.split('.')[1:])
88 if use_resolv_conf:
89 return _get_domainname_from_resolv_conf(resolv_conf_file)
90 return None
93def get_full_hostname(use_resolv_conf=True,
94 resolv_conf_file="/etc/resolv.conf"):
95 """Return the "full" hostname of the server.
97 "full" hostname means "with network domain" appended.
99 Args:
100 use_resolv_conf (boolean): if set to True, we use the resolv.conf file
101 to find the domain name.
102 resolv_conf_file (string): full path of the resolv.conf file (useful
103 for unit testing).
105 Returns:
106 string: the "full" hostname of the server.
108 """
109 tmp = socket.getfqdn(get_simple_hostname())
110 if '.' in tmp or not use_resolv_conf:
111 return tmp
112 domainname = get_domainname(use_resolv_conf, resolv_conf_file)
113 if domainname is not None:
114 return "%s.%s" % (get_simple_hostname(), domainname)
115 return get_simple_hostname()
118def _get_real_ip_netifaces():
119 # pylint: disable=E1101
120 ip = "127.0.0.1"
121 try:
122 # we try first with the default gateway
123 if 'default_gateway' in dir(netifaces):
124 #netifaces2
125 def_gw_device = netifaces.default_gateway(old_api=True)[netifaces.AF_INET][1]
126 else:
127 #original netifaces
128 def_gw_device = netifaces.gateways()['default'][netifaces.AF_INET][1]
129 infos = netifaces.ifaddresses(def_gw_device)
130 ip = str(infos[netifaces.AF_INET][0]['addr'])
131 except Exception:
132 pass
133 if ip != "127.0.0.1":
134 return ip
135 # we try every interface
136 for interface in netifaces.interfaces():
137 try:
138 infos = netifaces.ifaddresses(interface)
139 ip = str(infos[netifaces.AF_INET][0]['addr'])
140 except Exception:
141 pass
142 if ip != "127.0.0.1":
143 return ip
144 return ip
147def get_real_ip():
148 """Try to find and return the real IP of the server.
150 We try to avoid to return 127.0.0.1 by examining network interfaces.
152 Returns:
153 string: the real IP of the server.
155 """
156 hostname = get_simple_hostname()
157 ip = get_ip_for_hostname(hostname)
158 if ip != "127.0.0.1":
159 return ip
160 # try to find the real ip (not 127.0.0.1)
161 return _get_real_ip_netifaces()
164def ping_tcp_port(host, port, timeout=5):
165 """Ping a TCP host/port with a configurable timeout.
167 It's not really a ping but a little connection attempt to see if the
168 port is open and listened. The timeout is useful when there is a kind
169 of firewall between.
171 No Exception are raised in any case.
173 Args:
174 host (string): the hostname/ip to ping.
175 port (int): the TCP port to ping.
176 timeout (int): timeout in seconds.
178 Returns:
179 boolean: True if the port is open and listened.
181 """
182 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
183 sock.settimeout(timeout)
184 try:
185 result = sock.connect_ex((host, port))
186 if result == 0:
187 sock.close()
188 return True
189 except Exception:
190 pass
191 return False