[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [ooni-probe/master] Re-ported echo. Fixed parameters not being passed through txscapy.sr to parent methods.
commit 8af6d133c5f48ae516842674602a5198c9dcece8
Author: Isis Lovecruft <isis@xxxxxxxxxxxxxx>
Date: Fri Nov 16 15:20:49 2012 +0000
Re-ported echo. Fixed parameters not being passed through txscapy.sr to parent methods.
---
nettests/bridge_reachability/echo.py | 141 ++++++++++++++++++++++++---------
ooni/utils/txscapy.py | 12 ++-
2 files changed, 110 insertions(+), 43 deletions(-)
diff --git a/nettests/bridge_reachability/echo.py b/nettests/bridge_reachability/echo.py
index df121b4..06c3aa4 100644
--- a/nettests/bridge_reachability/echo.py
+++ b/nettests/bridge_reachability/echo.py
@@ -16,34 +16,39 @@ import os
import sys
from twisted.python import usage
-from twisted.internet import reactor, defer
-from ooni.nettest import NetTestCase
+from twisted.internet import reactor, defer, address
+from ooni import nettest
from ooni.utils import log, net, Storage
try:
- from scapy.all import IP, ICMP
- from scapy.all import sr1
- from ooni.lib import txscapy
- from ooni.lib.txscapy import txsr, txsend
- from ooni.templates.scapyt import BaseScapyTest
-except:
+ from scapy.all import IP, ICMP
+ from scapy.all import sr1
+ from ooni.utils import txscapy
+except Exception, e:
log.msg("This test requires scapy, see www.secdev.org/projects/scapy")
+ log.exception(e)
class UsageOptions(usage.Options):
+ """
+ Options for EchoTest.
+
+ Note: 'count', 'size', and 'ttl' have yet to be implemented.
+ """
optParameters = [
['dst', 'd', None, 'Host IP to ping'],
['file', 'f', None, 'File of list of IPs to ping'],
+ ['pcap', 'p', None, 'Save pcap to this file'],
['interface', 'i', None, 'Network interface to use'],
+ ['receive', 'r', True, 'Receive response packets'],
+ ['timeout', 't', 2, 'Seconds to wait if no response', int],
['count', 'c', 1, 'Number of packets to send', int],
- ['size', 's', 56, 'Number of bytes to send in ICMP data field', int],
- ['ttl', 'l', 25, 'Set the IP Time to Live', int],
- ['timeout', 't', 2, 'Seconds until timeout if no response', int],
- ['pcap', 'p', None, 'Save pcap to this file'],
- ['receive', 'r', True, 'Receive response packets']]
+ ['size', 's', 56, 'Bytes to send in ICMP data field', int],
+ ['ttl', 'l', 25, 'Set the IP Time to Live', int]]
-class EchoTest(BaseScapyTest):
+class EchoTest(nettest.NetTestCase):
"""
Basic ping test. This takes an input file containing one IP or hostname
+ per line.
"""
name = 'echo'
author = 'Isis Lovecruft <isis@xxxxxxxxxxxxxx>'
@@ -55,6 +60,22 @@ class EchoTest(BaseScapyTest):
#requiredOptions = ['dst']
def setUp(self, *a, **kw):
+ """
+ Send an ICMP-8 packet to a host IP, and process the response.
+
+ @param timeout:
+ Seconds after sending the last packet to timeout.
+ @param interface:
+ The interface to restrict listening to.
+ @param dst:
+ A single host to ping.
+ @param file:
+ A file of hosts to ping, one per line.
+ @param receive:
+ Whether or not to receive replies. Defaults to True.
+ @param pcap:
+ The file to save packet captures to.
+ """
self.destinations = {}
if self.localOptions:
@@ -87,11 +108,10 @@ class EchoTest(BaseScapyTest):
self.dstProcessor(self.file)
for address, details in self.destinations.items():
for labels, data in details.items():
- if not 'ans' in labels:
+ if not 'response' in labels:
self.dst = details['dst_ip']
else:
self.addDest(self.dst)
- log.debug("self.dst is now: %s" % self.dst)
log.debug("Initialization of %s test completed." % self.name)
@@ -107,31 +127,74 @@ class EchoTest(BaseScapyTest):
continue
self.addDest(line)
- def test_icmp(self):
+ def build_packets(self):
+ """
+ Construct a list of packets to send out.
+ """
+ packets = []
+ for dest, data in self.destinations.items():
+ pkt = IP(dst=dest)/ICMP()
+ packets.append(pkt)
+ ## XXX if a domain was specified, we need a way to check that
+ ## its IP matches the one we're seeing in pkt.src
+ #try:
+ # address.IPAddress(dest)
+ #except:
+ # data['dst_ip'] = pkt.dst
+ return packets
- def process_response(pkt, dest):
- try:
- ans, unans = pkt
- if ans:
- log.msg("Recieved echo-reply: %s" % pkt.summary())
- self.destinations[dest]['ans'] = a.show2()
- self.report['response'] = [a.show2() for a in ans]
- self.report['censored'] = False
- else:
- log.msg("No reply from %s. Possible censorship event." % dest)
- log.debug("Unanswered packets: %s" % unans.summary())
- self.report['response'] = [u.show2() for u in unans]
- self.report['censored'] = True
- except Exception, e:
- log.exception(e)
+ def test_icmp(self):
+ """
+ Send the list of ICMP packets.
+ TODO: add end summary progress report for % answered, etc.
+ """
try:
- for dest, data in self.destinations.items():
- reply = txsr(IP(dst=dest)/ICMP(),
- iface=self.interface,
- retry=self.count,
- multi=True,
- timeout=self.timeout)
- process = process_response(reply, dest)
+ def nicely(packets):
+ """Print scapy summary nicely."""
+ return list([x.summary() for x in packets])
+
+ def process_answered((answered, sent)):
+ """Callback function for txscapy.sr()."""
+ self.report['sent'] = nicely(sent)
+ self.report['answered'] = [nicely(ans) for ans in answered]
+
+ for req, resp in answered:
+ log.msg("Received echo-reply:\n%s" % resp.summary())
+ for dest, data in self.destinations.items():
+ if data['dst_ip'] == resp.src:
+ data['response'] = resp.summary()
+ data['censored'] = False
+ for snd in sent:
+ if snd.dst == resp.src:
+ answered.remove((req, resp))
+ return (answered, sent)
+
+ def process_unanswered((unanswered, sent)):
+ """
+ Callback function for remaining packets and destinations which
+ do not have an associated response.
+ """
+ if len(unanswered) > 0:
+ nicer = [nicely(unans) for unans in unanswered]
+ log.msg("Unanswered/remaining packets:\n%s"
+ % nicer)
+ self.report['unanswered'] = nicer
+ for dest, data in self.destinations.items():
+ if not 'response' in data:
+ log.msg("No reply from %s. Possible censorship event."
+ % dest)
+ data['response'] = None
+ data['censored'] = True
+ return (unanswered, sent)
+
+ packets = self.build_packets()
+ d = txscapy.sr(packets, iface=self.interface, multi=True)
+ d.addCallback(process_answered)
+ d.addErrback(log.exception)
+ d.addCallback(process_unanswered)
+ d.addErrback(log.exception)
+ self.report['destinations'] = self.destinations
+ return d
except Exception, e:
log.exception(e)
diff --git a/ooni/utils/txscapy.py b/ooni/utils/txscapy.py
index 2b108ca..9c33d18 100644
--- a/ooni/utils/txscapy.py
+++ b/ooni/utils/txscapy.py
@@ -1,4 +1,5 @@
-# -*- coding:utf8 -*-
+# -*- coding: utf-8 -*-
+#
# txscapy
# *******
# Here shall go functions related to using scapy with twisted.
@@ -32,7 +33,7 @@ class TXPcapWriter(PcapWriter):
class ScapyProtocol(abstract.FileDescriptor):
def __init__(self, super_socket=None,
- reactor=None, timeout=None, receive=True):
+ reactor=None, timeout=None, receive=True, *a, **kw):
abstract.FileDescriptor.__init__(self, reactor)
# By default we use the conf.L3socket
if not super_socket:
@@ -54,7 +55,10 @@ class ScapyProtocol(abstract.FileDescriptor):
# This deferred will fire when we have finished sending a receiving packets.
self.d = defer.Deferred()
self.debug = False
+
self.multi = False
+ if kw['multi']:
+ self.multi = kw['multi']
# XXX this needs to be implemented. It would involve keeping track of
# the state of the sending via the super socket file descriptor and
# firing the callback when we have concluded sending. Check out
@@ -127,9 +131,9 @@ class ScapyProtocol(abstract.FileDescriptor):
self.sendPackets(packets)
return self.d
-def sr(x, filter=None, iface=None, nofilter=0, timeout=None):
+def sr(x, filter=None, iface=None, nofilter=0, timeout=None, *a, **kw):
super_socket = conf.L3socket(filter=filter, iface=iface, nofilter=nofilter)
- sp = ScapyProtocol(super_socket=super_socket, timeout=timeout)
+ sp = ScapyProtocol(super_socket=super_socket, timeout=timeout, *a, **kw)
return sp.startSending(x)
def send(x, filter=None, iface=None, nofilter=0, timeout=None):
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits