为何Python网络追踪代码仅输出KML头尾,无IP位置信息?
问题排查:Python网络追踪工具仅输出KML头尾无IP位置内容
我参照教程用Python、Wireshark和Google Maps制作可视化网络追踪工具,理解整体原理,但代码仅输出KML头和尾,没有生成IP相关的位置内容。猜测代码未正确读取pcap文件,但找不到问题所在,请求协助排查。
原代码如下:
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()
核心问题及修复方案
1. 未初始化GeoIP数据库实例
代码中直接调用gi.record_by_name()但从未定义gi对象,这会直接触发异常,导致retKML返回空字符串。
- 修复:在
main函数中初始化GeoIP实例,确保你已下载GeoLiteCity数据库文件(如GeoLiteCity.dat)并放在代码可访问路径:gi = pygeoip.GeoIP('GeoLiteCity.dat')
2. 宽泛异常捕获掩盖错误
代码中用except:捕获所有异常,无法定位具体问题(比如pcap解析失败、IP无定位记录、字段不存在等)。
- 修复:替换为捕获特定异常并打印错误信息,例如:
在plotIPs的异常块中:
在except Exception as e: print(f"数据包解析失败: {e}") passretKML的异常块中:except Exception as e: print(f"KML生成失败(目标IP: {dstip}): {e}") return ''
3. 源IP硬编码且逻辑错误
retKML中硬编码源IP为'x.xxx.xxx.xxx',既未使用传入的srcip参数,也无法保证该IP能被GeoIP识别。
- 修复:改用传入的源IP参数:
同时注意:内网IP无法被GeoIP定位,若测试用数据包多为内网流量,需筛选公网IP。src = gi.record_by_name(srcip)
4. 未过滤非IP数据包
pcap文件中可能包含ARP等非IP数据包,直接解析eth.data会导致错误。
- 修复:在
plotIPs中增加IP类型判断:if not isinstance(ip, dpkt.ip.IP): continue
5. KML转义字符冗余
原代码中使用<、"等转义字符,直接写普通XML标签即可,避免解析问题。
修复后完整代码
import dpkt import socket import pygeoip def plotIPs(pcap, gi): kmlPts = '' for (ts, buf) in pcap: try: eth = dpkt.ethernet.Ethernet(buf) ip = eth.data # 过滤非IP数据包 if not isinstance(ip, dpkt.ip.IP): continue src = socket.inet_ntoa(ip.src) dst = socket.inet_ntoa(ip.dst) KML = retKML(dst, src, gi) kmlPts += KML except Exception as e: print(f"数据包解析失败: {e}") pass return kmlPts def retKML(dstip, srcip, gi): try: dst = gi.record_by_name(dstip) src = gi.record_by_name(srcip) # 跳过无法定位的IP if not dst or not src: return '' 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 Exception as e: print(f"KML生成失败(目标IP: {dstip}): {e}") return '' def main(): # 初始化GeoIP数据库 try: gi = pygeoip.GeoIP('GeoLiteCity.dat') except Exception as e: print(f"GeoIP数据库加载失败: {e}") return # 读取pcap文件 try: with open('DataCapture.pcap', 'rb') as f: 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, gi) + kmlfooter print(kmldoc) except Exception as e: print(f"pcap文件打开失败: {e}") if __name__ == '__main__': main()
内容的提问来源于stack exchange,提问作者papasamil
相关产品推荐
相关产品推荐

