[tor-commits] [ooni-probe/master] * Moved iface and ipaddr discovery function to ooni.utils.net.

isis at torproject.org isis at torproject.org
Fri Nov 16 00:50:07 UTC 2012


commit 33ba9a28c4f3aae4e72c8b9fce370255e21971b7
Author: Isis Lovecruft <isis at torproject.org>
Date:   Sun Nov 11 13:56:09 2012 +0000

    * Moved iface and ipaddr discovery function to ooni.utils.net.
---
 nettests/bridge_reachability/echo.py |   26 -----
 ooni/utils/net.py                    |  194 +++++++++++++++++++++++++--------
 2 files changed, 147 insertions(+), 73 deletions(-)

diff --git a/nettests/bridge_reachability/echo.py b/nettests/bridge_reachability/echo.py
index 5060ffd..5198766 100644
--- a/nettests/bridge_reachability/echo.py
+++ b/nettests/bridge_reachability/echo.py
@@ -59,41 +59,15 @@ class EchoTest(BaseScapyTest):
             Struct returned from getifaddrs(3) and turned into a tuple in the
             form (*ifa_name, AF_FAMILY, *ifa_addr)
         '''
-
         if self.localOptions:
-            log.debug("%s: local_options found" % self.name)
             for key, value in self.localOptions.items():
                 log.debug("setting self.%s = %s" % (key, value))
                 setattr(self, key, value)
 
-        ## xxx is this now .subOptions?
-        #self.inputFile = self.localOptions['file']
         self.timeout *= 1000            ## convert to milliseconds
 
         if not self.interface:
             log.msg("No network interface specified!")
-            log.debug("OS detected: %s" % sys.platform)
-            if LINUX or OPENBSD or NETBSD or FREEBSD or DARWIN or SOLARIS:
-                from twisted.internet.test import _posixifaces
-                log.msg("Attempting to discover network interfaces...")
-                ifaces = _posixifaces._interfaces()
-            elif WINDOWS:
-                from twisted.internet.test import _win32ifaces
-                log.msg("Attempting to discover network interfaces...")
-                ifaces = _win32ifaces._interfaces()
-            else:
-                log.debug("Client OS %s not accounted for!" % sys.platform)
-                log.debug("Unable to discover network interfaces...")
-                ifaces = [('lo', '')]
-
-            ## found = {'eth0': '1.1.1.1'}
-            found = [{i[0]: i[2]} for i in ifaces if i[0] != 'lo']
-            log.info("Found interfaces:\n%s" % pprint(found))
-            self.interfaces = self.tryInterfaces(found)
-        else:
-            ## xxx need a way to check that iface exists, is up, and
-            ## we have permissions on it
-            log.debug("Our interface has been set to %s" % self.interface)
 
         if self.pcap:
             try:
diff --git a/ooni/utils/net.py b/ooni/utils/net.py
index 3ddba61..0cbc095 100644
--- a/ooni/utils/net.py
+++ b/ooni/utils/net.py
@@ -2,58 +2,43 @@
 #
 # net.py
 # --------
-# OONI utilities for networking related operations
+# OONI utilities for network infrastructure and hardware.
+#
+# :authors: Isis Lovecruft, Arturo Filasto
+# :version: 0.0.1-pre-alpha
+# :license: (c) 2012 Isis Lovecruft, Arturo Filasto
+#           see attached LICENCE file
 
 import sys
-from zope.interface import implements
 
+from zope.interface import implements
 from twisted.internet import protocol, defer
 from twisted.internet import threads, reactor
 from twisted.web.iweb import IBodyProducer
-
 from scapy.all import utils
 
 from ooni.utils import log, txscapy
 
-userAgents = [("Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.8.1.6) Gecko/20070725 Firefox/2.0.0.6", "Firefox 2.0, Windows XP"),
-              ("Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)", "Internet Explorer 7, Windows Vista"),
-              ("Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30)", "Internet Explorer 7, Windows XP"),
-              ("Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322)", "Internet Explorer 6, Windows XP"),
-              ("Mozilla/4.0 (compatible; MSIE 5.0; Windows NT 5.1; .NET CLR 1.1.4322)", "Internet Explorer 5, Windows XP"),
-              ("Opera/9.20 (Windows NT 6.0; U; en)", "Opera 9.2, Windows Vista"),
-              ("Opera/9.00 (Windows NT 5.1; U; en)", "Opera 9.0, Windows XP"),
-              ("Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; en) Opera 8.50", "Opera 8.5, Windows XP"),
-              ("Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; en) Opera 8.0", "Opera 8.0, Windows XP"),
-              ("Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows NT 5.1) Opera 7.02 [en]", "Opera 7.02, Windows XP"),
-              ("Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20060127 Netscape/8.1", "Netscape 8.1, Windows XP")]
-
-class StringProducer(object):
-    implements(IBodyProducer)
-
-    def __init__(self, body):
-        self.body = body
-        self.length = len(body)
+#if platformm.system() == 'Windows':
+#    import _winreg as winreg
 
-    def startProducing(self, consumer):
-        consumer.write(self.body)
-        return defer.succeed(None)
+PLATFORMS = {'LINUX': platform.startswith("linux"),
+             'OPENBSD': platform.startswith("openbsd"),
+             'FREEBSD': platform.startswith("freebsd"),
+             'NETBSD': platform.startswith("netbsd"),
+             'DARWIN': platform.startswith("darwin"),
+             'SOLARIS': platform.startswith("sunos"),
+             'WINDOWS': platform.startswith("win32")}
 
-    def pauseProducing(self):
-        pass
 
-    def stopProducing(self):
-        pass
+class UnsupportedPlatform(Exception):
+    """Support for this platform is not currently available."""
 
-class BodyReceiver(protocol.Protocol):
-    def __init__(self, finished):
-        self.finished = finished
-        self.data = ""
+class IfaceError(Exception):
+    """Could not find default network interface."""
 
-    def dataReceived(self, bytes):
-        self.data += bytes
-
-    def connectionLost(self, reason):
-        self.finished.callback(self.data)
+class PermissionsError(SystemExit):
+    """This test requires admin or root privileges to run. Exiting..."""
 
 def capturePackets(pcap_filename):
     from scapy.all import sniff
@@ -79,14 +64,129 @@ def capturePackets(pcap_filename):
     reactor.addSystemEventTrigger('before', 'shutdown', stopCapture)
     return d
 
-class PermissionsError(SystemExit):
-    def __init__(self, *args, **kwargs):
-        if not args and not kwargs:
-            pe = "This test requires admin or root privileges to run. Exiting..."
-            super(PermissionsError, self).__init__(pe, *args, **kwargs)
-        else:
-            super(PermissionsError, self).__init__(*args, **kwargs)
 
-class IfaceError(SystemExit):
-    def __init__(self, *args, **kwargs):
-        super(IfaceError, self).__init__(*args, **kwargs)
+def getClientPlatform(platform_name=None):
+    for name, test in PLATFORMS.items():
+        if not platform_name or platform_name.upper() == name:
+            if test:
+                return name, test
+
+def getPosixIface():
+    from twisted.internet.test import _posixifaces
+
+    log.msg("Attempting to discover network interfaces...")
+    ifaces = _posixifaces._interfaces()
+    ifup = tryInterfaces(ifaces)
+    return ifup
+
+def getWindowsIface():
+    from twisted.internet.test import _win32ifaces
+
+    log.msg("Attempting to discover network interfaces...")
+    ifaces = _win32ifaces._interfaces()
+    ifup = tryInterfaces(ifaces)
+    return ifup
+
+def getPlatformAndIfaces(platform_name=None):
+    client, test = getClientPlatform(platform_name)
+    if client:
+        if client == ('LINUX' or 'DARWIN') or client[-3:] == 'BSD':
+            return getPosixIface()
+        elif client == 'WINDOWS':
+            return getWindowsIface()
+        ## XXX fixme figure out how to get iface for Solaris
+        else:
+            return None
+    else:
+        raise UnsupportedPlatform
+
+def checkInterfaces(ifaces=None, timeout=1):
+    """
+    @param ifaces:
+        A dictionary in the form of ifaces['if_name'] = 'if_addr'.
+    """
+    try:
+        from scapy.all import IP, ICMP
+        from scapy.all import sr1   ## we want this check to be blocking
+    except:
+        log.msg(("Scapy required: www.secdev.org/projects/scapy"))
+
+    ifup = {}
+    if not ifaces:
+        log.debug("net.checkInterfaces(): no interfaces specified!")
+        return None
+
+    for iface in ifaces:
+        for ifname, ifaddr in iface:
+            log.debug("net.checkInterfaces(): testing iface {} by pinging"
+                      + " local address {}".format(ifname, ifaddr))
+            try:
+                pkt = IP(dst=ifaddr)/ICMP()
+                ans, unans = sr(pkt, iface=ifname, timeout=5, retry=3)
+            except Exception, e:
+                raise PermissionsError if e.find("Errno 1") else log.err(e)
+            else:
+                if ans.summary():
+                    log.debug("net.checkInterfaces(): got answer on interface %s"
+                             + ":\n%s".format(ifname, ans.summary()))
+                    ifup.update(ifname, ifaddr)
+                else:
+                    log.debug("Interface test packet was unanswered:\n%s"
+                             % unans.summary())
+    if len(ifup) > 0:
+        log.msg("Discovered working network interfaces: %s" % ifup)
+        return ifup
+    else:
+        raise IfaceError
+
+def getNonLoopbackIfaces(platform_name=None):
+    try:
+        ifaces = getPlatformAndIfaces(platform_name)
+    except UnsupportedPlatform, up:
+        log.err(up)
+
+    if not ifaces:
+        log.msg("Unable to discover network interfaces...")
+        return None
+    else:
+        found = [{i[0]: i[2]} for i in ifaces if i[0] != 'lo']
+        log.debug("utils.net.getClientIfaces: Found non-loopback interfaces: %s"
+                  % pprint(found))
+        try:
+            interfaces = checkInterfaces(found)
+        except IfaceError, ie:
+            log.err(ie)
+            return None
+        else:
+            return interfaces
+
+def getNetworksFromRoutes():
+    from scapy.all import conf, ltoa
+    from ipaddr    import IPNetwork, IPAddress
+
+    ## Hide the 'no routes' warnings
+    conf.verb = 0
+
+    networks = []
+    client   = conf.route
+    log.debug("Local Routing Table:\n{}".format(client))
+
+    for nw, nm, gw, iface, addr in client.routes:
+        n = IPNetwork( ltoa(nw) )
+        (n.netmask, n.gateway, n.ipaddr) = [IPAddress(x) for x in [nm, gw, addr]]
+        n.iface = iface
+        if not n.compressed in networks:
+            networks.append(n)
+
+    return networks
+
+def getDefaultIface():
+    networks = getNetworksFromRoutes()
+    for net in networks:
+        if net.is_private:
+            return net
+    raise IfaceError
+
+def getLocalAddress():
+    default_iface = getDefaultIface()
+    return default_iface.ipaddr





More information about the tor-commits mailing list