commit 33ba9a28c4f3aae4e72c8b9fce370255e21971b7 Author: Isis Lovecruft isis@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
tor-commits@lists.torproject.org