[tor-commits] [ooni-probe/master] Move the parasitic traceroute function to the experimental tests.

art at torproject.org art at torproject.org
Wed Mar 12 21:49:22 UTC 2014


commit 2e5647cf4a5de7ba83c3c12596661f9007c216b5
Author: Arturo Filastò <art at fuffa.org>
Date:   Fri Mar 7 13:42:52 2014 +0100

    Move the parasitic traceroute function to the experimental tests.
---
 ooni/nettests/experimental/parasitictraceroute.py |  157 +++++----------------
 ooni/nettests/manipulation/parasitictraceroute.py |   48 -------
 2 files changed, 38 insertions(+), 167 deletions(-)

diff --git a/ooni/nettests/experimental/parasitictraceroute.py b/ooni/nettests/experimental/parasitictraceroute.py
index 631c24b..c8aa3ed 100644
--- a/ooni/nettests/experimental/parasitictraceroute.py
+++ b/ooni/nettests/experimental/parasitictraceroute.py
@@ -1,129 +1,48 @@
-# -*- encoding: utf-8 -*-
-#
-# :authors: Arturo Filastò
-# :licence: see LICENSE
-
 from twisted.python import usage
-from twisted.internet import defer
-
+from twisted.internet import defer, reactor
 from ooni.templates import scapyt
-
-from scapy.all import *
-
 from ooni.utils import log
+from ooni.utils.txscapy import ParasiticTraceroute
+from ooni.settings import config
 
-class UsageOptions(usage.Options):
-    optParameters = [['backend', 'b', 'google.com', 'Test backend to use'],
-                    ['timeout', 't', 5, 'The timeout for the traceroute test'],
-                    ['maxttl', 'm', 64, 'The maximum value of ttl to set on packets'],
-                    ['dstport', 'd', 80, 'Set the destination port of the traceroute test'],
-                    ['srcport', 'p', None, 'Set the source port to a specific value']]
+from scapy.all import TCPerror, IPerror
 
-class ParasiticalTracerouteTest(scapyt.BaseScapyTest):
-    name = "Parasitic TCP Traceroute Test"
-    author = "Arturo Filastò"
-    version = "0.1"
+class ParasiticTracerouteTest(scapyt.BaseScapyTest):
+    name = "Parasitic Traceroute Test"
+    description = "Injects duplicate TCP packets with varying TTL values by sniffing traffic"
+    version = '0.1'
 
-    usageOptions = UsageOptions
+    samplePeriod = 40
 
     def setUp(self):
-        def get_sport():
-            if self.localOptions['srcport']:
-                return int(self.localOptions['srcport'])
+        self.report['parasitic_traceroute'] = {}
+
+    def test_parasitic_traceroute(self):
+        self.pt = ParasiticTraceroute()
+        config.scapyFactory.registerProtocol(self.pt)
+        d = defer.Deferred()
+        reactor.callLater(self.samplePeriod, d.callback, self.pt)
+        return d
+
+    def postProcessor(self, *args, **kwargs):
+        self.pt.stopListening()
+        self.report['received_packets'] = self.pt.received_packets
+
+        for packet in self.pt.received_packets:
+            k = (packet[IPerror].id, packet[TCPerror].sport, packet[TCPerror].dport, packet[TCPerror].seq)
+            if k in self.pt.matched_packets:
+                ttl = self.pt.matched_packets[k]['ttl']
             else:
