diff --git a/patator.py b/patator.py
index 0adc655..c07f560 100755
--- a/patator.py
+++ b/patator.py
@@ -604,28 +604,119 @@ TODO
# logging {{{
import logging
logging._levelNames[logging.ERROR] = 'FAIL'
-class MyLoggingFormatter(logging.Formatter):
-
- dft_fmt = '%(asctime)s %(name)-7s %(levelname)7s - %(message)s'
- dbg_fmt = '%(asctime)s %(name)-7s %(levelname)7s [%(threadName)s] %(message)s'
+logger = logging.getLogger('patator')
- def __init__(self):
- logging.Formatter.__init__(self, MyLoggingFormatter.dft_fmt, datefmt='%H:%M:%S')
+class TXTFormatter(logging.Formatter):
+ def __init__(self, indicatorsfmt):
+ self.resultfmt = '%(asctime)s %(name)-7s %(levelname)7s - ' + ' '.join('%%(%s)%ss' % (k, v) for k, v in indicatorsfmt) + ' | %(candidate)-34s | %(num)5s | %(mesg)s'
+ logging.Formatter.__init__(self, datefmt='%H:%M:%S')
def format(self, record):
+ if record.msg:
if record.levelno == 10: # DEBUG
- self._fmt = MyLoggingFormatter.dbg_fmt
+ self._fmt = '%(asctime)s %(name)-7s %(levelname)7s [%(threadName)s] %(message)s'
else:
- self._fmt = MyLoggingFormatter.dft_fmt
+ self._fmt = '%(asctime)s %(name)-7s %(levelname)7s - %(message)s'
+ else:
+ self._fmt = self.resultfmt
- return logging.Formatter.format(self, record)
+ return logging.Formatter.format(self, record)
+
+class CSVFormatter(logging.Formatter):
+ def __init__(self, indicatorsfmt):
+ fmt = '%(asctime)s,%(levelname)s,'+','.join('%%(%s)s' % name for name, _ in indicatorsfmt)+',%(candidate)s,%(num)s,%(mesg)s'
+
+ logging.Formatter.__init__(self, fmt, datefmt='%H:%M:%S')
+
+class XMLFormatter(logging.Formatter):
+ def __init__(self, indicatorsfmt):
+ fmt = '''
+''' + '\n'.join(' <{0}>%({0})s{0}>'.format(name) for name, _ in indicatorsfmt) + '''
+ %(candidate)s
+ %(num)s
+ %(mesg)s
+'''
+
+ logging.Formatter.__init__(self, fmt, datefmt='%H:%M:%S')
+
+class Output:
+
+ def __init__(self, indicatorsfmt, argv, log_dir, auto_log):
+
+ self.indicatorsfmt = indicatorsfmt
+ self.cmdline = ' '.join(argv)
+
+ if auto_log:
+ self.log_dir = create_time_dir(log_dir or '/tmp/patator', auto_log)
+ elif log_dir:
+ self.log_dir = create_dir(log_dir)
+ else:
+ self.log_dir = None
+
+ handler_out = logging.StreamHandler()
+ handler_out.setFormatter(TXTFormatter(self.indicatorsfmt))
+ logger.addHandler(handler_out)
+
+ self.audit = logging.getLogger('audit')
+ self.audit.addHandler(logging.NullHandler())
+ self.audit.setLevel(logging.INFO)
+
+ if self.log_dir:
+ handler_log = logging.FileHandler(os.path.join(self.log_dir, 'RUNTIME.log'))
+ handler_log.setFormatter(TXTFormatter(self.indicatorsfmt))
+ logger.addHandler(handler_log)
+
+ handler_csv = logging.FileHandler(os.path.join(self.log_dir, 'RESULTS.csv'))
+ handler_xml = logging.FileHandler(os.path.join(self.log_dir, 'RESULTS.xml'))
+
+ handler_csv.setFormatter(CSVFormatter(self.indicatorsfmt))
+ handler_xml.setFormatter(XMLFormatter(self.indicatorsfmt))
+
+ self.audit.addHandler(handler_csv)
+ self.audit.addHandler(handler_xml)
+
+ def headers(self):
+
+ names = [name for name, _ in self.indicatorsfmt] + ['candidate', 'num', 'mesg']
+
+ if self.log_dir:
+ with open(os.path.join(self.log_dir, 'RUNTIME.log'), 'a') as f:
+ f.write('$ %s\n' % self.cmdline)
+
+ with open(os.path.join(self.log_dir, 'RESULTS.xml'), 'a') as f:
+ f.write('\n\n')
+
+ with open(os.path.join(self.log_dir, 'RESULTS.csv'), 'a') as f:
+ f.write('time,level,'+','.join(names)+',candidate,num,mesg\n')
+
+ logger.info(' '*70)
+ logger.info(None, extra=dict((n, n) for n in names))
+ logger.info('-'*70)
+
+ def log_result(self, typ, resp, candidate, num):
+
+ results = [(name, value) for (name, _), value in zip(self.indicatorsfmt, resp.indicators())]
+ results += [('candidate', candidate), ('num', num), ('mesg', resp)]
+
+ if typ == 'fail':
+ logger.error(None, extra=dict(results))
+ self.audit.error(None, extra=dict(results))
+ else:
+ logger.info(None, extra=dict(results))
+ self.audit.info(None, extra=dict(results))
+
+ def save(self, resp, num):
+ if self.log_dir:
+ filename = '%d_%s' % (num, ':'.join(map(str, resp.indicators())))
+ with open('%s/%s.txt' % (self.log_dir, filename), 'w') as f:
+ f.write(resp.dump())
+
+ def __del__(self):
+ if self.log_dir:
+ with open(os.path.join(self.log_dir, 'RESULTS.xml'), 'a') as f:
+ f.write('\n')
-handler = logging.StreamHandler()
-handler.setFormatter(MyLoggingFormatter())
-logger = logging.getLogger('patator')
-logger.setLevel(logging.INFO)
-logger.addHandler(handler)
# }}}
# imports {{{
@@ -1013,6 +1104,8 @@ Please read the README inside for more examples and usage information.
if opts.debug:
logger.setLevel(logging.DEBUG)
+ else:
+ logger.setLevel(logging.INFO)
if not len(args) > 0:
parser.print_usage()
@@ -1028,7 +1121,6 @@ Please read the README inside for more examples and usage information.
self.start_time = 0
self.total_size = 1
self.quit_now = False
- self.log_dir = None
self.thread_report = []
self.thread_progress = []
@@ -1046,6 +1138,8 @@ Please read the README inside for more examples and usage information.
self.num_threads = opts.num_threads
self.start, self.stop, self.resume = opts.start, opts.stop, opts.resume
+ self.output = Output(self.module.Response.indicatorsfmt, argv, opts.log_dir, opts.auto_log)
+
wlists = {}
kargs = []
for arg in args: # ('host=NET0', '0=10.0.0.0/24', 'user=COMBO10', 'password=COMBO11', '1=combos.txt', 'name=google.MOD2', '2=TLD')
@@ -1126,20 +1220,6 @@ Please read the README inside for more examples and usage information.
self.update_actions(x)
logger.debug('actions: %s' % self.actions)
-
- if opts.auto_log:
- self.log_dir = create_time_dir(opts.log_dir or '/tmp/patator', opts.auto_log)
- elif opts.log_dir:
- self.log_dir = create_dir(opts.log_dir)
-
- if self.log_dir:
- log_file = os.path.join(self.log_dir, 'RUNTIME.log')
- with open(log_file, 'a') as f:
- f.write('$ %s\n' % ' '.join(argv))
-
- handler = logging.FileHandler(log_file)
- handler.setFormatter(MyLoggingFormatter())
- logging.getLogger('patator').addHandler(handler)
def update_actions(self, arg):
actions, conditions = arg.split(':', 1)
@@ -1341,9 +1421,7 @@ Please read the README inside for more examples and usage information.
self.resume = [int(i) for i in self.resume.split(',')]
self.total_size -= sum(self.resume)
- logger.info('')
- logger.info(self.module.Response.logformat % self.module.Response.logheader)
- logger.info('-' * 70)
+ self.output.headers()
self.start_time = time()
count = 0
@@ -1526,13 +1604,11 @@ Please read the README inside for more examples and usage information.
p.current = current
p.seconds[p.done_count % len(p.seconds)] = seconds
- msg = self.module.Response.logformat % (resp.compact()+(current, offset, resp))
-
if 'fail' in actions:
- logger.error(msg)
+ self.output.log_result('fail', resp, current, offset)
elif 'ignore' not in actions:
- logger.info(msg)
+ self.output.log_result('hit', resp, current, offset)
if 'fail' in actions:
p.fail_count += 1
@@ -1543,10 +1619,7 @@ Please read the README inside for more examples and usage information.
elif 'ignore' not in actions:
p.hits_count += 1
- if self.log_dir:
- filename = '%d_%s' % (offset, ':'.join(map(str, resp.compact())))
- with open('%s/%s.txt' % (self.log_dir, filename), 'w') as f:
- f.write(resp.dump())
+ self.output.save(resp, offset)
self.push_final(resp)
@@ -1665,17 +1738,16 @@ class Response_Base:
('egrep', 'search for regex in mesg'),
)
- logformat = '%-5s %-4s %6s | %-34s | %5s | %s'
- logheader = ('code', 'size', 'time', 'candidate', 'num', 'mesg')
+ indicatorsfmt = [('code', -5), ('size', -4), ('time', 6)]
def __init__(self, code, mesg, timing=0, trace=None):
self.code = code
self.mesg = mesg
- self.time = isinstance(timing, Timing) and timing.time or time
+ self.time = isinstance(timing, Timing) and timing.time or time
self.size = len(mesg)
self.trace = trace
- def compact(self):
+ def indicators(self):
return self.code, self.size, '%.3f' % self.time
def __str__(self):
@@ -1853,7 +1925,7 @@ try:
import paramiko
l = logging.getLogger('paramiko.transport')
l.setLevel(logging.CRITICAL)
- l.addHandler(handler)
+ l.addHandler(logging.NullHandler())
except ImportError:
warnings.append('paramiko')
@@ -2637,8 +2709,8 @@ class VMauthd_login(TCP_Cache):
trace = resp + '\r\n'
try:
- resp = fp.sendcmd(cmd)
- trace += '%s\r\n%s\r\n' % (cmd, resp)
+ if user is not None or password is not None:
+ with Timing() as timing:
if user is not None:
cmd = 'USER %s' % user
@@ -2885,14 +2957,13 @@ except ImportError:
class Response_HTTP(Response_Base):
- logformat = '%-4s %-13s %6s | %-32s | %5s | %s'
- logheader = ('code', 'size:clen', 'time', 'candidate', 'num', 'mesg')
+ indicatorsfmt= [('code', -4), ('size:clen', -13), ('time', 6)]
def __init__(self, code, response, trace, content_length, time):
Response_Base.__init__(self, code, response, time, trace=trace)
self.content_length = content_length
- def compact(self):
+ def indicators(self):
return self.code, '%d:%d' % (self.size, self.content_length), '%.3f' % self.time
def __str__(self):