initial commit

master
Tomek Dubrownik 2012-01-26 19:58:09 +01:00
commit ae406076f7
5 changed files with 178 additions and 0 deletions

117
at.py Normal file
View File

@ -0,0 +1,117 @@
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
import logging
import sqlite3
import threading
import traceback
from datetime import datetime
from wsgiref import simple_server
from pesto import Response, dispatcher_app
from time import sleep, time
from collections import namedtuple
from jinja2 import Environment, FileSystemLoader
import config
dispatcher = dispatcher_app()
logger = logging.getLogger()
env = Environment(loader=FileSystemLoader('templates'))
conn = None
updater = None
from functools import wraps
def render(filepath):
def decorator(f):
@wraps(f)
def func(request, *a, **kw):
template = env.get_template(filepath)
data = f(request, *a, **kw)
return Response([template.render(**data)])
return func
return decorator
def strfts(ts, format='%d/%m/%Y %H:%M'):
return datetime.fromtimestamp(ts).strftime(format)
env.filters['strfts'] = strfts
def setup_db():
conn = sqlite3.connect(config.db)
conn.row_factory = sqlite3.Row
return conn
DeviceInfo = namedtuple('DeviceInfo', ['hwaddr', 'owner', 'ignored'])
User = namedtuple('User', ['login', 'passwd', 'url'])
def get_device_info(conn, hwaddr):
return list(get_device_infos(conn, (hwaddrs,)))[0]
def get_device_infos(conn, hwaddrs):
stmt = '''select hwaddr, name, ignored, login, url from
devices left join users on devices.owner = users.userid
where devices.hwaddr in (''' + ','.join(['?'] * len(hwaddrs)) + ')'
for row in conn.execute(stmt, hwaddrs):
owner = User(row['login'], None, row['url']) if row['login'] else None
ignored = row['ignored']
yield DeviceInfo(row['hwaddr'], owner, ignored)
class Updater(threading.Thread):
def __init__(self, cap_file, timeout, *a, **kw):
self.cap_file = cap_file
self.timeout = timeout
self.lock = threading.Lock()
self.active = {}
threading.Thread.__init__(self, *a, **kw)
def purge_stale(self):
now = time()
for addr, atime in self.active.items():
if now - atime > self.timeout:
del self.active[addr]
def get_active_devices(self):
self.lock.acquire()
self.purge_stale()
r = dict(self.active)
self.lock.release()
return r
def update(self, hwaddr):
self.lock.acquire()
self.active[hwaddr] = time()
self.lock.release()
def run(self):
while True:
try:
f = open(self.cap_file, 'r', buffering=0)
logger.info('Updater ready on cap file %s', self.cap_file)
while True:
hwaddr = f.readline().strip()
if not hwaddr:
break
self.update(hwaddr)
logger.info('logged dhcp request from %s', hwaddr)
logging.warning('Cap file %s closed, reopening', self.cap_file)
except Exception as e:
logging.error('Updater got an exception:\n' + \
traceback.format_exc(e))
sleep(10.0)
@dispatcher.match('/', 'GET')
@render('main.html')
def now_at(request):
devices = updater.get_active_devices()
device_infos = list(get_device_infos(conn, devices.keys()))
device_infos.sort(key=lambda di: devices.__getitem__)
users = list(dict((info.owner, devices[info.hwaddr]) for info in device_infos
if info.owner and not info.ignored).iteritems())
users.sort(key=lambda (u, a): a, reverse=True)
unknown = set(devices.keys()) - set(d.hwaddr for d in device_infos)
return dict(users=users, unknown=unknown)
port = 8080
if __name__ == '__main__':
print env.list_templates()
logger.setLevel(logging.DEBUG)
logger.addHandler(logging.StreamHandler())
conn = setup_db()
updater = Updater(config.cap_file, config.timeout)
updater.start()
server = simple_server.make_server('', port, dispatcher)
server.serve_forever()

30
cap.py Normal file
View File

@ -0,0 +1,30 @@
import logging
import pcapy
import struct
interface = 'wlan0'
target = './dhcp-cap'
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
logger.addHandler(logging.StreamHandler())
def hwaddr_ascii(packet):
# picking up MAC directly from ethernet frame
return ':'.join('%02x' % ord(c) for c in packet[6:12])
def capture_dhcp(itf):
f = open(target, 'w')
reader = pcapy.open_live(itf, 4096, False, 5000)
reader.setfilter('udp dst port 67')
def callback(header, packet):
hwaddr = hwaddr_ascii(packet)
logger.info('Captured dhcp request from %s', hwaddr)
f.write(hwaddr + '\n')
f.flush()
try:
while True:
reader.dispatch(1, callback)
except KeyboardInterrupt:
pass
capture_dhcp('wlan0')

4
config.py Normal file
View File

@ -0,0 +1,4 @@
db = './at.db'
cap_file = './dhcp-cap'
timeout = 300

13
dbsetup.sql Normal file
View File

@ -0,0 +1,13 @@
create table users (
userid integer primary key,
login varchar(50) unique not null,
pass character(64),
url varchar(300)
);
create table devices (
hwaddr character(17) primary key,
name varchar(50),
owner integer references users(userid),
ignored boolean
);

14
templates/main.html Normal file
View File

@ -0,0 +1,14 @@
<html>
Recently at <a href="http://www.hackerspace.pl">hackerspace</a>:
<ul>
{% for user, timestamp in users %}
<li>
{% if user.url %}<a href="{{ user.url }}">{% endif %}
{{ user.login }} ({{ timestamp|strfts() }})
{% if user.url %}</a>{% endif %}
</li>
{% endfor %}
</ul>
<hr>
There are {{ unknown|length }} unknown devices operating.
</html>