-
Notifications
You must be signed in to change notification settings - Fork 0
/
ping.py
124 lines (95 loc) · 3.85 KB
/
ping.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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#!/usr/bin/env/python3
"""Ping implementation in Python. RFC 792
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Code | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Identifier | Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Identifier
If code = 0, an identifier to aid in matching request and replies,
may be zero.
Sequence Number
If code = 0, a sequence number to aid in matching request and
replies, may be zero.
In this implementation identifier is not set and timestamp is not included in ICMP packet..
"""
import socket
import struct
import sys
from time import time, sleep
from arp import get_target_mac, mac_to_byte
from traceroute import IpPacket, get_checksum
# Network environment settings for ARP request.
INTERFACE = None # 'wlan0'
SRC_IP = None # '192.168.1.192'
DEST_IP = None # '192.168.1.1'
SRC_MAC = None # '11:aa:6d:24:01:68'
DEST_MAC = 0 if not INTERFACE else get_target_mac(DEST_IP, SRC_IP, SRC_MAC, INTERFACE) # ARP req
def ethernet_construct():
"""Constructs ethernet header"""
eth_dest_mac = mac_to_byte(DEST_MAC)
eth_src_mac = mac_to_byte(SRC_MAC)
eth_type = 0x0800 # IP
return struct.pack('>6s6sH', eth_dest_mac, eth_src_mac, eth_type)
def icmp_construct(seq=1):
"""Returns ICMP packet with all required fields.
However, identifier is not set and timestamp might also be included.
"""
icmp_type = 8 # (1B) Echo ping
icmp_code = 0 # (1B)
icmp_checksum = 0 # (2B)
icmp_id = 0 # (2B)
icmp_seq = seq # (2B)
icmp_data = b'@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_'
icmp_fmt = '>BBHHH{}s'.format(len(icmp_data))
icmp_pkt = struct.pack(icmp_fmt, icmp_type, icmp_code, icmp_checksum,
icmp_id, icmp_seq, icmp_data)
icmp_checksum = get_checksum(icmp_pkt)
icmp_pkt = struct.pack(icmp_fmt, icmp_type, icmp_code, icmp_checksum,
icmp_id, icmp_seq, icmp_data)
return icmp_pkt
def ping(url):
"""Sends echo request. In response gets echo replay."""
sock = socket.socket(socket.PF_PACKET, socket.SOCK_RAW, socket.IPPROTO_ICMP)
sock.bind((INTERFACE, 0x800))
icmp = icmp_construct()
ether = ethernet_construct()
icmp_len = len(icmp)
dest_ip = socket.gethostbyname(url)
ip = IpPacket(SRC_IP, dest_ip, icmp_len, 1) # 1 - protocol ID for ICMP
ip_pkt = ip.get_pkt(64)
base_frame = ether + ip_pkt
seq_num = 1
for _ in range(100):
resp = ''
icmp = icmp_construct(seq_num)
frame = base_frame + icmp
try:
start = time()
sock.send(frame)
while True:
resp = sock.recv(1024)
sock.settimeout(10)
if resp[23] == 1:
break
rtt = round((time() - start) * 1000, 3)
except socket.timeout:
print('Request timed out.')
continue
unpacked = struct.unpack('>6s6sHBBHHBBBBH4s4sBBHHH{}s'.format(icmp_len - 8), resp)
ip_data_size = unpacked[5] - 20 # size of ip packet - ip header
seqnum = unpacked[-2]
src = unpacked[-8]
src = socket.inet_ntoa(src)
print('{} bytes from {} ({}): icmp_seq={}, time={}ms'
.format(ip_data_size, url, src, seqnum, rtt))
seq_num += 1
sleep(1)
if __name__ == "__main__":
if not (INTERFACE and SRC_IP and DEST_IP and SRC_MAC):
print("Constant variables have to be set before running the script.\n"
"These are: INTERFACE, SRC_IP, DEST_IP and SRC_MAC.")
sys.exit(0)
ping(sys.argv[-1])