Kismet Wireless

Kismet Forums

 

Posted by:jymibeer
Subject:python sax parser to convert kismet logs to google earth kml
Date:22:06:50 11/01/2007

I'll host a file for you
I've been working on converting my data with the various scripts that i have found and yours will make a nice addition with your permission.
you can join my site http://www.conbeer.org (i don't spam it's a joomla! website that i havn't updated for a while) and get my contact info there.
I have alot(~5000) of ap's logged and am always looking for another way to show my wardrives.
i'm also in the middle of some php for google maps and displaying some of the data from my kismet & gpsdrive logs.

> Hi all,
>
> Here is a script I wrote to convert kismet logs to google earth. I realise there is a php one here:
>
> http://www.niquille.com/kismet-earth/
>
> But I wrote my own because:
>
> - I got php out of memory errors for large gps files
> - The signal strength data wasn't mapped onto google earth
> - The APs were not placed at points of max signal strength, and so didn't really make sense.
>
> I have addressed all these issues. I have included the text below, but as this is python the indenting is important so I have emailled dragorn@kismetwireless.net with the file. Hopefully kismetwireless will host it for everyone. Certainly many improvement can still be made to the script.
>
> greg
>
>
> #!/bin/python
>
> #greg912noharvesting@gmail.com
> #please remove "noharvesting" to send me email.
>
> import sys
> import random
> import urllib
> from xml.sax import make_parser, handler
>
>
> class KismetFileHandler(handler.ContentHandler):
> """This class parses kismet .gps and .xml files.
> The idea is to produce a folder for each ssid with a signal strength map, metadata about the AP, and a best guess location (currently placed at location of strongest power).
>
> """
>
> def __init__(self):
>
> self.signal_strength={}
> self.color={}
> self.max_signal_strength={}
> self.max_signal_strength_coords={}
> self.net={}
> self.path=""
> self.output=""
> self.tag="none"
> self.interested=False
>
> def startElement(self, name, attrs):
>
> if name=="gps-run":
> #This is the first thing in our gps file.
> self.output="""<?xml version='1.0' encoding='UTF-8'?>
> <kml xmlns='http://earth.google.com/kml/2.0'>
> <Folder>
> <name>"""+sys.argv[1]+"""</name>
> <description>"""+attrs["start-time"]+"""</description>
> <visibility>1</visibility>
> <open>1</open>"""
>
> elif name=="wireless-network":
> if attrs["type"]=="infrastructure":
> #We only care about infrastructure networks.
> self.interested=True
> self.net["cloaked"]=attrs["cloaked"]
> self.net["first-seen"]=attrs["first-time"]
> self.net["last-seen"]=attrs["last-time"]
>
> elif name=="SSID" and self.interested:
> self.tag="ssid"
> elif name=="BSSID" and self.interested:
> self.tag="bssid"
> elif name=="channel" and self.interested:
> self.tag=name
> elif name=="maxrate" and self.interested:
> self.tag=name
> elif name=="maxseenrate" and self.interested:
> self.tag=name
> elif name=="carrier" and self.interested:
> self.tag=name
> elif name=="encryption" and self.interested:
> self.tag=name
> elif name=="LLC" and self.interested:
> self.tag="llc"
> elif name=="data" and self.interested:
> self.tag=name
> elif name=="crypt" and self.interested:
> self.tag=name
> elif name=="weak" and self.interested:
> self.tag=name
> elif name=="dupeiv" and self.interested:
> self.tag=name
> elif name=="total" and self.interested:
> self.tag=name
> elif name=="datasize" and self.interested:
> self.tag=name
> elif name=="min-lat" and self.interested:
> self.tag=name
> elif name=="min-lon" and self.interested:
> self.tag=name
> elif name=="min-alt" and self.interested:
> self.tag=name
> elif name=="min-spd" and self.interested:
> self.tag=name
> elif name=="max-lat" and self.interested:
> self.tag=name
> elif name=="max-lon" and self.interested:
> self.tag=name
> elif name=="max-alt" and self.interested:
> self.tag=name
> elif name=="max-spd" and self.interested:
> self.tag=name
>
> elif name=="gps-point":
>
> #Storlat/long/altwarpath track
> self.path = self.path + attrs["lon"] + "," + attrs["lat"] + ",0 "
> if attrs["bssid"] != "GP:SD:TR:AC:KL:OG":
> try:
> #Create a point for each gps measurement. Build an array
> #of measurements per bssid.
> self.signal_strength[attrs["bssid"]]+="""
> <Placemark>
> <visibility>0</visibility>
> <open>0</open>
> <Style>
> <LineStyle>
> <color>""" + self.color[attrs["bssid"]] + """</color>
> <width>4</width>
> </LineStyle>
> </Style>
> <LineString>
> <extrude>1</extrude>
> <tessellate>1</tessellate>
> <altitudeMode>relativeToGround</altitudeMode>
> <coordinates>""" + attrs["lon"]+","+attrs["lat"]+","+attrs["signal"]+"""
> </coordinates>
> </LineString>
> </Placemark>"""
>
> try:
> if int(attrs["signal"]) > int(self.max_signal_strength[attrs["bssid"]]):
> self.max_signal_strength[attrs["bssid"]]=attrs["signal"]
> self.max_signal_strength_coords[attrs["bssid"]]=[attrs["lon"],attrs["lat"]]
> except KeyError:
> self.max_signal_strength[attrs["bssid"]]=attrs["signal"]
> self.max_signal_strength_coords[attrs["bssid"]]=[attrs["lon"],attrs["lat"]]
>
> except KeyError:
> #This is a new BSSID, assign it a color and add in the first point
> self.color[attrs["bssid"]]=hex(random.randrange(0xFF000000,0xFFFFFFFF))[2:-1]
> self.signal_strength[attrs["bssid"]]="""
> <Placemark>
> <visibility>0</visibility>
> <open>0</open>
> <Style>
> <LineStyle>
> <color>""" + self.color[attrs["bssid"]] + """</color>
> <width>4</width>
> </LineStyle>
> </Style>
> <LineString>
> <extrude>1</extrude>
> <tessellate>1</tessellate>
> <altitudeMode>relativeToGround</altitudeMode>
> <coordinates>""" + attrs["lon"]+","+attrs["lat"]+","+attrs["signal"]+"""
> </coordinates>
> </LineString>
> </Placemark>"""
>
> else:
> self.tag="none"
>
> def endElement(self, name):
>
> if name=="gps-run":
> temp=self.path.split(" ",1)[0]
> startlat=temp.split(",")[1]
> startlong=temp.split(",")[0]
>
> #Write out the warpath route
> self.output+="""
>
> <Placemark>
> <description>Warpath Route Taken</description>
> <name>Route</name>
> <LookAt>
> <longitude>"""+startlong+"""</longitude>
> <latitude>"""+startlat+"""</latitude>
> <range>1000</range>
> <tilt>54</tilt>
> <heading>-35</heading>
> </LookAt>
> <visibility>1</visibility>
> <open>0</open>
> <Style>
> <LineStyle>
> <color>BB0000FF</color>
> <width>4</width>
> </LineStyle>
> </Style>
> <LineString>
> <extrude>0</extrude>
> <tessellate>1</tessellate>
> <altitudeMode>clampedToGround</altitudeMode>
> <coordinates>""" + self.path + """
> </coordinates>
> </LineString>
> </Placemark>"""
>
> if name=="wireless-network" and self.interested:
>
> try:
> #People have ssid's with lots of funky chars that google earth doesn't like.
> ssid=urllib.quote(self.net["ssid"])
> except KeyError:
> #Must have been no ssid
> ssid="no-ssid"
>
> try:
> sig_str=self.signal_strength[self.net["bssid"]]
> max_sig_lon=self.max_signal_strength_coords[self.net["bssid"]][0]
> max_sig_lat=self.max_signal_strength_coords[self.net["bssid"]][1]
> lookat="""
> <LookAt>
> <longitude>%s</longitude>
> <latitude>%s</latitude>
> <range>100</range>
> <tilt>54</tilt>
> <heading>-35</heading>
> </LookAt>
> """ % (max_sig_lon,max_sig_lat)
>
> except KeyError:
> #We don't have gps data for this MAC for whatever reason
> sig_str="<description>No GPS Data Available!!</description>"
> lookat=""
> max_sig_lon=0
> max_sig_lat=0
>
>
> try:
> if (self.net["encryption"].index("WPA")>=0) or self.net["encryption"].contains("TKIP"):
> encryption="<font color=\"green\">%s</font>" % self.net["encryption"]
> icon="node_closed.png"
> except ValueError:
> if self.net["encryption"]=="WEP":
> encryption="<font color=\"blue\">%s</font>" % self.net["encryption"]
> icon="node_open.png"
> elif self.net["encryption"]=="None":
> encryption="<font color=\"red\">%s</font>" % self.net["encryption"]
> icon="node_open.png"
>
>
> self.output+="""
> <Folder>
> <name>%s</name>
> %s
> <description><![CDATA[First-seen:%s<br>
> Last-seen:%s<br><hr>
> BSSID:%s<br>
> channel:%s<br>
> encryption:%s<br>
> cloaked:%s<br>
> max rate:%s<br><hr>
> GPS Coordinates<br>
> Min lat/long/alt:%s lat, %s lon, %s alt<br>
> Max lat/long/alt:%s lat, %s lon, %s alt<br><hr>
> Captured Packets<br>
> llc:%s<br>
> data:%s<br>
> crypt:%s<br>
> weak:%s<br>
> dupeiv:%s<br>
> total:%s<br>
> total datasize captured:%s<br>
> ]]></description>
> <Placemark>
> <name>%s</name>
> <description>Location of max AP signal strength</description>
> <visibility>0</visibility>
> <open>0</open>
> %s
> <Style>
> <icon>%s</icon>
> </Style>
> <Point>
> <altitudeMode>clampedToGround</altitudeMode>
> <extrude>0</extrude>
> <tessellate>0</tessellate>
> <coordinates>%s,%s,0</coordinates>
> </Point>
> </Placemark>
> <Folder>
> <name>Signal Strength Map</name>
> %s
> %s
> </Folder></Folder>""" % (ssid,lookat,self.net["first-seen"],self.net["last-seen"],self.net["bssid"],self.net["channel"],encryption,self.net["cloaked"],self.net["maxrate"],self.net["min-lat"],self.net["min-lon"],self.net["min-alt"],self.net["max-lat"],self.net["max-lon"],self.net["max-alt"],self.net["llc"],self.net["data"],self.net["crypt"],self.net["weak"],self.net["dupeiv"],self.net["total"],self.net["datasize"],ssid,lookat,icon,max_sig_lon,max_sig_lat,lookat,sig_str)
>
> self.tag="none"
> self.net={}
> self.interested=False
>
>
> def characters(self,chars):
>
> #The characters output is a bit messy - throw away whitespace only stuff
> if self.interested and self.tag !="none" and len(chars.strip())!=0:
> try:
> if self.net[self.tag]:
> #We already have a value for this key so append
> self.net[self.tag]+=" "+str(chars)
> except KeyError:
> self.net[self.tag]=str(chars)
> except:
> print "Couldn't process string: %s" % chars
>
> def endDocument(self):
>
>
> handle = open(sys.argv[1]+".kml","w+")
> handle.write(self.output)
> handle.write("</Folder>\n</kml>")
>
>
> kismetparser = make_parser()
> kismetparser.setContentHandler(KismetFileHandler())
> kismetparser.parse(sys.argv[1]+".gps")
> kismetparser.parse(sys.argv[1]+".xml")


Reply to this message