Changeset 9619 for src


Ignore:
Timestamp:
Aug 30, 2011, 2:14:03 PM (13 years ago)
Author:
rick
Message:

Importer method for netstumbler, prepared for merging, al import_droidstumbler, import_kismet, import_netstumber share quite some commom code.

File:
1 copied

Legend:

Unmodified
Added
Removed
  • src/django_gheat/gheat/management/commands/import_netstumbler.py

    r9592 r9619  
    22# -*- coding: utf-8 -*-
    33#
    4 # Script for importing .gpsxml and .netxml files (Kismet output)
     4# Script for importing .ns1 files (Netstumber output)
    55#
    66# Rick van der Zwet <info@rickvanderzwet.nl>
     
    1919from collections import defaultdict
    2020
     21from netstumbler import parse_netstumbler
    2122from import_droidstumbler import bulk_sql,get_organization_id_by_ssid
    2223
     
    3334
    3435
    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 
     36def import_accespoints(ap_pool, counters):
    6837  # 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)
    7040  bssid_list_insert = set(ap_pool.keys()) - set(bssid_list_present)
    7141
     
    7646      ssid, encryption = ap_pool[bssid]
    7747      # 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)))
    7950      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)
    9353  return counters
    9454
    9555
    9656
    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 
     57def import_metingen(meetrondje, meting_pool, counters):
     58  # Temponary holders
    10359  bssid_failed = defaultdict(int)
    104 
    105   # Prepare new accespoints and measurements
    106   points = gpsxml_doc.findall('gps-point')
    107 
    108   # Temponary holders
    109   meting_pool = defaultdict(list)
    110 
    111   for point in points:
    112     counters['meting_total'] += 1
    113     #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 support
    117     # that (yet).
    118     if bssid in ['GP:SD:TR:AC:KL:OG','00:00:00:00:00:00']:
    119       counters['meting_ignored'] =+ 1
    120       continue
    121     # XXX: Signal need properly be a relation of signal_dbm and noice_dbm
    122     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'] += 1
    127       continue
    128     # We store all values found, avg or max will be done later on
    129     key = (bssid, point.attrib['lat'], point.attrib['lon'])
    130     signaal=100 + int(level)
    131     meting_pool[key].append(signaal)
    13260
    13361  bssid_list = [x[0] for x in meting_pool.keys()]
    13462  # Build mapping for meting import
    13563  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'):
    13766    mac2id[mac] = int(id)
    13867
    13968  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):
    14171    clients[mac] = True
    14272
     
    14979      bssid_failed[bssid] += len(signals)
    15080    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)))
    15283      sql_values.append(item)
    15384
     
    15788
    15889  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)
    16092  return counters
    16193
    16294
     95
     96def 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
    163142class Command(BaseCommand):
    164   args = '<gpsxml|netxml>[.gz] [gpsxml2[.gz]  gpsxml3[.gz] ...]'
     143  args = '<netstumber.ns1>[.gz] [netstumber2.ns1[.gz]  netstumber3.ns1[.gz] ...]'
    165144  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"),
    167147    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"),
    173155  )
    174156
    175157  def handle(self, *args, **options):
     158    if options['verbosity'] > 1:
     159      logger.setLevel(logging.DEBUG)
    176160    if len(args) == 0:
    177161      self.print_help(sys.argv[0],sys.argv[1])
     
    179163
    180164    # Please first the netxml and then the gpsxml files
    181     sorted_args = [x for x in args if "netxml" in x] + [x for x in args if "gpsxml" in x]
     165    sorted_args = [x for x in args if "ns1" in x]
    182166    remainder = list(set(args) - set(sorted_args))
    183167    args = sorted_args + remainder
    184168    logger.debug("Parsing files in the following order: %s", args)
    185169
    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:
    197184        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()
    199190        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'])
    206192
    207193        # Meetrondje from filename if needed
    208194        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')
    210196        else:
    211197          meetrondje = options['meetrondje']
    212198
    213199        # 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'])
    215202        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)
    217205        logger.info('Meetrondje: %s @ %s' % (meetrondje, datum))
    218206        if not created:
    219207          logger.error("Meetrondje '%s' already imported" % mr)
    220208          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)
    223216      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.