1 | #!/usr/bin/env python
|
---|
2 | #
|
---|
3 | # Script for importing .gpsxml and .netxml files (Kismet output)
|
---|
4 | #
|
---|
5 |
|
---|
6 | from django.core.management.base import BaseCommand,CommandError
|
---|
7 | from django.db.utils import IntegrityError
|
---|
8 | from optparse import OptionParser, make_option
|
---|
9 | from gheat.models import *
|
---|
10 | from lxml import etree
|
---|
11 | import datetime
|
---|
12 | import gzip
|
---|
13 | import os
|
---|
14 | import sys
|
---|
15 | import logging
|
---|
16 |
|
---|
17 | def import_file(gpsxml_file, netxml_file, meetrondje, kaart, gebruiker, email):
|
---|
18 | # TODO: Source source is variable entitity, based on mesurement
|
---|
19 | kaart = 'deadcode'
|
---|
20 | gebruiker, created = Gebruiker.objects.get_or_create(naam=gebruiker , email=email)
|
---|
21 | apparatuur, created = Apparatuur.objects.get_or_create(kaart=kaart)
|
---|
22 | # TODO: Date is set to import date, but should pick the date from the netxml file
|
---|
23 | mr = MeetRondje.objects.create(datum=None,
|
---|
24 | naam=meetrondje , gebruiker=gebruiker , apparatuur=apparatuur)
|
---|
25 | if not created:
|
---|
26 | logging.error("Meetrondje '%s' already imported" % mr)
|
---|
27 | sys.exit(1)
|
---|
28 |
|
---|
29 | open_file = lambda file: gzip.open(file,'rb') if file.endswith('.gz') else open(file,'rb')
|
---|
30 | gpsxml_doc = etree.parse(open_file(gpsxml_file))
|
---|
31 | netxml_doc = etree.parse(open_file(netxml_file))
|
---|
32 |
|
---|
33 | points = gpsxml_doc.findall('gps-point')
|
---|
34 | wnetworks = netxml_doc.findall('wireless-network')
|
---|
35 |
|
---|
36 | # Create all accesspoints and for caching validation purposes store them
|
---|
37 | # locally as well
|
---|
38 | ap_cache = {}
|
---|
39 | ap_ignore = []
|
---|
40 | print "#INFO: Going to import %s accesspoints" % len(wnetworks)
|
---|
41 | for wnetwork in wnetworks:
|
---|
42 | bssid = wnetwork.find('BSSID').text
|
---|
43 | # Only store access points
|
---|
44 | if wnetwork.attrib['type'] != "infrastructure":
|
---|
45 | ap_ignore.append(bssid)
|
---|
46 | continue
|
---|
47 |
|
---|
48 | enc = (wnetwork.find('SSID/encryption') != None)
|
---|
49 | ssid_node = wnetwork.find('SSID/essid[@cloaked="false"]')
|
---|
50 | ssid = ssid_node.text if ssid_node != None else 'hidden'
|
---|
51 |
|
---|
52 | ap, created = Accespoint.objects.get_or_create(mac=bssid, ssid=ssid, encryptie=enc)
|
---|
53 | ap_cache[bssid] = ap
|
---|
54 |
|
---|
55 | count = 0
|
---|
56 | #XXX: This is not effient at all, try to wrap it into a a bulk insert would
|
---|
57 | # be much more effient as for example: http://djangosnippets.org/snippets/2362/
|
---|
58 | print "#INFO: Going to import %s points" % len(points)
|
---|
59 | for point in points:
|
---|
60 | #XXX: This needs to be either the 'bssid' or the 'source', accesspoint from or too data.
|
---|
61 | bssid = point.attrib['bssid']
|
---|
62 | # XXX: Filter this in the beginning with XPath, but etree does not support that (yet).
|
---|
63 | if bssid in ['GP:SD:TR:AC:KL:OG','00:00:00:00:00:00']:
|
---|
64 | continue
|
---|
65 | elif bssid in ap_ignore:
|
---|
66 | continue
|
---|
67 | elif not ap_cache.has_key(bssid):
|
---|
68 | try:
|
---|
69 | ap = Accespoint.objects.get(mac=bssid)
|
---|
70 | ap_cache[bssid] = ap
|
---|
71 | except Accespoint.DoesNotExist:
|
---|
72 | print "#ERROR: Cannot found SSID for BSSID '%s'" % bssid
|
---|
73 | continue
|
---|
74 |
|
---|
75 | # XXX: Signal need properly be a relation of signal_dbm and noice_dbm
|
---|
76 | try:
|
---|
77 | signaal = 100 + int(point.attrib['signal_dbm'])
|
---|
78 | except KeyError:
|
---|
79 | print "#ERROR: Point '%s' does not have signal strengh" % point
|
---|
80 |
|
---|
81 | # TODO: This also saves semi-duplicates; multiple entries with the same values, except
|
---|
82 | # the signal strength is different. Should get an AVG or something.
|
---|
83 | try:
|
---|
84 | meting= Meting.objects.create(meetrondje=mr, accespoint=ap_cache[bssid],
|
---|
85 | latitude=point.attrib['lat'], longitude=point.attrib['lon'],
|
---|
86 | signaal=signaal)
|
---|
87 | except IntegrityError, e:
|
---|
88 | continue
|
---|
89 | # Give some feedback to the user
|
---|
90 | count += 1
|
---|
91 | if (count % 1000) == 0:
|
---|
92 | sys.stdout.write(str(count))
|
---|
93 | elif (count % 100) == 0:
|
---|
94 | sys.stdout.write(".")
|
---|
95 | sys.stdout.flush()
|
---|
96 |
|
---|
97 | sys.stdout.write("%s\n" % count)
|
---|
98 | print "#INFO: All done, goodbye"
|
---|
99 |
|
---|
100 |
|
---|
101 | class Command(BaseCommand):
|
---|
102 | args = '<gpsxml>[.gz] [<netxml>[.gz]]'
|
---|
103 | option_list = BaseCommand.option_list + (
|
---|
104 | make_option('-m', '--meetrondje', dest='meetrondje', default='rondje',help='Naam van het meetrondje'),
|
---|
105 | make_option('-k', '--kaart', dest='kaart', default='onbekend', help="Kaart gebruikt"),
|
---|
106 | make_option('-g', '--gebruiker', dest='gebruiker', default='username',help='Naam van de persoon die de meting uitgevoerd heeft'),
|
---|
107 | make_option('-e', '--email', dest='email', default='foo@bar.org',help='Email van de persoon die de meting uitgevoerd heeft'),
|
---|
108 | )
|
---|
109 |
|
---|
110 | def handle(self, *args, **options):
|
---|
111 | try:
|
---|
112 | if len(args) == 2:
|
---|
113 | (gpsxml_file, netxml_file) = args
|
---|
114 | elif len(args) == 1:
|
---|
115 | (gpsxml_file,) = args
|
---|
116 | netxml_file = gpsxml_file.replace('.gpsxml','.netxml')
|
---|
117 | else:
|
---|
118 | raise ValueError
|
---|
119 | except ValueError:
|
---|
120 | self.print_help(sys.argv[0],sys.argv[1])
|
---|
121 | raise CommandError("Not all arguments are provided")
|
---|
122 | if not os.path.isfile(gpsxml_file):
|
---|
123 | raise CommandError("gpsxml file '%s' does not exists" % gpsxml_file)
|
---|
124 | if not os.path.isfile(netxml_file):
|
---|
125 | raise CommandError("netxml file '%s' does not exists" % netxml_file)
|
---|
126 |
|
---|
127 | import_file(gpsxml_file, netxml_file ,options['meetrondje'], options['kaart'],options['gebruiker'],options['email'])
|
---|