##// END OF EJS Templates
Merge pull request #8247 from minrk/localinterfaces...
Thomas Kluyver -
r21136:ad8172ef merge
parent child Browse files
Show More
@@ -0,0 +1,268 b''
1 """Simple utility for building a list of local IPs using the socket module.
2 This module defines two constants:
3
4 LOCALHOST : The loopback interface, or the first interface that points to this
5 machine. It will *almost* always be '127.0.0.1'
6
7 LOCAL_IPS : A list of IP addresses, loopback first, that point to this machine.
8 This will include LOCALHOST, PUBLIC_IPS, and aliases for all hosts,
9 such as '0.0.0.0'.
10
11 PUBLIC_IPS : A list of public IP addresses that point to this machine.
12 Use these to tell remote clients where to find you.
13 """
14
15 # Copyright (c) IPython Development Team.
16 # Distributed under the terms of the Modified BSD License.
17
18 import os
19 import re
20 import socket
21
22 from IPython.utils.data import uniq_stable
23 from IPython.utils.process import get_output_error_code
24 from warnings import warn
25
26
27 LOCAL_IPS = []
28 PUBLIC_IPS = []
29
30 LOCALHOST = ''
31
32 def _only_once(f):
33 """decorator to only run a function once"""
34 f.called = False
35 def wrapped(**kwargs):
36 if f.called:
37 return
38 ret = f(**kwargs)
39 f.called = True
40 return ret
41 return wrapped
42
43 def _requires_ips(f):
44 """decorator to ensure load_ips has been run before f"""
45 def ips_loaded(*args, **kwargs):
46 _load_ips()
47 return f(*args, **kwargs)
48 return ips_loaded
49
50 # subprocess-parsing ip finders
51 class NoIPAddresses(Exception):
52 pass
53
54 def _populate_from_list(addrs):
55 """populate local and public IPs from flat list of all IPs"""
56 if not addrs:
57 raise NoIPAddresses
58
59 global LOCALHOST
60 public_ips = []
61 local_ips = []
62
63 for ip in addrs:
64 local_ips.append(ip)
65 if not ip.startswith('127.'):
66 public_ips.append(ip)
67 elif not LOCALHOST:
68 LOCALHOST = ip
69
70 if not LOCALHOST:
71 LOCALHOST = '127.0.0.1'
72 local_ips.insert(0, LOCALHOST)
73
74 local_ips.extend(['0.0.0.0', ''])
75
76 LOCAL_IPS[:] = uniq_stable(local_ips)
77 PUBLIC_IPS[:] = uniq_stable(public_ips)
78
79 def _load_ips_ifconfig():
80 """load ip addresses from `ifconfig` output (posix)"""
81
82 out, err, rc = get_output_error_code('ifconfig')
83 if rc:
84 # no ifconfig, it's usually in /sbin and /sbin is not on everyone's PATH
85 out, err, rc = get_output_error_code('/sbin/ifconfig')
86 if rc:
87 raise IOError("no ifconfig: %s" % err)
88
89 lines = out.splitlines()
90 addrs = []
91 for line in lines:
92 blocks = line.lower().split()
93 if (len(blocks) >= 2) and (blocks[0] == 'inet'):
94 if blocks[1].startswith("addr:"):
95 addrs.append(blocks[1].split(":")[1])
96 else:
97 addrs.append(blocks[1])
98 _populate_from_list(addrs)
99
100
101 def _load_ips_ip():
102 """load ip addresses from `ip addr` output (Linux)"""
103 out, err, rc = get_output_error_code('ip addr')
104 if rc:
105 raise IOError("no ip: %s" % err)
106
107 lines = out.splitlines()
108 addrs = []
109 for line in lines:
110 blocks = line.lower().split()
111 if (len(blocks) >= 2) and (blocks[0] == 'inet'):
112 addrs.append(blocks[1].split('/')[0])
113 _populate_from_list(addrs)
114
115 _ipconfig_ipv4_pat = re.compile(r'ipv4.*?(\d+\.\d+\.\d+\.\d+)$', re.IGNORECASE)
116
117 def _load_ips_ipconfig():
118 """load ip addresses from `ipconfig` output (Windows)"""
119 out, err, rc = get_output_error_code('ipconfig')
120 if rc:
121 raise IOError("no ipconfig: %s" % err)
122
123 lines = out.splitlines()
124 addrs = []
125 for line in lines:
126 m = _ipconfig_ipv4_pat.match(line.strip())
127 if m:
128 addrs.append(m.group(1))
129 _populate_from_list(addrs)
130
131
132 def _load_ips_netifaces():
133 """load ip addresses with netifaces"""
134 import netifaces
135 global LOCALHOST
136 local_ips = []
137 public_ips = []
138
139 # list of iface names, 'lo0', 'eth0', etc.
140 for iface in netifaces.interfaces():
141 # list of ipv4 addrinfo dicts
142 ipv4s = netifaces.ifaddresses(iface).get(netifaces.AF_INET, [])
143 for entry in ipv4s:
144 addr = entry.get('addr')
145 if not addr:
146 continue
147 if not (iface.startswith('lo') or addr.startswith('127.')):
148 public_ips.append(addr)
149 elif not LOCALHOST:
150 LOCALHOST = addr
151 local_ips.append(addr)
152 if not LOCALHOST:
153 # we never found a loopback interface (can this ever happen?), assume common default
154 LOCALHOST = '127.0.0.1'
155 local_ips.insert(0, LOCALHOST)
156 local_ips.extend(['0.0.0.0', ''])
157 LOCAL_IPS[:] = uniq_stable(local_ips)
158 PUBLIC_IPS[:] = uniq_stable(public_ips)
159
160
161 def _load_ips_gethostbyname():
162 """load ip addresses with socket.gethostbyname_ex
163
164 This can be slow.
165 """
166 global LOCALHOST
167 try:
168 LOCAL_IPS[:] = socket.gethostbyname_ex('localhost')[2]
169 except socket.error:
170 # assume common default
171 LOCAL_IPS[:] = ['127.0.0.1']
172
173 try:
174 hostname = socket.gethostname()
175 PUBLIC_IPS[:] = socket.gethostbyname_ex(hostname)[2]
176 # try hostname.local, in case hostname has been short-circuited to loopback
177 if not hostname.endswith('.local') and all(ip.startswith('127') for ip in PUBLIC_IPS):
178 PUBLIC_IPS[:] = socket.gethostbyname_ex(socket.gethostname() + '.local')[2]
179 except socket.error:
180 pass
181 finally:
182 PUBLIC_IPS[:] = uniq_stable(PUBLIC_IPS)
183 LOCAL_IPS.extend(PUBLIC_IPS)
184
185 # include all-interface aliases: 0.0.0.0 and ''
186 LOCAL_IPS.extend(['0.0.0.0', ''])
187
188 LOCAL_IPS[:] = uniq_stable(LOCAL_IPS)
189
190 LOCALHOST = LOCAL_IPS[0]
191
192 def _load_ips_dumb():
193 """Fallback in case of unexpected failure"""
194 global LOCALHOST
195 LOCALHOST = '127.0.0.1'
196 LOCAL_IPS[:] = [LOCALHOST, '0.0.0.0', '']
197 PUBLIC_IPS[:] = []
198
199 @_only_once
200 def _load_ips(suppress_exceptions=True):
201 """load the IPs that point to this machine
202
203 This function will only ever be called once.
204
205 It will use netifaces to do it quickly if available.
206 Then it will fallback on parsing the output of ifconfig / ip addr / ipconfig, as appropriate.
207 Finally, it will fallback on socket.gethostbyname_ex, which can be slow.
208 """
209
210 try:
211 # first priority, use netifaces
212 try:
213 return _load_ips_netifaces()
214 except ImportError:
215 pass
216
217 # second priority, parse subprocess output (how reliable is this?)
218
219 if os.name == 'nt':
220 try:
221 return _load_ips_ipconfig()
222 except (IOError, NoIPAddresses):
223 pass
224 else:
225 try:
226 return _load_ips_ifconfig()
227 except (IOError, NoIPAddresses):
228 pass
229 try:
230 return _load_ips_ip()
231 except (IOError, NoIPAddresses):
232 pass
233
234 # lowest priority, use gethostbyname
235
236 return _load_ips_gethostbyname()
237 except Exception as e:
238 if not suppress_exceptions:
239 raise
240 # unexpected error shouldn't crash, load dumb default values instead.
241 warn("Unexpected error discovering local network interfaces: %s" % e)
242 _load_ips_dumb()
243
244
245 @_requires_ips
246 def local_ips():
247 """return the IP addresses that point to this machine"""
248 return LOCAL_IPS
249
250 @_requires_ips
251 def public_ips():
252 """return the IP addresses for this machine that are visible to other machines"""
253 return PUBLIC_IPS
254
255 @_requires_ips
256 def localhost():
257 """return ip for localhost (almost always 127.0.0.1)"""
258 return LOCALHOST
259
260 @_requires_ips
261 def is_local_ip(ip):
262 """does `ip` point to this machine?"""
263 return ip in LOCAL_IPS
264
265 @_requires_ips
266 def is_public_ip(ip):
267 """is `ip` a publicly visible address?"""
268 return ip in PUBLIC_IPS
@@ -1,278 +1,5 b''
1 """Simple utility for building a list of local IPs using the socket module.
1 from warnings import warn
2 This module defines two constants:
3
2
4 LOCALHOST : The loopback interface, or the first interface that points to this
3 warn("IPython.utils.localinterfaces has moved to jupyter_client.localinterfaces")
5 machine. It will *almost* always be '127.0.0.1'
6
4
7 LOCAL_IPS : A list of IP addresses, loopback first, that point to this machine.
5 from jupyter_client.localinterfaces import *
8 This will include LOCALHOST, PUBLIC_IPS, and aliases for all hosts,
9 such as '0.0.0.0'.
10
11 PUBLIC_IPS : A list of public IP addresses that point to this machine.
12 Use these to tell remote clients where to find you.
13 """
14 #-----------------------------------------------------------------------------
15 # Copyright (C) 2010 The IPython Development Team
16 #
17 # Distributed under the terms of the BSD License. The full license is in
18 # the file COPYING, distributed as part of this software.
19 #-----------------------------------------------------------------------------
20
21 #-----------------------------------------------------------------------------
22 # Imports
23 #-----------------------------------------------------------------------------
24
25 import os
26 import re
27 import socket
28
29 from .data import uniq_stable
30 from .process import get_output_error_code
31 from .warn import warn
32
33 #-----------------------------------------------------------------------------
34 # Code
35 #-----------------------------------------------------------------------------
36
37 LOCAL_IPS = []
38 PUBLIC_IPS = []
39
40 LOCALHOST = ''
41
42 def _only_once(f):
43 """decorator to only run a function once"""
44 f.called = False
45 def wrapped(**kwargs):
46 if f.called:
47 return
48 ret = f(**kwargs)
49 f.called = True
50 return ret
51 return wrapped
52
53 def _requires_ips(f):
54 """decorator to ensure load_ips has been run before f"""
55 def ips_loaded(*args, **kwargs):
56 _load_ips()
57 return f(*args, **kwargs)
58 return ips_loaded
59
60 # subprocess-parsing ip finders
61 class NoIPAddresses(Exception):
62 pass
63
64 def _populate_from_list(addrs):
65 """populate local and public IPs from flat list of all IPs"""
66 if not addrs:
67 raise NoIPAddresses
68
69 global LOCALHOST
70 public_ips = []
71 local_ips = []
72
73 for ip in addrs:
74 local_ips.append(ip)
75 if not ip.startswith('127.'):
76 public_ips.append(ip)
77 elif not LOCALHOST:
78 LOCALHOST = ip
79
80 if not LOCALHOST:
81 LOCALHOST = '127.0.0.1'
82 local_ips.insert(0, LOCALHOST)
83
84 local_ips.extend(['0.0.0.0', ''])
85
86 LOCAL_IPS[:] = uniq_stable(local_ips)
87 PUBLIC_IPS[:] = uniq_stable(public_ips)
88
89 def _load_ips_ifconfig():
90 """load ip addresses from `ifconfig` output (posix)"""
91
92 out, err, rc = get_output_error_code('ifconfig')
93 if rc:
94 # no ifconfig, it's usually in /sbin and /sbin is not on everyone's PATH
95 out, err, rc = get_output_error_code('/sbin/ifconfig')
96 if rc:
97 raise IOError("no ifconfig: %s" % err)
98
99 lines = out.splitlines()
100 addrs = []
101 for line in lines:
102 blocks = line.lower().split()
103 if (len(blocks) >= 2) and (blocks[0] == 'inet'):
104 if blocks[1].startswith("addr:"):
105 addrs.append(blocks[1].split(":")[1])
106 else:
107 addrs.append(blocks[1])
108 _populate_from_list(addrs)
109
110
111 def _load_ips_ip():
112 """load ip addresses from `ip addr` output (Linux)"""
113 out, err, rc = get_output_error_code('ip addr')
114 if rc:
115 raise IOError("no ip: %s" % err)
116
117 lines = out.splitlines()
118 addrs = []
119 for line in lines:
120 blocks = line.lower().split()
121 if (len(blocks) >= 2) and (blocks[0] == 'inet'):
122 addrs.append(blocks[1].split('/')[0])
123 _populate_from_list(addrs)
124
125 _ipconfig_ipv4_pat = re.compile(r'ipv4.*?(\d+\.\d+\.\d+\.\d+)$', re.IGNORECASE)
126
127 def _load_ips_ipconfig():
128 """load ip addresses from `ipconfig` output (Windows)"""
129 out, err, rc = get_output_error_code('ipconfig')
130 if rc:
131 raise IOError("no ipconfig: %s" % err)
132
133 lines = out.splitlines()
134 addrs = []
135 for line in lines:
136 m = _ipconfig_ipv4_pat.match(line.strip())
137 if m:
138 addrs.append(m.group(1))
139 _populate_from_list(addrs)
140
141
142 def _load_ips_netifaces():
143 """load ip addresses with netifaces"""
144 import netifaces
145 global LOCALHOST
146 local_ips = []
147 public_ips = []
148
149 # list of iface names, 'lo0', 'eth0', etc.
150 for iface in netifaces.interfaces():
151 # list of ipv4 addrinfo dicts
152 ipv4s = netifaces.ifaddresses(iface).get(netifaces.AF_INET, [])
153 for entry in ipv4s:
154 addr = entry.get('addr')
155 if not addr:
156 continue
157 if not (iface.startswith('lo') or addr.startswith('127.')):
158 public_ips.append(addr)
159 elif not LOCALHOST:
160 LOCALHOST = addr
161 local_ips.append(addr)
162 if not LOCALHOST:
163 # we never found a loopback interface (can this ever happen?), assume common default
164 LOCALHOST = '127.0.0.1'
165 local_ips.insert(0, LOCALHOST)
166 local_ips.extend(['0.0.0.0', ''])
167 LOCAL_IPS[:] = uniq_stable(local_ips)
168 PUBLIC_IPS[:] = uniq_stable(public_ips)
169
170
171 def _load_ips_gethostbyname():
172 """load ip addresses with socket.gethostbyname_ex
173
174 This can be slow.
175 """
176 global LOCALHOST
177 try:
178 LOCAL_IPS[:] = socket.gethostbyname_ex('localhost')[2]
179 except socket.error:
180 # assume common default
181 LOCAL_IPS[:] = ['127.0.0.1']
182
183 try:
184 hostname = socket.gethostname()
185 PUBLIC_IPS[:] = socket.gethostbyname_ex(hostname)[2]
186 # try hostname.local, in case hostname has been short-circuited to loopback
187 if not hostname.endswith('.local') and all(ip.startswith('127') for ip in PUBLIC_IPS):
188 PUBLIC_IPS[:] = socket.gethostbyname_ex(socket.gethostname() + '.local')[2]
189 except socket.error:
190 pass
191 finally:
192 PUBLIC_IPS[:] = uniq_stable(PUBLIC_IPS)
193 LOCAL_IPS.extend(PUBLIC_IPS)
194
195 # include all-interface aliases: 0.0.0.0 and ''
196 LOCAL_IPS.extend(['0.0.0.0', ''])
197
198 LOCAL_IPS[:] = uniq_stable(LOCAL_IPS)
199
200 LOCALHOST = LOCAL_IPS[0]
201
202 def _load_ips_dumb():
203 """Fallback in case of unexpected failure"""
204 global LOCALHOST
205 LOCALHOST = '127.0.0.1'
206 LOCAL_IPS[:] = [LOCALHOST, '0.0.0.0', '']
207 PUBLIC_IPS[:] = []
208
209 @_only_once
210 def _load_ips(suppress_exceptions=True):
211 """load the IPs that point to this machine
212
213 This function will only ever be called once.
214
215 It will use netifaces to do it quickly if available.
216 Then it will fallback on parsing the output of ifconfig / ip addr / ipconfig, as appropriate.
217 Finally, it will fallback on socket.gethostbyname_ex, which can be slow.
218 """
219
220 try:
221 # first priority, use netifaces
222 try:
223 return _load_ips_netifaces()
224 except ImportError:
225 pass
226
227 # second priority, parse subprocess output (how reliable is this?)
228
229 if os.name == 'nt':
230 try:
231 return _load_ips_ipconfig()
232 except (IOError, NoIPAddresses):
233 pass
234 else:
235 try:
236 return _load_ips_ifconfig()
237 except (IOError, NoIPAddresses):
238 pass
239 try:
240 return _load_ips_ip()
241 except (IOError, NoIPAddresses):
242 pass
243
244 # lowest priority, use gethostbyname
245
246 return _load_ips_gethostbyname()
247 except Exception as e:
248 if not suppress_exceptions:
249 raise
250 # unexpected error shouldn't crash, load dumb default values instead.
251 warn("Unexpected error discovering local network interfaces: %s" % e)
252 _load_ips_dumb()
253
254
255 @_requires_ips
256 def local_ips():
257 """return the IP addresses that point to this machine"""
258 return LOCAL_IPS
259
260 @_requires_ips
261 def public_ips():
262 """return the IP addresses for this machine that are visible to other machines"""
263 return PUBLIC_IPS
264
265 @_requires_ips
266 def localhost():
267 """return ip for localhost (almost always 127.0.0.1)"""
268 return LOCALHOST
269
270 @_requires_ips
271 def is_local_ip(ip):
272 """does `ip` point to this machine?"""
273 return ip in LOCAL_IPS
274
275 @_requires_ips
276 def is_public_ip(ip):
277 """is `ip` a publicly visible address?"""
278 return ip in PUBLIC_IPS
@@ -20,7 +20,7 b' import tempfile'
20 import zmq
20 import zmq
21
21
22 from IPython.config import LoggingConfigurable
22 from IPython.config import LoggingConfigurable
23 from IPython.utils.localinterfaces import localhost
23 from .localinterfaces import localhost
24 from IPython.utils.path import filefind
24 from IPython.utils.path import filefind
25 from IPython.utils.py3compat import (str_to_bytes, bytes_to_str, cast_bytes_py2,
25 from IPython.utils.py3compat import (str_to_bytes, bytes_to_str, cast_bytes_py2,
26 string_types)
26 string_types)
@@ -28,7 +28,7 b' from .session import Session'
28
28
29 ConnectionFileMixin = connect.ConnectionFileMixin
29 ConnectionFileMixin = connect.ConnectionFileMixin
30
30
31 from IPython.utils.localinterfaces import localhost
31 from .localinterfaces import localhost
32
32
33 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
34 # Aliases and Flags
34 # Aliases and Flags
@@ -20,7 +20,7 b' except ImportError:'
20 import zmq
20 import zmq
21
21
22 from IPython.utils.importstring import import_item
22 from IPython.utils.importstring import import_item
23 from IPython.utils.localinterfaces import is_local_ip, local_ips
23 from .localinterfaces import is_local_ip, local_ips
24 from IPython.utils.path import get_ipython_dir
24 from IPython.utils.path import get_ipython_dir
25 from IPython.utils.traitlets import (
25 from IPython.utils.traitlets import (
26 Any, Instance, Unicode, List, Bool, Type, DottedObjectName
26 Any, Instance, Unicode, List, Bool, Type, DottedObjectName
1 NO CONTENT: file renamed from IPython/utils/tests/test_localinterfaces.py to jupyter_client/tests/test_localinterfaces.py
NO CONTENT: file renamed from IPython/utils/tests/test_localinterfaces.py to jupyter_client/tests/test_localinterfaces.py
@@ -7,7 +7,7 b' from unittest import TestCase'
7 from IPython.testing import decorators as dec
7 from IPython.testing import decorators as dec
8
8
9 from IPython.config.loader import Config
9 from IPython.config.loader import Config
10 from IPython.utils.localinterfaces import localhost
10 from ..localinterfaces import localhost
11 from jupyter_client import KernelManager
11 from jupyter_client import KernelManager
12 from jupyter_client.multikernelmanager import MultiKernelManager
12 from jupyter_client.multikernelmanager import MultiKernelManager
13
13
General Comments 0
You need to be logged in to leave comments. Login now