-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain3.py
160 lines (122 loc) · 5.46 KB
/
main3.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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
from arp import Arp
import optparse
import re
from checkValues import *
import socket
import time
import packetExtraction
def get_inputs():
import netifaces
parser = optparse.OptionParser()
parser.add_option('-s', '--source', help='Source IP address', dest='sip')
parser.add_option('-m', '--mac', help='Source MAC address', dest='mac')
parser.add_option('-i', '--iface', help='Interface name (required)', dest='iface')
parser.add_option('-r', '--range', help='Range of IP to scan(e.g: 192.168.1.1/24)', dest='range')
parser.add_option('-n', '--number', help='number of interface (default=1)', dest='n', default='1')
parser.add_option('-d', '--delay', help='time to wait for a response', dest='delay', default='1')
options, args = parser.parse_args()
if options.iface is None:
print('[-] Interface name is required.')
exit(1)
elif not check_iface(options.iface): # checks if there is such iface name
print('[-] Wrong interface name.')
exit(1)
else:
iface = options.iface
if options.range is None:
print('[-] Range of IPs to scan should be specified!')
exit(1)
elif not check_ip_range(options.range): # checking the FORMAT of ip range. -> CORRECT: 192.168.0.0/24 , WRONG: 192.168.0/24,
print('[-] Wrong range of IPs.')
exit(1)
else:
mask = options.range[options.range.find('/') + 1:]
rip = options.range[:options.range.find('/')]
if options.mac is None:
mac = netifaces.ifaddresses(iface)[netifaces.AF_LINK][int(options.n) - 1]['addr'] # number of nic is given from input. default is 1
else: # source MAC address is specified
if check_mac(options.mac):
mac = options.mac
else:
print('[-] Wrong MAC address')
exit(1)
if options.sip is None:
sip = netifaces.ifaddresses(options.iface)[netifaces.AF_INET][int(options.n) - 1]['addr'] # number of nic is given from input. default is 1
elif not check_ip(options.sip):
print('[-] Wrong source of IPs.')
exit(1)
else:
sip = options.sip
try: # delay should be numeric
delay = float(options.delay)
except:
print('[-] Delay should be numeric.')
exit(1)
return iface, mac, rip, int(mask), sip, delay
def make_ip_integer(ip):
# gets an ip like "192.168.1.1". it is 4 bytes or 32bit. returns an integer as its corresponding unsigned integer
assert (re.match(r'(\d{1,3}\.){3}\d{1,3}', ip))
numbers = tuple(reversed(tuple(map(int, ip.split('.')))))
res = 0
# ip can be thought of a number in base of 256. so to make it to a decimal integer we can use a loop
# numbers of ip has been reversed.
for i in range(len(numbers)):
res += 256 ** i * numbers[i]
return res
def make_integer_ip(ip_integer):
# gets an integer. this integer is assumed to be 4 bytes. this function breaks this integer to 4 bytes each of seze 1B.
# and makes an ip according to that
assert(type(ip_integer) == int)
res = ''
for i in range(4):
res += str(ip_integer // (256 ** (3 - i)))
ip_integer = ip_integer % (256 ** (3 - i))
res += '.'
res = res[:-1] # in the above for loop there will be an additional "." at the end of string.
return res
def get_range(ip, mask):
# ip is a string. -> "192.168.1.1". mask is an integer between 0, 32
# gets the net id(ip) as a string and mask.
# returns two integers. first one the start ip and second is last ip
# each integer is the converted version of 32 bit ip. e.g: 192.168.1.1 -> 11000000.10100100.00000001.00000001 -> 3232235777
assert (type(mask) == int and type(ip) == str)
if mask > 32 or mask < 0:
print('[-] Wrong mask!')
exit(1)
start = (make_ip_integer(ip) // (2 ** (32 - mask))) * (2 ** (32 - mask))
end = start + 2 ** (32 - mask) - 1
return start, end
def send_raw_packet(sock, packet, iface):
sock.sendall(packet)
def recieve_arp(sock, delay, ip, opcode=2):
# recives packets in the interval of given delay and if there was an arp packet with destination of ip and given opcode
start = time.time()
end = time.time()
while end - start < delay:
try:
sock.settimeout(delay - (end - start))
response, addr = s.recvfrom(1024)
except: # if delat < end - start or socket time out
break
headers = packetExtraction.extract(response)
if headers is None or 'ARP' not in headers:
end = time.time()
elif headers['ARP']['Opcode'] == opcode and headers['ARP']['Destination protocol address'] == ip:
return headers['ARP']['Source protocol address'], headers['ARP']['Source hardware address']
if __name__ == '__main__':
iface, mac, rip, mask, sip, delay = get_inputs()
start, end = get_range(rip, int(mask))
# creating packet for first ip in the given range
# later we use the same object for other ips with changing its dip then we call its make method
arp = Arp(sip, make_integer_ip(start), mac)
s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(3))
s.bind((iface, 0))
res = list()
for ip in range(start, end + 1):
arp.update_values({'dip': make_integer_ip(ip)})
packet = arp.make()
send_raw_packet(s, packet, iface)
response = recieve_arp(s, delay, sip)
if response:
res.append(response)
print(*res, sep='\n')