Source code for wltrace.fusion

#!/usr/bin/env python

import argparse
import datetime

from collections import OrderedDict
import numpy as np

import progressbar as pbar

import dot11
import wltrace
import pcap
import utils

import logging
logging.basicConfig(
    format='[%(asctime)s] %(levelname)s [%(filename)11s:%(lineno)4d]'
    ' %(message)s',
    level=logging.DEBUG)
logger = logging.getLogger('pyparser')


[docs]def arg_parser(): parser = argparse.ArgumentParser() parser.add_argument('--traces', nargs='+', required=True, help="Traces to fusion.") parser.add_argument('--out', required=True, help="Output trace.") parser.add_argument('--verbose', action='store_true', help="Verbose output.") return parser
[docs]class Aggregator(object): def __init__(self, trace1, trace2, verbose=False, *args, **kwargs): self.trace1 = trace1 self.trace2 = trace2 self.merged_trace = [] self.drifts = [] self.verbose = verbose
[docs] def do_aggregate(self): if not isinstance(self.trace1, list): self.trace1 = list(self.trace1) if not isinstance(self.trace2, list): self.trace2 = list(self.trace2) hash1 = OrderedDict((p.hash, p) for p in self.trace1 if dot11.is_beacon(p) and p.phy.mactime is not None) hash2 = OrderedDict((p.hash, p) for p in self.trace2 if dot11.is_beacon(p) and p.phy.mactime is not None) common_hash = [h for h in hash1 if h in hash2] if self.verbose: logger.debug("Beacons:: Trace1: %d, Trace2: %d, Common: %d" % (len(hash1), len(hash2), len(common_hash))) if len(common_hash) < 2: logger.warning("Less than 2 common beacons, can not merge.") self.merged_trace = self.trace1 base_mactime = hash1[common_hash[0]].phy.mactime base_ts = hash1[common_hash[0]].ts widgets = [pbar.Percentage(), pbar.Bar(), pbar.ETA()] bar = pbar.ProgressBar(widgets=widgets, maxval=len(common_hash)) if self.verbose: progress = 0 bar.start() for first_beacon, second_beacon in utils.pairwise(common_hash): t1_a, t2_a = hash1[first_beacon].phy.mactime, hash1[ second_beacon].phy.mactime t1_b, t2_b = hash2[first_beacon].phy.mactime, hash2[ second_beacon].phy.mactime duration = t2_a - t1_a ratio = float(duration) / (t2_b - t1_b) drift = (t2_b - t1_b) - (t2_a - t1_a) self.drifts.append((duration, drift)) for p in self.trace2[hash2[first_beacon].counter: (hash2[second_beacon].counter - 1)]: if p.phy.mactime is not None: p.phy.mactime = int(ratio * (p.phy.mactime - t1_b) + t1_a) self.merged_trace.append(hash1[first_beacon]) for pkt in sorted( self.trace1[hash1[first_beacon].counter: (hash1[second_beacon].counter - 1)] + self.trace2[hash2[first_beacon].counter:( hash2[second_beacon].counter - 1)], key=lambda p: p.phy.mactime): if pkt.phy.mactime is None: continue if (pkt.phy.mactime - self.merged_trace[-1].phy.mactime) < 5\ and pkt.hash == self.merged_trace[-1].hash: continue self.merged_trace.append(pkt) if self.verbose: bar.update(progress) progress += 1 self.merged_trace.append(hash1[common_hash[-1]]) if self.verbose: bar.finish() intervals = [t[0] for t in self.drifts] drifts = [t[1] for t in self.drifts] logger.debug("Intervals: %d, min: %d, max: %d, mean: %d" % (len(intervals), min(intervals), max(intervals), np.mean(intervals))) logger.debug("drifts: %d, min: %d, max: %d, mean: %d" % (len(drifts), min(drifts), max(drifts), np.mean(drifts))) logger.debug("Trace1: %d, Trace2: %d, Merged: %d" % (len(self.trace1), len(self.trace2), len(self.merged_trace))) # adjust packet timestamp and counter for c, p in enumerate(self.merged_trace, start=1): p.ts = base_ts + \ datetime.timedelta(microseconds=(p.phy.mactime - base_mactime)) p.counter = c
[docs]def main(): args = arg_parser().parse_args() traces = [wltrace.load_file(p, aggregate_ack=False) for p in args.traces] fused = traces[0] logger.debug("Starting with %s" % (traces[0].path)) for t in traces[1:]: logger.debug("Merging %s" % (t.path)) a = Aggregator(fused, t, verbose=args.verbose) a.do_aggregate() fused = a.merged_trace pcap.PcapCapture.save(args.out, fused)
if __name__ == '__main__': main()