1#!/usr/bin/env python 2 3import math, optparse, random, socket, sys, time 4import dpkt 5 6class Ping(object): 7 def __init__(self): 8 usage = '%prog [OPTIONS] <host>' 9 self.op = optparse.OptionParser(usage=usage) 10 self.op.add_option('-c', dest='count', type='int', default=sys.maxint, 11 help='Total number of queries to send') 12 self.op.add_option('-i', dest='wait', type='float', default=1, 13 help='Specify packet interval timeout in seconds') 14 15 def gen_ping(self, opts): 16 pass 17 def open_sock(self, opts): 18 pass 19 def print_header(self, opts): 20 pass 21 def print_reply(self, opts, buf): 22 pass 23 24 def main(self, argv=None): 25 if not argv: 26 argv = sys.argv[1:] 27 opts, args = self.op.parse_args(argv) 28 29 if not args: 30 self.op.error('missing host') 31 elif len(args) > 1: 32 self.op.error('only one host may be specified') 33 34 host = args[0] 35 opts.ip = socket.gethostbyname(host) 36 sock = self.open_sock(opts) 37 38 sent = rcvd = rtt_max = rtt_sum = rtt_sumsq = 0 39 rtt_min = 0xffff 40 try: 41 self.print_header(opts) 42 for ping in self.gen_ping(opts): 43 try: 44 start = time.time() 45 sock.send(ping) 46 buf = sock.recv(0xffff) 47 rtt = time.time() - start 48 49 if rtt < rtt_min: rtt_min = rtt 50 if rtt > rtt_max: rtt_max = rtt 51 rtt_sum += rtt 52 rtt_sumsq += rtt * rtt 53 54 self.print_reply(opts, buf, rtt) 55 rcvd += 1 56 except socket.timeout: 57 pass 58 sent += 1 59 time.sleep(opts.wait) 60 except KeyboardInterrupt: 61 pass 62 63 print '\n--- %s ping statistics ---' % opts.ip 64 print '%d packets transmitted, %d packets received, %.1f%% packet loss' % \ 65 (sent, rcvd, (float(sent - rcvd) / sent) * 100) 66 rtt_avg = rtt_sum / sent 67 if rtt_min == 0xffff: rtt_min = 0 68 print 'round-trip min/avg/max/std-dev = %.3f/%.3f/%.3f/%.3f ms' % \ 69 (rtt_min * 1000, rtt_avg * 1000, rtt_max * 1000, 70 math.sqrt((rtt_sumsq / sent) - (rtt_avg * rtt_avg)) * 1000) 71 72class ICMPPing(Ping): 73 def __init__(self): 74 Ping.__init__(self) 75 self.op.add_option('-p', dest='payload', type='string', 76 default='hello world!', 77 help='Echo payload string') 78 79 def open_sock(self, opts): 80 sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, 1) 81 sock.connect((opts.ip, 1)) 82 sock.settimeout(opts.wait) 83 return sock 84 85 def gen_ping(self, opts): 86 for i in xrange(opts.count): 87 icmp = dpkt.icmp.ICMP( 88 type=8, data=dpkt.icmp.ICMP.Echo(id=random.randint(0, 0xffff), 89 seq=i, data=opts.payload)) 90 yield str(icmp) 91 92 def print_header(self, opts): 93 print 'PING %s: %d data bytes' % (opts.ip, len(opts.payload)) 94 95 def print_reply(self, opts, buf, rtt): 96 ip = dpkt.ip.IP(buf) 97 if sys.platform == 'darwin': 98 # XXX - work around raw socket bug on MacOS X 99 ip.data = ip.icmp = dpkt.icmp.ICMP(buf[20:]) 100 ip.len = len(ip.data) 101 print '%d bytes from %s: icmp_seq=%d ip_id=%d ttl=%d time=%.3f ms' % \ 102 (len(ip.icmp), opts.ip, ip.icmp.echo.seq, ip.id, ip.ttl, 103 rtt * 1000) 104 105if __name__ == '__main__': 106 p = ICMPPing() 107 p.main() 108