Search code examples
pythonpython-3.xnetwork-programmingkml

Why does it only print the KML header rather then the IP information


I am trying to follow a webpage in creating a visual network tracker using google maps, wireshark and python. I understand how it all works but my code seems to only be printing the header and footer.

I am guessing the code is not reading the pcap file correctly but do not see where to fix it. Any help would be greatly appreciated.

The website I was following is https://medium.com/vinsloev-academy/python-cybersecurity-network-tracking-using-wireshark-and-google-maps-2adf3e497a93

My code can be seen below;

import dpkt
import socket
import pygeoip


def plotIPs(pcap):
    kmlPts = ''
    for (ts, buf) in pcap:
        try:
            eth = dpkt.ethernet.Ethernet(buf)
            ip = eth.data
            src = socket.inet_ntoa(ip.src)
            dst = socket.inet_ntoa(ip.dst)
            KML = retKML(dst, src)
            kmlPts = kmlPts + KML
        except:
            pass
    return kmlPts

def retKML(dstip, srcip):
    dst = gi.record_by_name(dstip)
    src = gi.record_by_name('x.xxx.xxx.xxx')
    try:
        dstlongitude = dst['longitude']
        dstlatitude = dst['latitude']
        srclongitude = src['longitude']
        srclatitude = src['latitude']
        kml = (
            '<Placemark>\n'
            '<name>%s</name>\n'
            '<extrude>1</extrude>\n'
            '<tessellate>1</tessellate>\n'
            '<styleUrl>#transBluePoly</styleUrl>\n'
            '<LineString>\n'
            '<coordinates>%6f,%6f\n%6f,%6f</coordinates>\n'
            '</LineString>\n'
            '</Placemark>\n'
        )%(dstip, dstlongitude, dstlatitude, srclongitude, srclatitude)
        return kml
    except:
        return ''

def main():
    f = open('DataCapture.pcap', 'rb')
    pcap = dpkt.pcap.Reader(f)
    kmlheader = '<?xml version="1.0" encoding="UTF-8"?> \n<kml     xmlns="http://www.opengis.net/kml/2.2">\n<Document>\n'\
'<Style id="transBluePoly">' \
            '<LineStyle>' \
            '<width>1.5</width>' \
            '<color>501400E6</color>' \
            '</LineStyle>' \
            '</Style>'
    kmlfooter = '</Document>\n</kml>\n'
    kmldoc=kmlheader+plotIPs(pcap)+kmlfooter
    print(kmldoc)

if __name__ == '__main__':
    main()

