My Expectations
I'm working my way through Violent Python and am currently on a module where I'm grabbing ip-addresses from a .pcap-file, parsing the ip-addresses to longitudes and latitudes and finally parsing those longs and langs into a .kml file.
The idea is that my .kml file should be uploadable to Google Earth and Google Maps to show pins for the source and destination of each captured package.
What is actually happening:
Parsing Aborted
<placemark>
with IP: 212.204.214.114.Code and other important stuffz:
You can find the whole .kml-file here.
The headers are correct (if the book and other SO threads are to believed):
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
And all of the placemarks have this simple structure:
<Placemark>
<name>212.204.214.114</name>
<Point>
<coordinates>4.834300, 52.404800</coordinates>
</Point>
</Placemark>
My code follows the same structure as the module in Violent Python, with some small changes to better follow more modern best practices:
import dpkt, socket, pygeoip, argparse, os
gi = pygeoip.GeoIP('/opt/GeoIP/Geo.dat')
def ret_klm(ip):
rec = gi.record_by_name(ip)
try:
long = rec['longitude']
lat = rec['latitude']
kml = (
'<Placemark>\n'
'<name>%s</name>\n'
'<Point>\n'
'<coordinates>%6f, %6f</coordinates>\n'
'</Point>\n'
'</Placemark>\n'
)%(ip, long, lat)
return kml
except:
return ''
def plotIPs(pcap):
kml_points = ''
for (ts, buf) in pcap:
try:
eth = dpkt.ethernet.Ethernet(buf)
ip = eth.data
src = socket.inet_ntoa(ip.src)
src_kml = ret_klm(src)
dst = socket.inet_ntoa(ip.dst)
dst_kml = ret_klm(dst)
kml_points = kml_points + src_kml + dst_kml
except:
pass
return kml_points
def main():
parser = argparse.ArgumentParser(
description=u'GeoLocator to parse IP addresses to their '
u'long, lat in KML for Google Maps.'
)
parser.add_argument(
u'-p',
help=u'Pcap file for parsing',
required=True,
dest=u'pcap_file'
)
arguments = parser.parse_args()
if not os.path.isfile(arguments.pcap_file):
parser.print_usage()
raise SystemExit
with open(arguments.pcap_file) as file:
pcap = dpkt.pcap.Reader(file)
kmlheader = '<?xml version="1.0" encoding="UTF-8"?>'+\
'\n<kml xmlns="http://www.opengis.net/kml/2.2">\n'
kmlfooter = '</kml>\n'
kmldoc = kmlheader + plotIPs(pcap) + kmlfooter
print(kmldoc)
if __name__ == '__main__':
main()
You need to add a <Document> element to your KML that will wrap all of your <Placemark> elements. Something like:
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2" xmlns:kml="http://www.opengis.net/kml/2.2" xmlns:atom="http://www.w3.org/2005/Atom">
<Document>
<Placemark>
<name>212.204.214.114</name>
<Point>
<coordinates>4.834300, 52.404800</coordinates>
</Point>
</Placemark>
<Placemark>
<name>212.204.214.114</name>
<Point>
<coordinates>4.834300, 52.404800</coordinates>
</Point>
</Placemark>
<!-- the rest of your placemarks -->
</Document>
</kml>