##// END OF EJS Templates
use netifaces for faster IPython.utils.localinterfaces
MinRK -
Show More
@@ -1,108 +1,164
1 1 """Simple utility for building a list of local IPs using the socket module.
2 2 This module defines two constants:
3 3
4 4 LOCALHOST : The loopback interface, or the first interface that points to this
5 5 machine. It will *almost* always be '127.0.0.1'
6 6
7 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'.
8 10
9 11 PUBLIC_IPS : A list of public IP addresses that point to this machine.
10 12 Use these to tell remote clients where to find you.
11 13 """
12 14 #-----------------------------------------------------------------------------
13 15 # Copyright (C) 2010-2011 The IPython Development Team
14 16 #
15 17 # Distributed under the terms of the BSD License. The full license is in
16 18 # the file COPYING, distributed as part of this software.
17 19 #-----------------------------------------------------------------------------
18 20
19 21 #-----------------------------------------------------------------------------
20 22 # Imports
21 23 #-----------------------------------------------------------------------------
22 24
23 25 import socket
24 26
25 27 from .data import uniq_stable
26 28
27 29 #-----------------------------------------------------------------------------
28 30 # Code
29 31 #-----------------------------------------------------------------------------
30 32
31 33 LOCAL_IPS = []
32 34 PUBLIC_IPS = []
33 35
34 LOCALHOST = '127.0.0.1'
36 LOCALHOST = ''
35 37
36 38 def _only_once(f):
37 39 """decorator to only run a function once"""
38 40 f.called = False
39 41 def wrapped():
40 42 if f.called:
41 43 return
42 44 ret = f()
43 45 f.called = True
44 46 return ret
45 47 return wrapped
46 48
47 49 def _requires_ips(f):
48 50 """decorator to ensure load_ips has been run before f"""
49 51 def ips_loaded(*args, **kwargs):
50 52 _load_ips()
51 53 return f(*args, **kwargs)
52 54 return ips_loaded
53 55
54 @_only_once
55 def _load_ips():
56 """load the IPs that point to this machine
56 def _load_ips_netifaces():
57 """load ip addresses with netifaces"""
58 import netifaces
59 global LOCALHOST
60 local_ips = []
61 public_ips = []
57 62
58 This function will only ever be called once.
63 # list of iface names, 'lo0', 'eth0', etc.
64 for iface in netifaces.interfaces():
65 # list of ipv4 addrinfo dicts
66 ipv4s = netifaces.ifaddresses(iface).get(netifaces.AF_INET, [])
67 for entry in ipv4s:
68 addr = entry.get('addr')
69 if not addr:
70 continue
71 if not (iface.startswith('lo') or addr.startswith('127.')):
72 public_ips.append(addr)
73 elif not LOCALHOST:
74 LOCALHOST = addr
75 local_ips.append(addr)
76 if not LOCALHOST:
77 # we never found a loopback interface (can this ever happen?), assume common default
78 LOCALHOST = '127.0.0.1'
79 local_ips.insert(0, LOCALHOST)
80 local_ips.extend(['0.0.0.0', ''])
81 LOCAL_IPS[:] = uniq_stable(local_ips)
82 PUBLIC_IPS[:] = uniq_stable(public_ips)
83
84 def _load_ips_gethostbyname():
85 """load ip addresses with socket.gethostbyname_ex
86
87 This can be slow.
59 88 """
60 89 global LOCALHOST
61 90 try:
62 91 LOCAL_IPS[:] = socket.gethostbyname_ex('localhost')[2]
63 92 except socket.error:
64 pass
93 # assume common default
94 LOCAL_IPS[:] = ['127.0.0.1']
65 95
66 96 try:
67 97 hostname = socket.gethostname()
68 98 PUBLIC_IPS[:] = socket.gethostbyname_ex(hostname)[2]
69 99 # try hostname.local, in case hostname has been short-circuited to loopback
70 100 if not hostname.endswith('.local') and all(ip.startswith('127') for ip in PUBLIC_IPS):
71 101 PUBLIC_IPS[:] = socket.gethostbyname_ex(socket.gethostname() + '.local')[2]
72 102 except socket.error:
73 103 pass
74 104 finally:
75 105 PUBLIC_IPS[:] = uniq_stable(PUBLIC_IPS)
76 106 LOCAL_IPS.extend(PUBLIC_IPS)
77 107
78 108 # include all-interface aliases: 0.0.0.0 and ''
79 109 LOCAL_IPS.extend(['0.0.0.0', ''])
80 110
81 111 LOCAL_IPS[:] = uniq_stable(LOCAL_IPS)
82 112
83 113 LOCALHOST = LOCAL_IPS[0]
84 114
115 def _load_ips_dumb():
116 """Fallback in case of unexpected failure"""
117 global LOCALHOST
118 LOCALHOST = '127.0.0.1'
119 LOCAL_IPS[:] = [LOCALHOST, '0.0.0.0', '']
120 PUBLIC_IPS[:] = []
121
122 @_only_once
123 def _load_ips():
124 """load the IPs that point to this machine
125
126 This function will only ever be called once.
127
128 It will use netifaces to do it quickly if available,
129 otherwise it will fallback on socket.gethostbyname_ex, which can be slow.
130 """
131 try:
132 try:
133 _load_ips_netifaces()
134 except ImportError:
135 _load_ips_gethostbyname()
136 except Exception:
137 # unexpected error shouldn't crash, load dumb default values instead.
138 _load_ips_dumb()
139
140
85 141 @_requires_ips
86 142 def local_ips():
87 143 """return the IP addresses that point to this machine"""
88 144 return LOCAL_IPS
89 145
90 146 @_requires_ips
91 147 def public_ips():
92 148 """return the IP addresses for this machine that are visible to other machines"""
93 149 return PUBLIC_IPS
94 150
95 151 @_requires_ips
96 152 def localhost():
97 153 """return ip for localhost (almost always 127.0.0.1)"""
98 154 return LOCALHOST
99 155
100 156 @_requires_ips
101 157 def is_local_ip(ip):
102 158 """does `ip` point to this machine?"""
103 159 return ip in LOCAL_IPS
104 160
105 161 @_requires_ips
106 162 def is_public_ip(ip):
107 163 """is `ip` a publicly visible address?"""
108 164 return ip in PUBLIC_IPS
General Comments 0
You need to be logged in to leave comments. Login now