mirror of
https://github.com/tahoe-lafs/tahoe-lafs.git
synced 2024-12-20 05:28:04 +00:00
port iputil to Windows (and Irix, and NetBSD, and Solaris 2, ...)
This commit is contained in:
parent
0f54468f66
commit
ac4d23d336
@ -1,111 +1,41 @@
|
||||
# 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
|
||||
|
||||
# adapted from nattraverso.ipdiscover
|
||||
# from the Python Standard Library
|
||||
import re, socket, sys
|
||||
|
||||
import subprocess
|
||||
import re
|
||||
import socket
|
||||
from cStringIO import StringIO
|
||||
# from Twisted
|
||||
from twisted.internet import defer
|
||||
from twisted.python import log
|
||||
from twisted.internet import reactor
|
||||
from twisted.internet.protocol import DatagramProtocol
|
||||
from twisted.internet.utils import getProcessOutput
|
||||
from twisted.python.procutils import which
|
||||
|
||||
from fcntl import ioctl
|
||||
import struct
|
||||
SIOCGIFADDR = 0x8915 # linux-specific
|
||||
|
||||
# inspired by scapy
|
||||
def get_if_list():
|
||||
f = open("/proc/net/dev","r")
|
||||
f.readline(); f.readline()
|
||||
names = []
|
||||
for l in f.readlines():
|
||||
names.append(l[:l.index(":")].strip())
|
||||
return names
|
||||
|
||||
def get_if_addr(ifname):
|
||||
try:
|
||||
s=socket.socket()
|
||||
ifreq = ioctl(s, SIOCGIFADDR, struct.pack("16s16x", ifname))
|
||||
s.close()
|
||||
naddr = ifreq[20:24]
|
||||
return socket.inet_ntoa(naddr)
|
||||
except IOError:
|
||||
return None
|
||||
|
||||
def get_local_addresses():
|
||||
"""Return a list of IPv4 addresses (as dotted-quad strings) that are
|
||||
currently configured on this host.
|
||||
|
||||
This will only work under linux, because it uses both a linux-specific
|
||||
/proc/net/dev devices (to get the interface names) and a SIOCGIFADDR
|
||||
ioctl (to get their addresses). If the listing-the-interfaces were done
|
||||
with an ioctl too (and if if you're lucky enough to be using the same
|
||||
value for the ioctls), then it might work on other forms of unix too.
|
||||
Windows is right out."""
|
||||
|
||||
ifnames = []
|
||||
for ifname in get_if_list():
|
||||
addr = get_if_addr(ifname)
|
||||
if addr:
|
||||
ifnames.append(addr)
|
||||
return ifnames
|
||||
|
||||
def get_local_addresses_sync():
|
||||
"""Return a list of IPv4 addresses (as dotted-quad strings) that are
|
||||
currently configured on this host.
|
||||
|
||||
Unfortunately this is not compatible with Twisted: it catches SIGCHLD and
|
||||
this usually results in errors about 'Interrupted system call'.
|
||||
|
||||
This will probably work on both linux and OS-X, but probably not windows.
|
||||
def get_local_addresses_async(target='A.ROOT-SERVERS.NET'):
|
||||
"""
|
||||
# eventually I want to use somebody else's cross-platform library for
|
||||
# this. For right now, I'm running ifconfig and grepping for the 'inet '
|
||||
# lines.
|
||||
Return a Deferred that fires with a list of IPv4 addresses (as dotted-quad
|
||||
strings) that are currently configured on this host.
|
||||
|
||||
cmd = "/sbin/ifconfig"
|
||||
#p = os.popen(cmd)
|
||||
c = subprocess.Popen(["ifconfig"], stdout=subprocess.PIPE)
|
||||
output = c.communicate()[0]
|
||||
p = StringIO(output)
|
||||
addresses = []
|
||||
for line in p.readlines():
|
||||
# linux shows: " inet addr:1.2.3.4 Bcast:1.2.3.255..."
|
||||
# OS-X shows: " inet 1.2.3.4 ..."
|
||||
m = re.match("^\s+inet\s+[a-z:]*([\d\.]+)\s", line)
|
||||
if m:
|
||||
addresses.append(m.group(1))
|
||||
return addresses
|
||||
|
||||
def get_local_addresses_async():
|
||||
"""Return a Deferred that fires with a list of IPv4 addresses (as
|
||||
dotted-quad strings) that are currently configured on this host.
|
||||
|
||||
This will probably work on both linux and OS-X, but probably not windows.
|
||||
@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.
|
||||
"""
|
||||
# eventually I want to use somebody else's cross-platform library for
|
||||
# this. For right now, I'm running ifconfig and grepping for the 'inet '
|
||||
# lines.
|
||||
|
||||
# I'd love to do this synchronously.
|
||||
cmd = "/sbin/ifconfig"
|
||||
d = getProcessOutput(cmd)
|
||||
def _parse(output):
|
||||
addresses = []
|
||||
for line in StringIO(output).readlines():
|
||||
# linux shows: " inet addr:1.2.3.4 Bcast:1.2.3.255..."
|
||||
# OS-X shows: " inet 1.2.3.4 ..."
|
||||
m = re.match("^\s+inet\s+[a-z:]*([\d\.]+)\s", line)
|
||||
if m:
|
||||
addresses.append(m.group(1))
|
||||
addresses.append(get_local_ip_for(target))
|
||||
|
||||
d = _find_addresses_via_config()
|
||||
def _collect(res):
|
||||
addresses.extend(res)
|
||||
return addresses
|
||||
def _fallback(f):
|
||||
return ["127.0.0.1", get_local_ip_for()]
|
||||
d.addCallbacks(_parse, _fallback)
|
||||
d.addCallback(_collect)
|
||||
|
||||
return d
|
||||
|
||||
|
||||
def get_local_ip_for(target='A.ROOT-SERVERS.NET'):
|
||||
def get_local_ip_for(target):
|
||||
"""Find out what our IP address is for use by a given target.
|
||||
|
||||
Returns a string that holds the IP address which could be used by
|
||||
@ -122,3 +52,89 @@ def get_local_ip_for(target='A.ROOT-SERVERS.NET'):
|
||||
port.stopListening() # note, this returns a Deferred
|
||||
return localip
|
||||
|
||||
# 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',)
|
||||
_win32_re = re.compile('^\s*0\.0\.0\.0\s.+\s(?P<address>\d+\.\d+\.\d+\.\d+)\s+(?P<metric>\d+)\s*$', flags=re.M|re.I|re.S)
|
||||
|
||||
# These work in Redhat 6.x and Debian 2.2 potato
|
||||
_linux_path = '/sbin/ifconfig'
|
||||
_linux_re = re.compile('^(?P<name>\w+)\s.+\sinet addr:(?P<address>\d+\.\d+\.\d+\.\d+)\s.+$', flags=re.M|re.I|re.S)
|
||||
|
||||
# NetBSD 1.4 (submitted by Rhialto), Darwin, Mac OS X
|
||||
_netbsd_path = '/sbin/ifconfig -a'
|
||||
_netbsd_re = re.compile('^\s+inet (?P<address>\d+\.\d+\.\d+\.\d+)\s.+$', flags=re.M|re.I|re.S)
|
||||
|
||||
# Irix 6.5
|
||||
_irix_path = '/usr/etc/ifconfig -a'
|
||||
|
||||
# Solaris 2.x
|
||||
_sunos_path = '/usr/sbin/ifconfig -a'
|
||||
|
||||
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):
|
||||
addresses = []
|
||||
for r in res:
|
||||
if r[0]:
|
||||
addresses.extend(r[1])
|
||||
return addresses
|
||||
dl.addCallback(_gather_results)
|
||||
return dl
|
||||
elif platform == 'linux':
|
||||
return _query(_linux_path, _linux_re)
|
||||
elif platform == 'bsd':
|
||||
return _query(_netbsd_path, _netbsd_re)
|
||||
elif platform == 'irix' :
|
||||
return _query(_irix_path, _netbsd_re)
|
||||
elif platform == 'sunos':
|
||||
return _query(_sunos_path, _netbsd_re)
|
||||
|
||||
def _query(path, regex, args=()):
|
||||
d = getProcessOutput(path, args)
|
||||
def _parse(output):
|
||||
addresses = []
|
||||
outputsplit = output.split('\n')
|
||||
for output in outputsplit:
|
||||
m = regex.match(output)
|
||||
if m:
|
||||
d = m.groupdict()
|
||||
addresses.append(d['address'])
|
||||
|
||||
return addresses
|
||||
d.addCallback(_parse)
|
||||
return d
|
||||
|
Loading…
Reference in New Issue
Block a user