From c16a1c3b6f1fdacf2ad365ff2a35252d7eb73c4e Mon Sep 17 00:00:00 2001 From: Laurent Ghigonis Date: Mon, 22 Jul 2013 03:23:01 +0200 Subject: autoscan: some code and add tests --- autoscan/Makefile | 8 +++ autoscan/autoscan.py | 115 ++++++++++++++++++++++++++++++++------- autoscan/tests/Makefile | 5 ++ autoscan/tests/spoofbin/ifconfig | 12 ++++ autoscan/tests/spoofbin/iwconfig | 4 ++ autoscan/tests/spoofbin/route | 7 +++ autoscan/tests/test_autoscan.sh | 19 +++++++ 7 files changed, 150 insertions(+), 20 deletions(-) create mode 100644 autoscan/Makefile mode change 100644 => 100755 autoscan/autoscan.py create mode 100644 autoscan/tests/Makefile create mode 100755 autoscan/tests/spoofbin/ifconfig create mode 100755 autoscan/tests/spoofbin/iwconfig create mode 100755 autoscan/tests/spoofbin/route create mode 100755 autoscan/tests/test_autoscan.sh diff --git a/autoscan/Makefile b/autoscan/Makefile new file mode 100644 index 0000000..0c13c1c --- /dev/null +++ b/autoscan/Makefile @@ -0,0 +1,8 @@ +all: + @echo "noting to do" + +tests: + make -C tests/ + +.PHONY: tests + diff --git a/autoscan/autoscan.py b/autoscan/autoscan.py old mode 100644 new mode 100755 index f614db3..f3a5734 --- a/autoscan/autoscan.py +++ b/autoscan/autoscan.py @@ -6,42 +6,59 @@ # Usage: autoscan.py [interfaces] # by default, monitor all network interfaces +# Should work on all Linux versions # Each time network connectivity become available after a cut-off, -# run some tests and store results in a file db +# run some tests and store results in +# YYYYMMDD_hhmmss_interface/testname/output" # * ifconfig # * if WIFI, iwconfig +# * /etc/resolv.conf +# * 15s pcap # * route -n # * traceroute # * local net IP scan # * public IP (curl ifconfig.me) # * ping 8.8.8.8 +# TODO +# rename log directory to YYYYMMDD_hhmmss_interface_[pubip/localip] + import sys +import os import time import subprocess +import traceback +import re +import argparse -class Mon_iface(object): +class Autoscan_iface(object): PUBIP = "8.8.8.8" - def __init__(self, iface, logpath): + def __init__(self, iface, logpath=".", verbose=False): self.iface = iface self.logpath = logpath + self.verbose = verbose self.date = None # set by _do_tests() - def run(self): + def monitor(self): self._do_tests() while True: self._wait_down() self._wait_up() self._do_tests() + def run_now(self): + self._do_tests() + def _wait_up(self): while True: out, err, code = self._exec( ['ifconfig', self.iface]) up = re.search(r'UP', out) - if up: + ip4 = re.search(r'inet (\S+)', out) + ip6 = re.search(r'inet6 (\S+)', out) + if up and (ip4 or ip6): break time.sleep(1) @@ -52,17 +69,28 @@ class Mon_iface(object): up = re.search(r'UP', out) if not up: break + # XXX also consider sleep as interface down time.sleep(1) def _do_tests(self): self.date = time.strftime("%Y%m%d_%H%M%S", time.gmtime()) - self._test_ifconfig() - self._test_iwconfig() - self._test_route() - self._test_scan() - self._test_pubip_get() - self._test_pubip_ping() - self._test_pubip_traceroute() + self._do_tests_run(self._test_ifconfig) + self._do_tests_run(self._test_iwconfig) + self._do_tests_run(self._test_route) + #self._do_tests_run(self._test_resolv) + #self._do_tests_run(self._test_pubip_get) + self._do_tests_run(self._test_pubip_ping) + #self._do_tests_run(self._test_pubip_traceroute) + #self._do_tests_run(self._test_pcap) + #self._do_tests_run(self._test_scan) + # XXX rename dir + + def _do_tests_run(self, func): + try: + func() + except Exception, e: + print("test %s failed: %s" % (func, e)) + traceback.print_exc() def _test_ifconfig(self): out, err, code = self._exec( @@ -75,6 +103,24 @@ class Mon_iface(object): ip6 = re.search(r'inet6 (\S+)', out) if ip6: self._store("ifconfig/ip6", ip6.group(1)) + def _test_iwconfig(self): + out, err, code = self._exec( + ['iwconfig', self.iface]) + if len(out) == 0: + return # not a WIFI interface + self._store("iwconfig/out", out) + essid = re.search(r'ESSID:(\S+)', out) + if essid: self._store("iwconfig/essid", essid.group(1)) + ap = re.search(r'Access Point: (\S+)', out) + if ap: self._store("iwconfig/ap", ap.group(1)) + + def _test_route(self): + out, err, code = self._exec( + ['route', '-n']) + self._store("route/out", out) + gw = re.findall(r'(\S+)', out.split('\n')[2])[1] + if gw: self._store("route/gw", gw) + def _test_pubip_ping(self): out, err, code = self._exec( ['ping', '-W', '3', '-c', '1', self.PUBIP]) @@ -87,17 +133,46 @@ class Mon_iface(object): out, err = p.communicate() return out, err, p.returncode - def _store(self, suffix, val): + def _store(self, suffix, txt): name = "%s/%s_%s/%s" % (self.logpath, self.date, self.iface, suffix) + d = os.path.dirname(name) + if not os.path.isdir(d): + os.makedirs(d) + if self.verbose: + print("%s = %s" % (name, txt)) f = open(name, "w+") - f.write(txt) + f.write(str(txt)) f.close() -logpath = "." - -# XXX netifaces -# XXX thread per interface -Mon_iface("eth0", logpath) - +# XXX all ifaces by default, use netifaces + +parser = argparse.ArgumentParser() +parser.add_argument("interfaces", nargs='+', + help="Interfaces to use") +parser.add_argument("-f", "--foreground", action="store_true", + help="Run in foreground, do not daemonize") +parser.add_argument("-o", "--outdir", action="store", default=".", + help="increase output verbosity") +parser.add_argument("-r", "--runnow", action="store_true", + help="Run tests/scans now and exit") +parser.add_argument("-v", "--verbose", action="store_true", + help="increase output verbosity") +args = parser.parse_args() + +for iface in args.interfaces: + pid = os.fork() + if pid == 0: + autoscan = Autoscan_iface(iface, args.outdir, args.verbose) + if args.runnow: + autoscan.run_now() + else: + autoscan.monitor() + # UNREACHED + +if args.foreground: + while True: + try: os.wait() # XXX wait all pids ? + except: break + diff --git a/autoscan/tests/Makefile b/autoscan/tests/Makefile new file mode 100644 index 0000000..77bebab --- /dev/null +++ b/autoscan/tests/Makefile @@ -0,0 +1,5 @@ +all: clean + ./test_autoscan.sh + +clean: + rm -rf test_output/ diff --git a/autoscan/tests/spoofbin/ifconfig b/autoscan/tests/spoofbin/ifconfig new file mode 100755 index 0000000..0df746d --- /dev/null +++ b/autoscan/tests/spoofbin/ifconfig @@ -0,0 +1,12 @@ +#!/bin/sh + +echo "eth0: flags=4163 mtu 1500 + inet 10.137.2.9 netmask 255.255.255.255 broadcast 10.255.255.255 + inet6 fe80::216:3eff:fe5e:6c07 prefixlen 64 scopeid 0x20 + ether 00:16:3e:5e:6c:07 txqueuelen 1000 (Ethernet) + RX packets 74405 bytes 93418449 (89.0 MiB) + RX errors 0 dropped 0 overruns 0 frame 0 + TX packets 54640 bytes 5365525 (5.1 MiB) + TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 + device interrupt 47 +" diff --git a/autoscan/tests/spoofbin/iwconfig b/autoscan/tests/spoofbin/iwconfig new file mode 100755 index 0000000..2302264 --- /dev/null +++ b/autoscan/tests/spoofbin/iwconfig @@ -0,0 +1,4 @@ +#!/bin/sh + +echo "eth0 no wireless extensions. +" diff --git a/autoscan/tests/spoofbin/route b/autoscan/tests/spoofbin/route new file mode 100755 index 0000000..20abcc3 --- /dev/null +++ b/autoscan/tests/spoofbin/route @@ -0,0 +1,7 @@ +#!/bin/sh + +echo "Kernel IP routing table +Destination Gateway Genmask Flags Metric Ref Use Iface +0.0.0.0 10.137.2.1 0.0.0.0 UG 0 0 0 eth0 +10.137.2.1 0.0.0.0 255.255.255.255 UH 0 0 0 eth0 +" diff --git a/autoscan/tests/test_autoscan.sh b/autoscan/tests/test_autoscan.sh new file mode 100755 index 0000000..bea2c34 --- /dev/null +++ b/autoscan/tests/test_autoscan.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +err() { + echo "ERROR: $1" + exit 1 +} + +export PATH="./spoofbin/:$PATH" + +../autoscan.py -f -o test_output/ -r eth0 ||err "autoscan execution failed" + +# XXX test output dirs +dir="test_output/$(ls -1 test_output |tail -n1)" +[[ $(cat $dir/route/gw) = "10.137.2.1" ]] ||err "route/gw" +[[ $(cat $dir/ifconfig/ip4) = "10.137.2.9" ]] ||err "ifconfig/ip4" +[[ $(cat $dir/ifconfig/ip6) = "fe80::216:3eff:fe5e:6c07" ]] ||err "ifconfig/ip6" +[[ $(cat $dir/pubip_ping/code) = "0" ]] ||err "pubip_ping/code" + +echo "TEST OK" -- cgit v1.2.3-59-g8ed1b