Solution

  • Firstly, you are not using the full power of exception handling to see your errors, you are just using pass or return ''. So you don't know what is going on. Try printing the exception at least or a traceback.

    Then you are missing the line in your example:

        gi = pygeoip.GeoIP('GeoLiteCity.dat')
    

    And you must have GeoLiteCity.dat in your path.

    You are returning strings from your function calls, this is not a good idea and that is where I think your code is failing.

    Then you are manipulating strings to create an XML document. This is not the best practice but I know the tutorial you used did it. I'm using minidom in this example:

    import traceback
    import dpkt
    import socket
    import pygeoip
    from xml.dom import minidom
    
    gi = pygeoip.GeoIP('GeoLiteCity.dat')
    
    
    def plot_ips(pcap) -> list:
        kml_pts = []
        for (ts, buf) in pcap:
            try:
                eth = dpkt.ethernet.Ethernet(buf)
                ip = eth.data
                src = socket.inet_ntoa(ip.src)
                dst = socket.inet_ntoa(ip.dst)
                kml = ret_kml(dst, src)
                kml_pts.append(kml)
            except Exception as ex:
                print(str(ex))
                traceback.print_exc()
        return kml_pts
    
    
    def ret_kml(dst_ip, src_ip) -> dict:
        dst = gi.record_by_name(dst_ip)
        src = gi.record_by_name(src_ip)
        # print(dst)
        # print(src)
        try:
            return {
                "dst_ip": dst_ip,
                "src_ip": src_ip,
                "dst_longitude": dst['longitude'],
                "dst_latitude": dst['latitude'],
                "src_longitude": src['longitude'],
                "src_latitude": src['latitude']
            }
        except KeyError as ex:
            print(f"KeyError {ex}")
            traceback.print_exc()
            return {}
    
    
    def main():
        f = open('DataCapture.pcap', 'rb')
        pcap = dpkt.pcap.Reader(f)
        root = minidom.Document()
        kml = root.createElement('kml')
        kml.setAttribute('xmlns', "http://www.opengis.net/kml/2.2")
        root.appendChild(kml)
        document = root.createElement('Document')
        kml.appendChild(document)
        style = root.createElement('Style')
        style.setAttribute("id", "transBluePoly")
        document.appendChild(style)
        line_style = root.createElement("LineStyle")
        style.appendChild(line_style)
        width = root.createElement("width")
        width_text = root.createTextNode("1.5")
        width.appendChild(width_text)
        line_style.appendChild(width)
        color = root.createElement("color")
        color_text = root.createTextNode("501400E6")
        color.appendChild(color_text)
        line_style.appendChild(color)
    
        try:
            for record in plot_ips(pcap):
                # print(record)
                place_mark = root.createElement('Placemark')
                name = root.createElement('name')
                name_text = root.createTextNode(record.get('dst_ip'))
                name.appendChild(name_text)
                place_mark.appendChild(name)
                extrude = root.createElement('extrude')
                extrude_text = root.createTextNode('1')
                extrude.appendChild(extrude_text)
                place_mark.appendChild(extrude)
                tessellate = root.createElement('tessellate')
                tessellate_text = root.createTextNode('1')
                tessellate.appendChild(tessellate_text)
                place_mark.appendChild(tessellate)
                style_url = root.createElement('styleUrl')
                style_url_text = root.createTextNode('#transBluePoly')
                style_url.appendChild(style_url_text)
                place_mark.appendChild(style_url)
                line_string = root.createElement('LineString')
                coordinates = root.createElement('coordinates')
                coordinates_text = root.createTextNode(
                    f"{record.get('dst_ip')},{record.get('dst_longitude')},{record.get('dst_latitude')},"
                    f"{record.get('src_longitude')},{record.get('src_latitude')}"
                )
                coordinates.appendChild(coordinates_text)
                line_string.appendChild(coordinates)
                place_mark.appendChild(line_string)
                document.appendChild(place_mark)
            print(root.toprettyxml())
    
        except Exception as ex:
            print(str(ex))
            traceback.print_exc()
    
    
    if __name__ == '__main__':
        main()
    

    Using the file from https://wiki.wireshark.org/uploads/__moin_import__/attachments/SampleCaptures/ipv4frags.pcap renamed to DataCapture.pcap my code produces the following output:

    <?xml version="1.0" ?>
    <kml xmlns="http://www.opengis.net/kml/2.2">
        <Document>
            <Style id="transBluePoly">
                <LineStyle>
                    <width>1.5</width>
                    <color>501400E6</color>
                </LineStyle>
            </Style>
            <Placemark>
                <name>2.1.1.1</name>
                <extrude>1</extrude>
                <tessellate>1</tessellate>
                <styleUrl>#transBluePoly</styleUrl>
                <LineString>
                    <coordinates>2.1.1.1,2.3386999999999887,48.85820000000001,2.3386999999999887,48.85820000000001</coordinates>
                </LineString>
            </Placemark>
            <Placemark>
                <name>2.1.1.1</name>
                <extrude>1</extrude>
                <tessellate>1</tessellate>
                <styleUrl>#transBluePoly</styleUrl>
                <LineString>
                    <coordinates>2.1.1.1,2.3386999999999887,48.85820000000001,2.3386999999999887,48.85820000000001</coordinates>
                </LineString>
            </Placemark>
            <Placemark>
                <name>2.1.1.2</name>
                <extrude>1</extrude>
                <tessellate>1</tessellate>
                <styleUrl>#transBluePoly</styleUrl>
                <LineString>
                    <coordinates>2.1.1.2,2.3386999999999887,48.85820000000001,2.3386999999999887,48.85820000000001</coordinates>
                </LineString>
            </Placemark>
        </Document>
    </kml>
    

    I have not checked the syntax for Google Maps so it may need some tweaking.