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