2006-11-30 23:23:39 +00:00
|
|
|
|
|
|
|
# adapted from nattraverso.ipdiscover
|
|
|
|
|
2007-03-08 02:29:00 +00:00
|
|
|
import subprocess
|
2007-03-08 01:22:30 +00:00
|
|
|
import re
|
2006-12-03 02:37:31 +00:00
|
|
|
import socket
|
2007-03-08 02:29:00 +00:00
|
|
|
from cStringIO import StringIO
|
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-03-08 03:03:47 +00:00
|
|
|
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
|
|
|
|
|
2007-03-08 01:22:30 +00:00
|
|
|
def get_local_addresses():
|
2007-03-08 03:03:47 +00:00
|
|
|
"""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.
|
2007-03-08 01:22:30 +00:00
|
|
|
"""
|
|
|
|
# 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.
|
2007-03-08 01:43:17 +00:00
|
|
|
|
2007-03-08 01:47:40 +00:00
|
|
|
cmd = "/sbin/ifconfig"
|
2007-03-08 02:29:00 +00:00
|
|
|
#p = os.popen(cmd)
|
|
|
|
c = subprocess.Popen(["ifconfig"], stdout=subprocess.PIPE)
|
|
|
|
output = c.communicate()[0]
|
|
|
|
p = StringIO(output)
|
2007-03-08 01:43:17 +00:00
|
|
|
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.
|
2007-03-08 03:03:47 +00:00
|
|
|
|
|
|
|
This will probably work on both linux and OS-X, but probably not windows.
|
2007-03-08 01:43:17 +00:00
|
|
|
"""
|
|
|
|
# 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.
|
2007-03-08 01:47:40 +00:00
|
|
|
cmd = "/sbin/ifconfig"
|
|
|
|
d = getProcessOutput(cmd)
|
2007-03-08 01:22:30 +00:00
|
|
|
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))
|
|
|
|
return addresses
|
|
|
|
def _fallback(f):
|
|
|
|
return ["127.0.0.1", get_local_ip_for()]
|
|
|
|
d.addCallbacks(_parse, _fallback)
|
|
|
|
return d
|
|
|
|
|
2006-11-30 23:23:39 +00:00
|
|
|
|
2006-11-30 23:39:38 +00:00
|
|
|
def get_local_ip_for(target='A.ROOT-SERVERS.NET'):
|
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
|
|
|
|