terom@236: #!/usr/bin/python terom@236: terom@236: """ terom@236: Analyze WLAN STA logs. terom@236: terom@236: Jul 3 23:05:04 buffalo-g300n-647682 daemon.info hostapd: wlan0-1: STA aa:bb:cc:dd:ee:ff WPA: group key handshake completed (RSN) terom@236: terom@236: """ terom@236: terom@236: __version__ = '0.1' terom@236: terom@236: import pvl.args terom@236: import pvl.syslog.args terom@236: import pvl.rrd.hosts terom@236: terom@236: import optparse terom@236: import logging; log = logging.getLogger('main') terom@236: terom@236: WLAN_STA_PROG = 'hostapd' terom@236: terom@236: def parse_argv (argv, doc = __doc__) : terom@236: """ terom@236: Parse command-line argv, returning (options, args). terom@236: """ terom@236: terom@236: prog = argv.pop(0) terom@236: args = argv terom@236: terom@236: # optparse terom@236: parser = optparse.OptionParser( terom@236: prog = prog, terom@236: usage = '%prog: [options] [ [...]]', terom@236: version = __version__, terom@236: description = doc, terom@236: ) terom@236: terom@236: # common terom@236: parser.add_option_group(pvl.args.parser(parser)) terom@236: parser.add_option_group(pvl.syslog.args.parser(parser, prog=WLAN_STA_PROG)) terom@236: terom@236: parser.add_option('--interfaces', metavar='PATH', terom@236: help="Load interface/node names from mapping file") terom@236: terom@236: parser.set_defaults( terom@236: ) terom@236: terom@236: # parse terom@236: options, args = parser.parse_args(args) terom@236: terom@236: # apply terom@236: pvl.args.apply(options) terom@236: terom@236: return options, args terom@236: terom@236: import re terom@236: terom@236: class HostapdHandler (object) : terom@236: HOSTAPD_STA_RE = re.compile(r'(?P.+?): STA (?P.+?) (?P.+)') terom@236: terom@236: def __init__ (self, interface_map=None) : terom@236: """ terom@236: interface_map - {(hostname, interface): (nodename, wlan)} terom@236: """ terom@236: self.interface_map = interface_map terom@236: terom@236: def parse (self, item) : terom@236: """ terom@236: Parse fields from a hostapd syslog message. terom@236: """ terom@236: terom@236: match = self.HOSTAPD_STA_RE.match(item['msg']) terom@236: terom@236: if not match : terom@236: return None terom@236: terom@236: return dict(item, **match.groupdict()) terom@236: terom@236: def build_sta (self, match) : terom@236: ap, wlan = match['host'], match['wlan'] terom@236: terom@236: # override? terom@236: if self.interface_map : terom@236: mapping = self.interface_map.get((ap, wlan)) terom@236: terom@236: if mapping : terom@236: ap, wlan = mapping terom@236: terom@236: build = dict( terom@236: timestamp = match['timestamp'], terom@236: ap = ap, terom@236: wlan = wlan, terom@236: sta = match['sta'], terom@236: msg = match['msg'], terom@236: ) terom@236: terom@236: terom@236: return build terom@236: terom@236: def main (argv) : terom@236: options, args = parse_argv(argv) terom@236: terom@236: if options.interfaces : terom@236: interfaces = dict(pvl.rrd.hosts.map_interfaces(options, open(options.interfaces))) terom@236: else : terom@236: interfaces = None terom@236: terom@236: # syslog terom@236: log.info("Open up syslog...") terom@236: syslog = pvl.syslog.args.apply(options) terom@236: handler = HostapdHandler(interface_map=interfaces) terom@236: terom@236: log.info("Enter mainloop...") terom@236: for source in syslog.main() : terom@236: for item in source: terom@236: match = handler.parse(item) terom@236: terom@236: if not match : terom@236: continue terom@236: elif 'sta' in match : terom@236: sta = handler.build_sta(match) terom@236: else : terom@236: continue terom@236: terom@236: print "{ap:>30}/{wlan:10} {sta:20} : {msg}".format(**sta) terom@236: terom@236: return 0 terom@236: terom@236: if __name__ == '__main__': terom@236: import sys terom@236: terom@236: sys.exit(main(sys.argv))