- Timestamp:
- Aug 30, 2011, 2:14:03 PM (13 years ago)
- File:
-
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
src/django_gheat/gheat/management/commands/import_netstumbler.py
r9592 r9619 2 2 # -*- coding: utf-8 -*- 3 3 # 4 # Script for importing . gpsxml and .netxml files (Kismetoutput)4 # Script for importing .ns1 files (Netstumber output) 5 5 # 6 6 # Rick van der Zwet <info@rickvanderzwet.nl> … … 19 19 from collections import defaultdict 20 20 21 from netstumbler import parse_netstumbler 21 22 from import_droidstumbler import bulk_sql,get_organization_id_by_ssid 22 23 … … 33 34 34 35 35 def import_kismet_netxml(netxml_file): 36 netxml_doc = etree.parse(open_file(netxml_file)) 37 38 counters = { 'ap_added' : 0, 'ap_total' : 0, 'ap_failed' : 0, 'ap_ignored' : 0, 39 'client_added' : 0, 'client_total' : 0, 'client_failed' : 0, 'client_ignored' : 0} 40 41 # Prepare new accespoints and measurements 42 wnetworks = netxml_doc.findall('wireless-network') 43 44 # Temponary holders 45 ap_pool = {} 46 client_pool = {} 47 48 # Create all accesspoints and for caching validation purposes store them 49 # locally as well 50 for wnetwork in wnetworks: 51 bssid = wnetwork.find('BSSID').text 52 ap_type = wnetwork.attrib['type'] 53 # Only access points and clients (for ignore listings) 54 if ap_type in ['infrastructure', 'data']: 55 counters['ap_total'] += 1 56 encryption = (wnetwork.find('SSID/encryption') != None) 57 ssid_node = wnetwork.find('SSID/essid[@cloaked="false"]') 58 ssid = ssid_node.text if ssid_node != None else 'hidden' 59 60 ap_pool[bssid] = (ssid, encryption) 61 elif ap_type in ['probe', 'ad-hoc']: 62 counters['client_total'] += 1 63 client_pool[bssid] = True 64 else: 65 logger.error('Unknown type %s - %s',bssid, wnetwork.attrib['type']) 66 67 36 def import_accespoints(ap_pool, counters): 68 37 # Determine which Accespoints to add 69 bssid_list_present = Accespoint.objects.filter(mac__in=ap_pool.keys()).values_list('mac', flat=True) 38 bssid_list_present = Accespoint.objects.filter(mac__in=ap_pool.keys()).\ 39 values_list('mac', flat=True) 70 40 bssid_list_insert = set(ap_pool.keys()) - set(bssid_list_present) 71 41 … … 76 46 ssid, encryption = ap_pool[bssid] 77 47 # Special trick in SSID ts avoid escaping in later stage 78 item = str((bssid.upper(),ssid.replace('%','%%'),encryption,get_organization_id_by_ssid(ssid))) 48 item = str((bssid.upper(),ssid.replace('%','%%'),encryption, 49 get_organization_id_by_ssid(ssid))) 79 50 sql_values.append(item) 80 counters['ap_added'] = bulk_sql('gheat_accespoint (`mac`, `ssid`, `encryptie`, `organization_id`)',sql_values) 81 82 # Determine which Wireless Clients to add 83 bssid_list_present = WirelessClient.objects.filter(mac__in=client_pool.keys()).values_list('mac', flat=True) 84 bssid_list_insert = set(client_pool.keys()) - set(bssid_list_present) 85 86 # Create a bulk import list and import 87 if bssid_list_insert: 88 sql_values = [] 89 for bssid in bssid_list_insert: 90 sql_values.append("('%s')" % bssid.upper()) 91 counters['client_added'] = bulk_sql('gheat_wirelessclient (`mac`)',sql_values) 92 51 counters['ap_added'] = bulk_sql('gheat_accespoint (`mac`, `ssid`,\ 52 `encryptie`, `organization_id`)',sql_values) 93 53 return counters 94 54 95 55 96 56 97 def import_kismet_gpsxml(gpsxml_file, meetrondje): 98 gpsxml_doc = etree.parse(open_file(gpsxml_file)) 99 100 #Various statistics 101 counters = {'meting_added' : 0, 'meting_total' : 0, 'meting_failed' : 0, 'meting_ignored' :0} 102 57 def import_metingen(meetrondje, meting_pool, counters): 58 # Temponary holders 103 59 bssid_failed = defaultdict(int) 104 105 # Prepare new accespoints and measurements106 points = gpsxml_doc.findall('gps-point')107 108 # Temponary holders109 meting_pool = defaultdict(list)110 111 for point in points:112 counters['meting_total'] += 1113 #XXX: This needs to be either the 'bssid' or the 'source',114 #XXX: accesspoint from or too data.115 bssid = point.attrib['bssid']116 # XXX: Filter this in the beginning with XPath, but etree does not support117 # that (yet).118 if bssid in ['GP:SD:TR:AC:KL:OG','00:00:00:00:00:00']:119 counters['meting_ignored'] =+ 1120 continue121 # XXX: Signal need properly be a relation of signal_dbm and noice_dbm122 try:123 level = point.attrib['signal_dbm']124 except KeyError:125 logger.debug("Point '%s' does not have signal strengh" % point)126 counters['meting_failed'] += 1127 continue128 # We store all values found, avg or max will be done later on129 key = (bssid, point.attrib['lat'], point.attrib['lon'])130 signaal=100 + int(level)131 meting_pool[key].append(signaal)132 60 133 61 bssid_list = [x[0] for x in meting_pool.keys()] 134 62 # Build mapping for meting import 135 63 mac2id = {} 136 for mac,id in Accespoint.objects.filter(mac__in=bssid_list).values_list('mac','id'): 64 for mac,id in Accespoint.objects.filter(mac__in=bssid_list).\ 65 values_list('mac','id'): 137 66 mac2id[mac] = int(id) 138 67 139 68 clients = {} 140 for mac in WirelessClient.objects.filter(mac__in=bssid_list).values_list('mac',flat=True): 69 for mac in WirelessClient.objects.filter(mac__in=bssid_list).\ 70 values_list('mac',flat=True): 141 71 clients[mac] = True 142 72 … … 149 79 bssid_failed[bssid] += len(signals) 150 80 else: 151 item = str((int(meetrondje.id),mac2id[bssid],float(lat),float(lon),max(signals))) 81 item = str((int(meetrondje.id),mac2id[bssid],float(lat),\ 82 float(lon),max(signals))) 152 83 sql_values.append(item) 153 84 … … 157 88 158 89 if sql_values: 159 counters['meting_added'] = bulk_sql('gheat_meting (`meetrondje_id`, `accespoint_id`, `lat`, `lng`, `signaal`)',sql_values) 90 counters['meting_added'] = bulk_sql('gheat_meting (`meetrondje_id`,\ 91 `accespoint_id`, `lat`, `lng`, `signaal`)',sql_values) 160 92 return counters 161 93 162 94 95 96 def process_netstumber(filename): 97 data = parse_netstumbler(open_file(filename)) 98 99 counters = { 100 'ap_added' : 0, 'ap_total' : 0, 101 'ap_failed' : 0, 'ap_ignored' : 0, 102 'client_added' : 0, 'client_total' : 0, 103 'client_failed' : 0, 'client_ignored' : 0, 104 'meting_added' : 0, 'meting_total' : 0, 105 'meting_failed' : 0, 'meting_ignored' : 0 106 } 107 108 # Temponary holders 109 meting_pool = defaultdict(list) 110 ap_pool = {} 111 112 for ap in data['aps']: 113 # XXX: How is encryption coded? 114 encryption = False 115 ap_pool[ap['BSSID']]= (ap['SSID'], encryption) 116 for point in ap["measurements"]: 117 counters['meting_total'] += 1 118 if point['LocationSource'] == 0: 119 logger.debug("No GPS Coordinates found for BSSID %s @ %s", 120 ap['BSSID'], point['Time']) 121 counters['meting_ignored'] += 1 122 continue 123 # We store all values found, avg or max will be done later on 124 key = (ap['BSSID'], point["Latitude"], point["Longitude"]) 125 126 # Known measurement error 127 if point['Signal'] == -32767: continue 128 129 # XXX: Signal need properly be a relation of signal_dbm and noice_dbm 130 signaal= 100 + point['Signal'] 131 if signaal > 100 or signaal < 0: 132 logger.warning("Signal %s is not valid entry for BSSID %s @ %s", 133 point['Signal'], ap['BSSID'], point['Time']) 134 continue 135 meting_pool[key].append(signaal) 136 137 return (counters, ap_pool, meting_pool) 138 139 140 141 163 142 class Command(BaseCommand): 164 args = '< gpsxml|netxml>[.gz] [gpsxml2[.gz] gpsxml3[.gz] ...]'143 args = '<netstumber.ns1>[.gz] [netstumber2.ns1[.gz] netstumber3.ns1[.gz] ...]' 165 144 option_list = BaseCommand.option_list + ( 166 make_option('-k', '--kaart', dest='kaart', default='onbekend', help="Kaart gebruikt"), 145 make_option('-k', '--kaart', dest='kaart', default='onbekend', 146 help="Kaart gebruikt"), 167 147 make_option('-m', '--meetrondje', dest='meetrondje', default=None), 168 make_option('-g', '--gebruiker', dest='gebruiker', default='username',help='Naam van de persoon die de meting uitgevoerd heeft'), 169 make_option('-e', '--email', dest='email', default='foo@bar.org',help='Email van de persoon die de meting uitgevoerd heeft'), 170 make_option('-d', '--datum', dest='datum', default=None, help="Provide date \ 171 in following format: '%Y%m%d-%H-%M-%S-1', by default it will be generated from \ 172 the filename"), 148 make_option('-g', '--gebruiker', dest='gebruiker', default='username', 149 help='Naam van de persoon die de meting uitgevoerd heeft'), 150 make_option('-e', '--email', dest='email', default='foo@bar.org', 151 help='Email van de persoon die de meting uitgevoerd heeft'), 152 make_option('-d', '--datum', dest='datum', default=None, 153 help="Provide date in following format: '%Y%m%d-%H-%M-%S-1', by \ 154 default it will be generated from the filename"), 173 155 ) 174 156 175 157 def handle(self, *args, **options): 158 if options['verbosity'] > 1: 159 logger.setLevel(logging.DEBUG) 176 160 if len(args) == 0: 177 161 self.print_help(sys.argv[0],sys.argv[1]) … … 179 163 180 164 # Please first the netxml and then the gpsxml files 181 sorted_args = [x for x in args if "n etxml" in x] + [x for x in args if "gpsxml" in x]165 sorted_args = [x for x in args if "ns1" in x] 182 166 remainder = list(set(args) - set(sorted_args)) 183 167 args = sorted_args + remainder 184 168 logger.debug("Parsing files in the following order: %s", args) 185 169 186 for xml_file in args: 187 if not os.path.isfile(xml_file): 188 raise CommandError("xml file '%s' does not exists" % xml_file) 189 190 for xml_file in args: 191 logger.info("Processing '%s'" % xml_file) 192 if 'netxml' in xml_file: 193 counters = import_kismet_netxml(xml_file) 194 logger.info("summary accespoints: total:%(ap_total)-6s added:%(ap_added)-6s failed:%(ap_failed)-6s ignored:%(ap_ignored)-6s" % counters) 195 logger.info("summary client : total:%(client_total)-6s added:%(client_added)-6s failed:%(client_failed)-6s ignored:%(client_ignored)-6s" % counters) 196 elif 'gpsxml' in xml_file: 170 for filename in args: 171 if not os.path.isfile(filename): 172 raise CommandError("file '%s' does not exists" % filename) 173 174 def process_date(datestr): 175 try: 176 # Kismet-20110805-15-37-30-1 177 return datetime.datetime.strptime(datestr,'%Y%m%d-%H-%M-%S-1') 178 except ValueError: 179 raise CommandError("Invalid date '%s'" % options['datum']) 180 181 for filename in args: 182 logger.info("Processing '%s'" % filename) 183 if 'ns1' in filename: 197 184 if options['datum'] == None: 198 datum = os.path.basename(xml_file).lstrip('Kismet-').rstrip('.gz').rstrip('.gpsxml').rstrip('.netxml') 185 datestr = os.path.basename(filename).lstrip('Kismet-').\ 186 rstrip('.gz').rstrip('.gpsxml').rstrip('.netxml').rstrip('.ns1') 187 datum = process_date(datestr) 188 elif options['datum'] == 'now': 189 datum = datetime.datetime.now() 199 190 else: 200 datum = options['datum'] 201 try: 202 # Kismet-20110805-15-37-30-1 203 datum = datetime.datetime.strptime(datum,'%Y%m%d-%H-%M-%S-1') 204 except ValueError: 205 raise CommandError("Invalid date '%s'" % options['datum']) 191 datum = process_date(options['datum']) 206 192 207 193 # Meetrondje from filename if needed 208 194 if options['meetrondje'] == None: 209 meetrondje = os.path.basename( xml_file).rstrip('.gz').rstrip('.gpsxml')195 meetrondje = os.path.basename(filename).rstrip('.gz').rstrip('.ns1') 210 196 else: 211 197 meetrondje = options['meetrondje'] 212 198 213 199 # Create meetrondje object 214 g, created = Gebruiker.objects.get_or_create(naam=options['gebruiker'] , email=options['email']) 200 g, created = Gebruiker.objects.get_or_create(naam=options['gebruiker'], 201 email=options['email']) 215 202 a, created = Apparatuur.objects.get_or_create(kaart=options['kaart']) 216 mr, created = MeetRondje.objects.get_or_create(datum=datum , naam=meetrondje , gebruiker=g , apparatuur=a) 203 mr, created = MeetRondje.objects.get_or_create(datum=datum, 204 naam=meetrondje, gebruiker=g, apparatuur=a) 217 205 logger.info('Meetrondje: %s @ %s' % (meetrondje, datum)) 218 206 if not created: 219 207 logger.error("Meetrondje '%s' already imported" % mr) 220 208 continue 221 counters = import_kismet_gpsxml(xml_file, mr) 222 logger.info("summary metingen : total:%(meting_total)-6s added:%(meting_added)-6s failed:%(meting_failed)-6s ignored:%(meting_ignored)-6s" % counters) 209 (counters, ap_pool, meting_pool) = process_netstumber(filename) 210 counters = import_accespoints(ap_pool, counters) 211 counters = import_metingen(mr, meting_pool, counters) 212 213 logger.info(("summary metingen : total:%(meting_total)-6s" + 214 "added:%(meting_added)-6s failed:%(meting_failed)-6s" + 215 "ignored:%(meting_ignored)-6s") % counters) 223 216 else: 224 raise CommandError(" xml file '%s' format not recognized" % xml_file)217 raise CommandError("file '%s' format not recognized" % filename)
Note:
See TracChangeset
for help on using the changeset viewer.