2007-04-16 21:59:13 +00:00
|
|
|
# portions extracted from ipaddresslib by Autonomous Zone Industries, LGPL (author: Greg Smith)
|
|
|
|
# portions adapted from nattraverso.ipdiscover
|
|
|
|
# portions authored by Brian Warner, working for Allmydata
|
|
|
|
# most recent version authored by Zooko O'Whielacronx, working for Allmydata
|
2006-11-30 23:23:39 +00:00
|
|
|
|
2007-04-16 21:59:13 +00:00
|
|
|
# from the Python Standard Library
|
|
|
|
import re, socket, sys
|
2006-11-30 23:23:39 +00:00
|
|
|
|
2007-04-16 21:59:13 +00:00
|
|
|
# from Twisted
|
|
|
|
from twisted.internet import defer
|
2006-11-30 23:23:39 +00:00
|
|
|
from twisted.internet import reactor
|
|
|
|
from twisted.internet.protocol import DatagramProtocol
|
2007-03-08 01:22:30 +00:00
|
|
|
from twisted.internet.utils import getProcessOutput
|
2007-04-16 21:59:13 +00:00
|
|
|
from twisted.python.procutils import which
|
2007-03-08 01:22:30 +00:00
|
|
|
|
2007-04-16 21:59:13 +00:00
|
|
|
def get_local_addresses_async(target='A.ROOT-SERVERS.NET'):
|
|
|
|
"""
|
|
|
|
Return a Deferred that fires with a list of IPv4 addresses (as dotted-quad
|
|
|
|
strings) that are currently configured on this host.
|
2007-03-08 03:03:47 +00:00
|
|
|
|
2007-04-16 21:59:13 +00:00
|
|
|
@param target: we want to learn an IP address they could try using to
|
|
|
|
connect to us; The default value is fine, but it might help if you
|
|
|
|
pass the address of a host that you are actually trying to be
|
|
|
|
reachable to.
|
2007-03-08 01:22:30 +00:00
|
|
|
"""
|
2007-04-16 22:12:01 +00:00
|
|
|
addresses = set()
|
|
|
|
addresses.add(get_local_ip_for(target))
|
2007-03-08 01:43:17 +00:00
|
|
|
|
2007-04-16 21:59:13 +00:00
|
|
|
d = _find_addresses_via_config()
|
|
|
|
def _collect(res):
|
2007-04-16 22:12:01 +00:00
|
|
|
addresses.update(res)
|
2007-03-08 01:22:30 +00:00
|
|
|
return addresses
|
2007-04-16 21:59:13 +00:00
|
|
|
d.addCallback(_collect)
|
2007-03-08 01:22:30 +00:00
|
|
|
|
2007-04-16 21:59:13 +00:00
|
|
|
return d
|
2006-11-30 23:23:39 +00:00
|
|
|
|
2007-04-16 21:59:13 +00:00
|
|
|
def get_local_ip_for(target):
|
2006-11-30 23:23:39 +00:00
|
|
|
"""Find out what our IP address is for use by a given target.
|
|
|
|
|
2006-12-03 02:37:31 +00:00
|
|
|
Returns a string that holds the IP address which could be used by
|
|
|
|
'target' to connect to us. It might work for them, it might not.
|
2006-11-30 23:23:39 +00:00
|
|
|
"""
|
2007-03-08 01:21:42 +00:00
|
|
|
try:
|
|
|
|
target_ipaddr = socket.gethostbyname(target)
|
|
|
|
except socket.gaierror:
|
|
|
|
return "127.0.0.1"
|
2006-11-30 23:23:39 +00:00
|
|
|
udpprot = DatagramProtocol()
|
|
|
|
port = reactor.listenUDP(0, udpprot)
|
|
|
|
udpprot.transport.connect(target_ipaddr, 7)
|
|
|
|
localip = udpprot.transport.getHost().host
|
2006-12-03 02:37:31 +00:00
|
|
|
port.stopListening() # note, this returns a Deferred
|
2006-11-30 23:23:39 +00:00
|
|
|
return localip
|
2006-12-03 02:37:31 +00:00
|
|
|
|
2007-04-16 21:59:13 +00:00
|
|
|
# k: result of sys.platform, v: which kind of IP configuration reader we use
|
|
|
|
_platform_map = {
|
|
|
|
"linux-i386": "linux", # redhat
|
|
|
|
"linux-ppc": "linux", # redhat
|
|
|
|
"linux2": "linux", # debian
|
|
|
|
"win32": "win32",
|
|
|
|
"irix6-n32": "irix",
|
|
|
|
"irix6-n64": "irix",
|
|
|
|
"irix6": "irix",
|
|
|
|
"openbsd2": "bsd",
|
|
|
|
"darwin": "bsd", # Mac OS X
|
|
|
|
"freebsd4": "bsd",
|
|
|
|
"freebsd5": "bsd",
|
|
|
|
"netbsd1": "bsd",
|
|
|
|
"sunos5": "sunos",
|
|
|
|
"cygwin": "cygwin",
|
|
|
|
}
|
|
|
|
|
|
|
|
class UnsupportedPlatformError(Exception):
|
|
|
|
pass
|
|
|
|
|
|
|
|
# Wow, I'm really amazed at home much mileage we've gotten out of calling
|
|
|
|
# the external route.exe program on windows... It appears to work on all
|
|
|
|
# versions so far. Still, the real system calls would much be preferred...
|
|
|
|
# ... thus wrote Greg Smith in time immemorial...
|
|
|
|
_win32_path = 'route.exe'
|
|
|
|
_win32_args = ('print',)
|
2007-04-16 22:12:01 +00:00
|
|
|
_win32_re = re.compile('^\s*\d+\.\d+\.\d+\.\d+\s.+\s(?P<address>\d+\.\d+\.\d+\.\d+)\s+(?P<metric>\d+)\s*$', flags=re.M|re.I|re.S)
|
2007-04-16 21:59:13 +00:00
|
|
|
|
|
|
|
# These work in Redhat 6.x and Debian 2.2 potato
|
|
|
|
_linux_path = '/sbin/ifconfig'
|
2007-04-16 22:12:01 +00:00
|
|
|
_linux_re = re.compile('^\s*inet addr:(?P<address>\d+\.\d+\.\d+\.\d+)\s.+$', flags=re.M|re.I|re.S)
|
2007-04-16 21:59:13 +00:00
|
|
|
|
|
|
|
# NetBSD 1.4 (submitted by Rhialto), Darwin, Mac OS X
|
2007-04-18 14:40:26 +00:00
|
|
|
_netbsd_path = '/sbin/ifconfig'
|
|
|
|
_netbsd_args = ('-a',)
|
2007-04-16 21:59:13 +00:00
|
|
|
_netbsd_re = re.compile('^\s+inet (?P<address>\d+\.\d+\.\d+\.\d+)\s.+$', flags=re.M|re.I|re.S)
|
|
|
|
|
|
|
|
# Irix 6.5
|
2007-04-18 14:40:26 +00:00
|
|
|
_irix_path = '/usr/etc/ifconfig'
|
|
|
|
_irix_args = ('-a',)
|
2007-04-16 21:59:13 +00:00
|
|
|
|
|
|
|
# Solaris 2.x
|
2007-04-18 14:40:26 +00:00
|
|
|
_sunos_path = '/usr/sbin/ifconfig'
|
|
|
|
_sunos_args = ('-a',)
|
2007-04-16 21:59:13 +00:00
|
|
|
|
|
|
|
def _find_addresses_via_config():
|
|
|
|
# originally by Greg Smith, hacked by Zooko to conform to Brian's API
|
|
|
|
|
|
|
|
platform = _platform_map.get(sys.platform)
|
|
|
|
if not platform:
|
|
|
|
raise UnsupportedPlatformError(sys.platform)
|
|
|
|
|
|
|
|
if platform in ('win32', 'cygwin',):
|
|
|
|
l = []
|
|
|
|
for executable in which(_win32_path):
|
|
|
|
l.append(_query(executable, _win32_re, _win32_args))
|
|
|
|
dl = defer.DeferredList(l)
|
|
|
|
def _gather_results(res):
|
2007-04-16 22:12:01 +00:00
|
|
|
addresses = set()
|
2007-04-16 21:59:13 +00:00
|
|
|
for r in res:
|
|
|
|
if r[0]:
|
2007-04-16 22:12:01 +00:00
|
|
|
addresses.update(r[1])
|
2007-04-16 21:59:13 +00:00
|
|
|
return addresses
|
|
|
|
dl.addCallback(_gather_results)
|
|
|
|
return dl
|
|
|
|
elif platform == 'linux':
|
|
|
|
return _query(_linux_path, _linux_re)
|
|
|
|
elif platform == 'bsd':
|
2007-04-18 14:40:26 +00:00
|
|
|
return _query(_netbsd_path, _netbsd_re, _netbsd_args)
|
2007-04-16 21:59:13 +00:00
|
|
|
elif platform == 'irix' :
|
2007-04-18 14:40:26 +00:00
|
|
|
return _query(_irix_path, _netbsd_re, _irix_args)
|
2007-04-16 21:59:13 +00:00
|
|
|
elif platform == 'sunos':
|
2007-04-18 14:40:26 +00:00
|
|
|
return _query(_sunos_path, _netbsd_re, _sunos_args)
|
2007-04-16 21:59:13 +00:00
|
|
|
|
|
|
|
def _query(path, regex, args=()):
|
|
|
|
d = getProcessOutput(path, args)
|
|
|
|
def _parse(output):
|
2007-04-16 22:12:01 +00:00
|
|
|
addresses = set()
|
2007-04-16 21:59:13 +00:00
|
|
|
outputsplit = output.split('\n')
|
2007-04-16 22:12:01 +00:00
|
|
|
for outline in outputsplit:
|
|
|
|
m = regex.match(outline)
|
2007-04-16 21:59:13 +00:00
|
|
|
if m:
|
|
|
|
d = m.groupdict()
|
2007-04-16 22:12:01 +00:00
|
|
|
addresses.add(d['address'])
|
2007-04-16 21:59:13 +00:00
|
|
|
|
|
|
|
return addresses
|
|
|
|
d.addCallback(_parse)
|
|
|
|
return d
|