Advertisement
CreadPag

netxml2kml

Mar 8th, 2017
188
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 11.48 KB | None | 0 0
  1. #!/usr/bin/env python
  2. # coding=utf-8
  3. #
  4. # Converts netxml files from Kismet Newcore into KML or KMZ files for Google Earth
  5. #
  6. # Author: Patrick Salecker
  7. # URL: http://www.salecker.org/software/netxml2kml/en
  8. # Last modified: 13.06.2011
  9.  
  10. import os
  11. import time
  12. import zipfile
  13.  
  14. import xml.parsers.expat
  15. import optparse
  16.  
  17. class WirelessNetwork:
  18.     def __init__(self,type,firsttime,lasttime):
  19.         self.type=type
  20.         self.firsttime=firsttime
  21.         self.lasttime=lasttime
  22.         self.bssid=""
  23.         self.manuf=""
  24.         self.ssid=[]
  25.         self.freqmhz={}
  26.         self.maxrate=0
  27.         self.maxseenrate=0
  28.         self.packets={}
  29.         self.snr={} # Signal-to-noise ratio
  30.         self.datasize=0
  31.         self.channel=0
  32.         self.carrier=""
  33.         self.bsstimestamp=0
  34.         self.gps={}
  35.         self.ipaddress={}
  36.    
  37.     def get_from_ssid(self,key):
  38.         result=[]
  39.         for ssid in self.ssid:
  40.             if key in ssid and ssid[key]!="":
  41.                 if type(ssid[key])!=type({}):
  42.                     return ssid[key]
  43.                 else:
  44.                     for bla in ssid[key]:
  45.                         if bla not in result:
  46.                             result+=[bla,]
  47.         if len(result)>0:
  48.             return result
  49.         else:
  50.             return ""
  51.        
  52.     def update(self,new):
  53.         """Update a network
  54.         Compare a existing network with a new and update the existing
  55.         """
  56.         if len(self.gps)==0 and len(new.gps)>0:
  57.             self.gps=new.gps
  58.         return True
  59.            
  60. KML_PLACEMARK="""
  61. <Placemark><styleUrl>#%s</styleUrl>%s
  62. <Point><coordinates>%s,%s</coordinates></Point>
  63. <description><![CDATA[
  64. SSID: %s<br />
  65. MAC: %s<br />
  66. Manuf: %s<br />
  67. Type: %s<br />
  68. Channel: %s<br />
  69. Encryption: <FONT color=%s>%s</FONT><br />
  70. Last time: %s<br />
  71. GPS: %s,%s]]></description></Placemark>
  72. """
  73.  
  74. KML_FOLDER = """
  75. <Folder>
  76. <name>%s: %s APs</name>
  77. <Style id="%s"><IconStyle><scale>0.5</scale>
  78. <Icon>")
  79. <href>http://files.salecker.org/netxml2kml/images/%s.gif</href>
  80. </Icon></IconStyle></Style>
  81. %s
  82. </Folder>
  83. """
  84.  
  85. class netxml:
  86.     def __init__(self):
  87.         self.networks={}
  88.         self.outputname=""
  89.         self.target=None
  90.         self.disable_names = False
  91.  
  92.     def main(self):
  93.         usage=self.main_usage()
  94.         parser = optparse.OptionParser(usage)
  95.         parser.add_option("-o", dest="outputname",
  96.             help="Filename without extension")
  97.         parser.add_option("--kml", dest="kml", action="store_true",
  98.             help="Create a KML file for Google Earth <outputname>.kml")
  99.         parser.add_option("--kmz", dest="kmz", action="store_true",
  100.             help="Create a KMZ file for Google Earth <outputname>.kmz")
  101.         parser.add_option("--disable-names", dest="names", action="store_true",
  102.             help="Disable names in KML/KMZ")
  103.        
  104.         (options, args) = parser.parse_args()
  105.                
  106.         # Input
  107.         if len(args)>0:
  108.             for filename in args:
  109.                 if os.path.isdir(filename):
  110.                     self.parse_dir(filename)
  111.                 elif os.path.isfile(filename):
  112.                     self.parse(filename)
  113.                 else:
  114.                     print "Invalid name: %s"%filename
  115.         if options.outputname==None:
  116.             print "Output name not defined, try '-h'"
  117.         else:
  118.             self.outputname=options.outputname
  119.             print "Outputfile: %s.*" % self.outputname
  120.            
  121.         print ""
  122.         if options.names is True:
  123.             self.disable_names = True
  124.        
  125.         # Output
  126.         if len(self.networks)>0:
  127.             if self.outputname!="":
  128.                 if options.kml is True:
  129.                     self.output_kml()
  130.                 if options.kmz is True:
  131.                     self.output_kml(kmz=True)
  132.         else:
  133.             print "No networks"
  134.            
  135.     def main_usage(self):
  136.         return """
  137. python netxml [options] [file1] [file2] [dir1] [dir2] [...]
  138. ./netxml [options] [dir1] [dir2] [file1] [file2] [...]
  139.  
  140. Example:
  141. python netxml.py --kmz --kml -o today somefile.netxml /mydir"""
  142.    
  143.     def parse_dir(self,parsedir):
  144.         """Parse all files in a directory
  145.         """
  146.         print "Parse .netxml files in Directory:",parsedir
  147.         starttime=time.time()
  148.         files=0
  149.         if not parsedir.endswith(os.sep):
  150.             parsedir+=os.sep
  151.         for filename in os.listdir(parsedir):
  152.             if os.path.splitext(filename)[1]==".netxml":
  153.                 self.parse(parsedir + filename)
  154.                 files+=1
  155.                
  156.         print "Directory done, %s sec, %s files" % (
  157.             round(time.time()-starttime,2),files)
  158.    
  159.     def parse(self,filename):
  160.         """Parse a netxml file generated by Kismet Newcore
  161.         """
  162.        
  163.         self.parser={
  164.             "update":0,
  165.             "new":0,
  166.             "laststart":"",
  167.             "parents":[],
  168.             "wn":None,
  169.             "ssid":None
  170.             }
  171.        
  172.         p = xml.parsers.expat.ParserCreate()
  173.         p.buffer_text=True #avoid chunked data
  174.         p.returns_unicode=False #disabled Unicode support is much faster
  175.         p.StartElementHandler = self.parse_start_element
  176.         p.EndElementHandler = self.parse_end_element
  177.         p.CharacterDataHandler = self.parse_char_data
  178.         if os.path.isfile(filename):
  179.             p.ParseFile(open(filename))
  180.         else:
  181.             print "Parser: filename is not a file:" % filename
  182.  
  183.         print "Parser: %s, %s new, %s old" % (
  184.             filename,self.parser["new"],self.parser["update"])
  185.    
  186.     def parse_start_element(self,name, attrs):
  187.         """<name attr="">
  188.         """
  189.         #print 'Start element:', name, attrs
  190.         if name=="wireless-network":
  191.             self.parser["wn"]=WirelessNetwork(
  192.                 attrs["type"],
  193.                 attrs["first-time"],
  194.                 attrs["last-time"])
  195.         elif name=="essid" and 'cloaked' in attrs:
  196.             self.parser["ssid"]['cloaked']=attrs['cloaked']
  197.         elif name=="SSID":
  198.             self.parser["ssid"]={"encryption":{}}
  199.            
  200.         self.parser["parents"].insert(0,self.parser["laststart"])
  201.         self.parser["laststart"]=name
  202.            
  203.     def parse_end_element(self,name):
  204.         """</name>
  205.         """
  206.         #print 'End element:', name
  207.         if name=="wireless-network":
  208.             if self.parser["wn"].bssid in self.networks:
  209.                 self.networks[self.parser["wn"].bssid].update(self.parser["wn"])
  210.                 self.parser["update"]+=1
  211.             else:
  212.                 self.networks[self.parser["wn"].bssid]=self.parser["wn"]
  213.                 self.parser["new"]+=1
  214.         elif name=="SSID":
  215.             if len(self.parser["ssid"])>0 and "type" in self.parser["ssid"]:
  216.                 if self.parser["parents"][0]=="wireless-network":
  217.                     self.parser["wn"].ssid.append(self.parser["ssid"])
  218.             del self.parser["ssid"]
  219.            
  220.         self.parser["laststart"]=self.parser["parents"].pop(0)
  221.            
  222.     def parse_char_data(self,data):
  223.         """<self.parser["laststart"]>data</self.parser["laststart"]>
  224.         """
  225.         if data.strip()=="":
  226.             return
  227.        
  228.         if self.parser["parents"][0]=="SSID":
  229.             if self.parser["laststart"]=="encryption":
  230.                 self.parser["ssid"]["encryption"][data]=True
  231.             elif self.parser["laststart"] in("type","ssid","essid","max-rate","packets","beaconrate","info"):
  232.                 self.parser["ssid"][self.parser["laststart"]]=data
  233.         elif self.parser["parents"][1]=="wireless-network":
  234.             if self.parser["parents"][0]=="gps-info":
  235.                 self.parser["wn"].gps[self.parser["laststart"]]=float(data)
  236.             """elif self.parser["parents"][0]=="packets":
  237.                 self.parser["wn"].packets[self.parser["laststart"]]=data
  238.             elif self.parser["parents"][0]=="snr-info":
  239.                 self.parser["wn"].snr[self.parser["laststart"]]=data
  240.             elif self.parser["parents"][0]=="ip-address":
  241.                 self.parser["wn"].ipaddress[self.parser["laststart"]]=data"""
  242.         elif self.parser["parents"][0]=="wireless-network":
  243.             if self.parser["laststart"]=="BSSID":
  244.                 self.parser["wn"].bssid=data
  245.             elif self.parser["laststart"]=="channel":
  246.                 self.parser["wn"].channel=int(data)
  247.             elif self.parser["laststart"]=="manuf":
  248.                 self.parser["wn"].manuf=data
  249.             """elif self.parser["laststart"]=="freqmhz":
  250.                 self.parser["wn"].freqmhz[data]=True
  251.             elif self.parser["laststart"]=="carrier":
  252.                 self.parser["wn"].carrier=data
  253.             elif self.parser["laststart"]=="maxseenrate":
  254.                 self.parser["wn"].maxseenrate=data
  255.             elif self.parser["laststart"]=="bsstimestamp":
  256.                 self.parser["wn"].bsstimestamp=data
  257.             elif self.parser["laststart"]=="datasize":
  258.                 self.parser["wn"].datasize=data"""
  259.            
  260.        
  261.     def output_kml(self,kmz=False):
  262.         """Output KML for Google Earth
  263.         """
  264.         print "%s export..." % ("KML" if not kmz else "KMZ")
  265.         #starttime=time.time()
  266.        
  267.         if kmz is True:
  268.             target=CreateKMZ(self.outputname)
  269.         else:
  270.             target=CreateKML(self.outputname)
  271.        
  272.         target.add("<?xml version='1.0' encoding='UTF-8'?>\r\n")
  273.         target.add("<kml xmlns='http://earth.google.com/kml/2.1'>\r\n")
  274.         target.add("<Document>\r\n")
  275.         target.add("<name>netxml2kml</name>\r\n")
  276.         target.add("<open>1</open>")
  277.        
  278.         count={"WPA":0,"WEP":0,"None":0,"Other":0}
  279.         folders, route = self.output_kml_fill_folders(count)
  280.  
  281.         for crypt in ("WPA","WEP","None","Other"):
  282.             if crypt=="WPA":
  283.                 pic="WPA"
  284.             elif crypt=="WEP":
  285.                 pic="WEP"
  286.             else:
  287.                 pic="Open"
  288.            
  289.             target.add(KML_FOLDER %(
  290.                 crypt,
  291.                 count[crypt],
  292.                 crypt,
  293.                 pic,
  294.                 "".join(folders[crypt])
  295.             ))
  296.  
  297.             print "%s\t%s" % (crypt,count[crypt])
  298.        
  299.         target.add(self.output_kml_route(route))
  300.         target.add("\r\n</Document>\r\n</kml>")
  301.         target.close()
  302.        
  303.         print "Done. %s networks" % sum(count.values())
  304.         #round(time.time()-starttime,2)
  305.        
  306.     def output_kml_fill_folders(self,count):
  307.         folders={"WPA":[],"WEP":[],"None":[],"Other":[]}
  308.         colors={"WPA":"red","WEP":"orange","None":"green","Other":"grey"}
  309.         route = {}
  310.         for net in self.networks:
  311.             wn=self.networks[net]
  312.             if len(wn.gps)==0:
  313.                 continue
  314.            
  315.             essid = wn.get_from_ssid('essid').replace("<","&lt;").replace(">","&gt;").replace("&","&amp;")
  316.             if not self.disable_names:
  317.                 name = "<name>%s</name>" % essid
  318.             else:
  319.                 name = ""
  320.             encryption=wn.get_from_ssid('encryption')
  321.             crypt=self.categorize_encryption(encryption)
  322.             if len(encryption)!=0:
  323.                 encryption.sort(reverse=True)
  324.                 encryption=" ".join(encryption)
  325.            
  326.             folders[crypt].append(KML_PLACEMARK %(
  327.                 crypt,name,wn.gps['avg-lon'],wn.gps['avg-lat'],
  328.                 essid,wn.bssid,wn.manuf,wn.type,
  329.                 wn.channel,colors[crypt],encryption,wn.lasttime,
  330.                 wn.gps['avg-lat'],wn.gps['avg-lon'],
  331.             ))
  332.             count[crypt]+=1
  333.             sec_first = int(time.mktime(time.strptime(wn.firsttime)))
  334.             sec_last = int(time.mktime(time.strptime(wn.lasttime)))
  335.             if sec_last - sec_first < 300:
  336.                 route[sec_last] = (wn.gps['avg-lat'],wn.gps['avg-lon'])
  337.            
  338.         return folders, route
  339.        
  340.     def output_kml_route(self, route):
  341.         output = []
  342.         num = 1
  343.         last_second = 0
  344.         output.append("<Folder><name>Routes</name>")
  345.         for second in sorted(route):
  346.             lat, lon = route[second]
  347.             if second - last_second > 1800:
  348.                 if len(output) > 1:
  349.                     output.append("</coordinates></LineString><name>Route %s (end %s)</name></Placemark>\n" % (num, time.strftime("%a %b %d %H:%M:%S %Y", time.gmtime(last_second))))
  350.                     num += 1
  351.                 output.append("<Placemark><Style><LineStyle><color>7f00ff00</color><width>3</width></LineStyle></Style><LineString><coordinates>\n")
  352.                
  353.             last_second = second
  354.             output.append("%s,%s \n" % (lon, lat))
  355.        
  356.         output.append("</coordinates></LineString><name>Route %s (end %s)</name></Placemark>\n" % (num, time.strftime("%a %b %d %H:%M:%S %Y", time.gmtime(last_second))))
  357.         output.append("</Folder>")
  358.         return "".join(output)
  359.        
  360.     def categorize_encryption(self,encryption):
  361.         for c in encryption:
  362.             if c.startswith("WPA"):
  363.                 return "WPA"
  364.                
  365.         if "WEP" in encryption:
  366.             return "WEP"
  367.         elif "None" in encryption:
  368.             return "None"
  369.         else:
  370.             return "Other"
  371.    
  372. class CreateKML:
  373.     """Write the KML data direct into a file
  374.     """
  375.     def __init__(self,outputname):
  376.         self.file=open("%s.kml" % outputname, 'w')
  377.        
  378.     def add(self,data):
  379.         self.file.write(data)
  380.        
  381.     def close(self):
  382.         self.file.close()
  383.        
  384. class CreateKMZ:
  385.     """Store the KML data in a list and write it into a zipfile in close()
  386.     """
  387.     def __init__(self,outputname):
  388.         self.data=[]
  389.         self.zip=zipfile.ZipFile("%s.kmz" % outputname, "w")
  390.        
  391.     def add(self,data):
  392.         self.data.append(data)
  393.        
  394.     def close(self):
  395.         zinfo = zipfile.ZipInfo("netxml2kml.kml")
  396.         zinfo.compress_type = zipfile.ZIP_DEFLATED
  397.         self.zip.writestr(zinfo,"".join(self.data))
  398.         self.zip.close()
  399.        
  400. if __name__ == "__main__":
  401.     converter=netxml()
  402.     converter.main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement