-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathicmplib.py
68 lines (55 loc) · 1.71 KB
/
icmplib.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# -*- coding: utf-8 -*-
# vim:set ts=8 sts=8 sw=8 tw=80 noet cc=80:
import socket as _socket
import time
import struct
import select
'''
Utilities for ICMP socket.
For the socket usage: https://lkml.org/lkml/2011/5/10/389
For the packet structure: https://bitbucket.org/delroth/python-ping
enable icmp socket: sysctl -w net.ipv4.ping_group_range="1000 1000"
'''
ICMP_ECHO_REQUEST = 8
_d_size = struct.calcsize('d')
def pack_packet(seq, payload):
# Header is type (8), code (8), checksum (16), id (16), sequence (16)
# The checksum is always recomputed by the kernel, and the id is the
# port number
header = struct.pack('bbHHh', ICMP_ECHO_REQUEST, 0, 0, 0, seq)
return header + payload
def parse_packet(data):
type, code, checksum, packet_id, sequence = struct.unpack('bbHHh',
data[:8])
return sequence, data[8:]
def pack_packet_with_time(seq, packetsize=56):
padding = (packetsize - _d_size) * b'Q'
timeinfo = struct.pack('d', time.time())
return pack_packet(seq, timeinfo + padding)
def parse_packet_with_time(data):
seq, payload = parse_packet(data)
t = struct.unpack('d', payload[:_d_size])[0]
return seq, t
def socket():
return _socket.socket(_socket.AF_INET, _socket.SOCK_DGRAM,
_socket.IPPROTO_ICMP)
def ping(address, timeout=3):
address = _socket.gethostbyname(address)
s = socket()
s.sendto(pack_packet_with_time(1), (address, 0))
s.setblocking(0)
s.settimeout(timeout)
ready = select.select([s], [], [], timeout)
if ready[0]:
packet, peer = s.recvfrom(1024)
_, t = parse_packet_with_time(packet)
return time.time() - t
return None
def main():
import sys
if len(sys.argv) != 2:
sys.exit('where to ping?')
t = ping(sys.argv[1])
print('%9.3fms.' % (t * 1000))
if __name__ == '__main__':
main()