-                return random.randint(1024, 65535)
-        self.get_sport = get_sport
-
-        self.dst_ip = socket.gethostbyaddr(self.localOptions['backend'])[2][0]
-
-        self.dport = int(self.localOptions['dstport'])
-        self.max_ttl = int(self.localOptions['maxttl'])
-
-    @defer.inlineCallbacks
-    def test_parasitic_tcp_traceroute(self):
-        """
-        Establishes a TCP stream, then sequentially sends TCP packets with
-        increasing TTL until we reach the ttl of the destination.
-
-        Requires the backend to respond with an ACK to our SYN packet (i.e.
-        the port must be open)
-
-        XXX this currently does not work properly. The problem lies in the fact
-        that we are currently using the scapy layer 3 socket. This socket makes
-        packets received be trapped by the kernel TCP stack, therefore when we
-        send out a SYN and get back a SYN-ACK the kernel stack will reply with
-        a RST because it did not send a SYN.
-
-        The quick fix to this would be to establish a TCP stream using socket
-        calls and then "cannibalizing" the TCP session with scapy.
-
-        The real fix is to make scapy use libpcap instead of raw sockets
-        obviously as we previously did... arg.
-        """
-        sport = self.get_sport()
-        dport = self.dport
-        ipid = int(RandShort())
-
-        ip_layer = IP(dst=self.dst_ip,
-                id=ipid, ttl=self.max_ttl)
-
-        syn = ip_layer/TCP(sport=sport, dport=dport, flags="S", seq=0)
-
-        log.msg("Sending...")
-        syn.show2()
-
-        synack = yield self.sr1(syn)
-
-        log.msg("Got response...")
-        synack.show2()
-
-        if not synack:
-            log.err("Got no response. Try increasing max_ttl")
-            return
-
-        if synack[TCP].flags == 11:
-            log.msg("Got back a FIN ACK. The destination port is closed")
-            return
-
-        elif synack[TCP].flags == 18:
-            log.msg("Got a SYN ACK. All is well.")
-        else:
-            log.err("Got an unexpected result")
-            return
-
-        ack = ip_layer/TCP(sport=synack.dport,
-                            dport=dport, flags="A",
-                            seq=synack.ack, ack=synack.seq + 1)
-
-        yield self.send(ack)
-
-        self.report['hops'] = []
-        # For the time being we make the assumption that we are NATted and
-        # that the NAT will forward the packet to the destination even if the TTL has 
-        for ttl in range(1, self.max_ttl):
-            log.msg("Sending packet with ttl of %s" % ttl)
-            ip_layer.ttl = ttl
-            empty_tcp_packet = ip_layer/TCP(sport=synack.dport,
-                    dport=dport, flags="A",
-                    seq=synack.ack, ack=synack.seq + 1)
-
-            answer = yield self.sr1(empty_tcp_packet)
-            if not answer:
-                log.err("Got no response for ttl %s" % ttl)
-                continue
-
-            try:
-                icmp = answer[ICMP]
-                report = {'ttl': empty_tcp_packet.ttl,
-                    'address': answer.src,
-                    'rtt': answer.time - empty_tcp_packet.time
-                }
-                log.msg("%s: %s" % (dport, report))
-                self.report['hops'].append(report)
-
-            except IndexError:
-                if answer.src == self.dst_ip:
-                    answer.show()
-                    log.msg("Reached the destination. We have finished the traceroute")
-                    return
+                ttl = 'unknown'
+            hop = (ttl, packet.src)
+            path = 'hops_%s' % packet[IPerror].dst
+            if path in self.report['parasitic_traceroute']:
+               self.report['parasitic_traceroute'][path].append(hop)
+            else:
+               self.report['parasitic_traceroute'][path] = [hop]
+        for p in self.report['parasitic_traceroute'].keys():
+            self.report['parasitic_traceroute'][p].sort(key=lambda x: x[0])
+                
+        self.report['sent_packets'] = self.pt.sent_packets
+        return self.report
 
diff --git a/ooni/nettests/manipulation/parasitictraceroute.py b/ooni/nettests/manipulation/parasitictraceroute.py
deleted file mode 100644
index c8aa3ed..0000000
--- a/ooni/nettests/manipulation/parasitictraceroute.py
+++ /dev/null
@@ -1,48 +0,0 @@
-from twisted.python import usage
-from twisted.internet import defer, reactor
-from ooni.templates import scapyt
-from ooni.utils import log
-from ooni.utils.txscapy import ParasiticTraceroute
-from ooni.settings import config
-
-from scapy.all import TCPerror, IPerror
-
-class ParasiticTracerouteTest(scapyt.BaseScapyTest):
-    name = "Parasitic Traceroute Test"
-    description = "Injects duplicate TCP packets with varying TTL values by sniffing traffic"
-    version = '0.1'
-
-    samplePeriod = 40
-
-    def setUp(self):
-        self.report['parasitic_traceroute'] = {}
-
-    def test_parasitic_traceroute(self):
-        self.pt = ParasiticTraceroute()
-        config.scapyFactory.registerProtocol(self.pt)
-        d = defer.Deferred()
-        reactor.callLater(self.samplePeriod, d.callback, self.pt)
-        return d
-
-    def postProcessor(self, *args, **kwargs):
-        self.pt.stopListening()
-        self.report['received_packets'] = self.pt.received_packets
-
-        for packet in self.pt.received_packets:
-            k = (packet[IPerror].id, packet[TCPerror].sport, packet[TCPerror].dport, packet[TCPerror].seq)
-            if k in self.pt.matched_packets:
-                ttl = self.pt.matched_packets[k]['ttl']
-            else:
-                ttl = 'unknown'
-            hop = (ttl, packet.src)
-            path = 'hops_%s' % packet[IPerror].dst
-            if path in self.report['parasitic_traceroute']:
-               self.report['parasitic_traceroute'][path].append(hop)
-            else:
-               self.report['parasitic_traceroute'][path] = [hop]
-        for p in self.report['parasitic_traceroute'].keys():
-            self.report['parasitic_traceroute'][p].sort(key=lambda x: x[0])
-                
-        self.report['sent_packets'] = self.pt.sent_packets
-        return self.report
-





More information about the tor-commits mailing list