blob: 9a8734920e05b872384392a3cb4b64cc8f2fb846 [file] [log] [blame]
#!/usr/bin/env python
import collections
import json
import os.path
import random
import re
import sys
import traceback
import urllib
import wsgiref.handlers
import wsgiref.simple_server
import webapp2
import tornado.template
from google.appengine.api import memcache
from google.appengine.api import users
from google.appengine.ext import blobstore
from google.appengine.ext import ndb
from google.appengine.ext.webapp import blobstore_handlers
from google.appengine.ext.webapp import util
import wifipacket
BROADCAST = 'ff:ff:ff:ff:ff:ff'
loader = tornado.template.Loader('.')
def GoogleLoginRequired(func):
def Handler(self, *args, **kwargs):
user = users.get_current_user()
if not user:
self.redirect(users.create_login_url('/'))
elif not user.email().endswith('@google.com'):
self.response.set_status(401, 'Unauthorized')
self.response.write("Sorry. You're not an authorized user.")
else:
return func(self, *args, **kwargs)
return Handler
class PcapData(ndb.Model):
create_time = ndb.DateTimeProperty(auto_now_add=True)
filename = ndb.StringProperty()
show_hosts = ndb.StringProperty(repeated=True)
aliases = ndb.PickleProperty()
class _BaseHandler(webapp2.RequestHandler):
def render(self, template, **kwargs):
d = dict()
d.update(kwargs)
self.response.write(loader.load(template).generate(**d))
class MainHandler(_BaseHandler):
@GoogleLoginRequired
def get(self):
upload_url = blobstore.create_upload_url('/upload')
q = PcapData.query().order(-PcapData.create_time).fetch(10)
self.render('index.html',
upload_url=upload_url,
recents=q)
class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
def post(self):
upload_files = self.get_uploads()
sys.stderr.write('upload: %r\n' % upload_files)
blob_info = upload_files[0]
self.redirect('/view/%s' % blob_info.key())
def _Boxes(blob_info):
boxes = memcache.get(str(blob_info.key()), namespace='boxes')
if not boxes:
reader = blob_info.open()
boxes = collections.defaultdict(lambda: 0)
for p, frame in wifipacket.Packetize(reader):
if 'flags' in p and p.flags & wifipacket.Flags.BAD_FCS: continue
if 'ta' in p and 'ra' in p:
boxes[p.ta] += 1
boxes[p.ra] += 1
memcache.add(key=str(blob_info.key()), value=dict(boxes),
namespace='boxes')
return boxes
class ViewHandler(_BaseHandler):
@GoogleLoginRequired
def get(self, blobres):
blob_info = blobstore.BlobInfo.get(str(urllib.unquote(blobres)))
capdefault = PcapData.get_or_insert(str('*'), show_hosts=[], aliases={})
pcapdata = PcapData.get_or_insert(str(blob_info.key()),
filename=blob_info.filename,
show_hosts=[], aliases={})
try:
boxes = _Boxes(blob_info)
except ValueError as e:
self.response.set_status(500, 'Server error')
self.response.write('<pre>%s</pre>' % traceback.format_exc())
return
cutoff = max(boxes.itervalues()) * 0.01
cutboxes = [(b, n)
for b, n
in sorted(boxes.iteritems(), key=lambda x: -x[1])
if n >= cutoff and b != BROADCAST]
other = sum((n for n in boxes.itervalues() if n < cutoff))
aliases = pcapdata.aliases
if pcapdata.show_hosts:
checked = dict((h, 1) for h in pcapdata.show_hosts)
else:
checked = {}
for b, n in cutboxes:
checked[b] = (n > cutoff * 10)
for b in boxes.keys():
if b not in aliases:
aliases[b] = capdefault.aliases.get(b, b)
self.render('view.html',
blob=blob_info,
boxes=cutboxes,
other=other,
aliases=aliases,
checked=checked)
class SaveHandler(_BaseHandler):
@GoogleLoginRequired
def post(self, blobres):
blob_info = blobstore.BlobInfo.get(str(urllib.unquote(blobres)))
capdefault = PcapData.get_or_insert(str('*'), show_hosts=[], aliases={})
pcapdata = PcapData.get_or_insert(str(blob_info.key()),
show_hosts=[], aliases={})
boxes = _Boxes(blob_info)
pcapdata.show_hosts = []
for b in boxes.keys():
alias = self.request.get('name-%s' % b)
if alias:
pcapdata.aliases[b] = alias
capdefault.aliases[b] = alias
else:
pcapdata.aliases[b] = b
if self.request.get('show-%s' % b):
pcapdata.show_hosts.append(b)
capdefault.put()
pcapdata.put()
self.response.write('done')
settings = dict(
debug = 1,
)
wsgi_app = webapp2.WSGIApplication([
(r'/', MainHandler),
(r'/upload', UploadHandler),
(r'/view/([^/]+)$', ViewHandler),
(r'/save/([^/]+)$', SaveHandler),
], **settings)