Scapy如何获得ping时间?

时间:2012-10-31 17:27:48

标签: python networking time ping scapy

我正在尝试编写一个scapy脚本,它可以在ping时间上取平均值,因此我需要获取ICMP回送/回复数据包发送和收到回复数据包之间的时间。现在,我有这个:

#! /usr/bin/env python
from scapy.all import *
from time import *

def QoS_ping(host, count=3):
  packet = Ether()/IP(dst=host)/ICMP()
  t=0.0
  for x in range(count):
      t1=time()
      ans=srp(packet,iface="eth0", verbose=0)
      t2=time()
      t+=t2-t1
  return (t/count)*1000

问题是使用time()函数不会产生好的结果。例如,我在一个域上发现134毫秒,并且在同一个域上使用ping系统功能,我发现30毫秒(当然是平均值)。

我的问题是:有没有办法通过scapy获得发送数据包和收到数据包之间的确切时间? 我不想使用popen()函数或其他系统调用,因为我需要scapy来进行未来数据包管理。

3 个答案:

答案 0 :(得分:6)

Scapy很慢,因为它是纯粹的python解析用户空间中的整个数据包... it is not all that unusual to hack around scapy's thoughput limitations

进行苹果与苹果的比较...我有一个Xeon服务器,带有直接的gig以太网管道到互联网,但我的流量很轻。当我对连接到的Cisco路由器运行正常ping时,我平均每个大约60微秒......

[mpenning@Bucksnort ~]$ ping -W 1 -c 3 192.0.2.1
PING 192.0.2.1 (192.0.2.6) 56(84) bytes of data.
64 bytes from 192.0.2.1: icmp_req=1 ttl=64 time=0.078 ms
64 bytes from 192.0.2.1: icmp_req=2 ttl=64 time=0.062 ms
64 bytes from 192.0.2.1: icmp_req=3 ttl=64 time=0.062 ms

--- 192.0.2.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1998ms
rtt min/avg/max/mdev = 0.062/0.067/0.078/0.010 ms
[mpenning@Bucksnort ~]$

scapy中的同一目的地......也以毫秒计算......

[mpenning@Bucksnort ~]$ sudo python new_ping_ip.py
Ping: 0.285587072372
Ping: 0.230889797211
Ping: 0.219928979874
AVERAGE 245.468616486
[mpenning@Bucksnort ~]$

Scapy的结果几乎比bash提示符(245.469 / 0.062)的基线ping强<4000> ...我自己运行了电缆,它距离思科不到10英尺电缆路由器。

您可以做些什么来获得更好的结果?正如评论中所提到的,看看sent_timetime ... Packet.time在解析之前已填充...这仍然比来自shell的ping慢,但可能有助于满足您的需求在scapy中捕获数据包。

#! /usr/bin/env python
from scapy.all import *

def QoS_ping(host, count=3):
  packet = Ether()/IP(dst=host)/ICMP()
  t=0.0
  for x in range(count):
      ans,unans=srp(packet,iface="eth0", filter='icmp', verbose=0)
      rx = ans[0][1]
      tx = ans[0][0]
      delta = rx.time-tx.sent_time
      print "Ping:", delta
      t+=delta
  return (t/count)*1000

if __name__=="__main__":
    total = QoS_ping('192.0.2.1')
    print "TOTAL", total

示例运行...

[mpenning@Bucksnort ~]$ sudo python ping_ip.py
Ping: 0.000389099121094
Ping: 0.000531911849976
Ping: 0.000631093978882
TOTAL 0.51736831665
[mpenning@Bucksnort ~]$

与shell调用相比,即使使用Packet.timePacket.sent_time也很慢......

>>> from subprocess import Popen, PIPE
>>> import re
>>> cmd = Popen('ping -q -c 3 192.0.2.1'.split(' '), stdout=PIPE)
>>> output = cmd.communicate()[0]
>>> match = re.search('(\d+\.\d+)\/(\d+\.\d+)\/(\d+\.\d+)\/(\d+\.\d+)\s+ms', output)
>>> if not (match is None):
...     print "Average %0.3f" % float(match.group(1))
... else:
...     print "Failure"
...
Average 0.073
>>>

ping -q -c 3提供3个ping的摘要输出,而不打印单个ping。

如果要捕获ping数据包(通过shell ping调用)以便以后进行scapy处理,请在运行CLI ping之前生成tcpdump -c <num-packets> -w <filename> icmp and host <host-addr> & ...然后使用scapy的rdpcap()来从tcpdump读取pcap文件。请务必正确计算您将在pcap文件中捕获的数据包数量。

答案 1 :(得分:0)

BTW,使用unbuffered python(python -u启动它)可以提高计时准确性,因为python不会等待缓冲区决定转储。使用上面的脚本,它将我的结果从关闭0.4毫秒变为关闭0.1-ish。

答案 2 :(得分:0)

迈克,为了获得平均时间,只需要一个小小的修正,改变:

print "Average %0.3f" % float(match.group(1))

为:

 print "Average %0.3f" % float(match.group(2))

因为(match.group(1))将得到最小时间而不是所提到的平均值。