-
Notifications
You must be signed in to change notification settings - Fork 115
/
ipsearch
executable file
·277 lines (230 loc) · 7.61 KB
/
ipsearch
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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
#! /usr/bin/env python3
# Search for IP clients on the current network.
# Only tested on Linux; requires ping or the Linux arguments for arp.
# ipsearch with no arguments uses ping; it takes a while but should be reliable.
# ipsearch -a uses arp only, which is fast but only shows
# hosts in the arp cache.
import sys
import subprocess
import socket
import fcntl
import struct
import re
import argparse
try:
from arpreq import arpreq
except:
arpreq = None
try:
from mac_lookup import match_mac
except:
match_mac = None
# Some globals
g_debugging = False
g_can_ping = True
g_can_arp = True
def ping(host):
"""Ping a host by name or address.
Return True if it answers, False otherwise.
If ping doesn't exist on the machine, raises FileNotFoundError.
"""
if not g_can_ping:
return False
rv = subprocess.call(["ping", "-q", "-c", "1", "-W", "1", host],
stdout = subprocess.PIPE,
stderr = subprocess.PIPE)
if rv == 0:
return True
return False
def fping(network):
"""Ping all hosts on the given network.
Return a list of the hosts that responded.
Raises FileNotFoundError if fping isn't installed.
"""
proc = subprocess.Popen(["fping", "-c1", "-t1000"]
+ [ network + '.'
+ str(i) for i in range(1,256) ],
stdout = subprocess.PIPE,
stderr = subprocess.PIPE)
proc_out = proc.communicate()
# Now proc_out[0].decode("utf-8") contains lines like
# 192.168.1.1 : [0], 84 bytes, 0.42 ms (0.42 avg, 0% loss)
# for everything that actually did respond.
#
# proc_out[0].decode("utf-8") contains stats about all hosts,
# 192.168.1.1 : xmt/rcv/%loss = 1/1/0%, min/avg/max = 0.42/0.42/0.42
# 192.168.1.2 : xmt/rcv/%loss = 1/0/100%
hits = []
for line in proc_out[0].decode("utf-8").split('\n'):
match = re.match(r'([0-9]{1,3}[\.]){3}([0-9]{1,3})', line)
if match:
hits.append(match.group())
return hits
def arp(host):
"""Call arp -a on an address.
Return the MAC if it answers, None if it doesn't.
If arp doesn't exist on the machine, raises FileNotFoundError.
"""
if arpreq:
return arpreq(host)
if not g_can_arp:
print("can't arp, skipping", host)
return False
proc = subprocess.Popen(["arp", "-a", host],
stdout = subprocess.PIPE,
stderr = subprocess.PIPE)
proc_out = proc.communicate()[0].strip()
if b"no match found" in proc_out:
# print("no match found, returning none")
return None
# else:
# print("'no match found' isn't in '%s'" % proc_out)
if b"<incomplete>" in proc_out:
return None
match = re.search(b'([0-9A-F]{2}[:-]){5}([0-9A-F]{2})', proc_out, re.I)
if match:
return match.group().decode("utf-8")
return None
def check_port(host, port):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(.25)
result = sock.connect_ex((host, port))
sock.close()
return not result
def net_interfaces():
ifaces = []
with open("/proc/net/dev") as fp:
for line in fp:
match = re.search('([a-z0-9]+): ', line)
if match:
iface = match.group(1)
if not iface.startswith('lo'):
ifaces.append(iface)
return ifaces
def ip_addr(iface):
"""Get the IP address of the interface (e.g. eth0)
"""
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
info = fcntl.ioctl(s.fileno(),
0x8915, # SIOCGIFADDR
struct.pack('256s', bytes(iface[:15], "utf-8")))
return socket.inet_ntoa(info[20:24])
def scan(iface, port=None):
"""Scan all hosts on the network specified by the interface iface.
This is not smart about network classes: it will replace the
final number in the dotted quad with 1-255.
"""
myip = ip_addr(iface)
mynetwork = '.'.join(myip.split('.')[0:3])
if (g_debugging):
print("My IP is", myip, "on", iface)
print("My network is", mynetwork)
print()
fmt = "%15s %18s %12s %s"
# Use fping to ping all hosts
try:
pinghosts = fping(mynetwork)
ping_separately = False
except FileNotFoundError:
print("Couldn't fping, will have to ping all hosts separately")
pinghosts = [ mynetwork + '.' + str(i) for i in range(1,256) ]
ping_separately = True
for hostip in pinghosts: # I know, it should adjust based on net class
# hostip = "%s.%d" % (mynetwork, h)
if g_debugging:
print(hostip, end='\r')
sys.stdout.flush()
if port:
if not check_port(hostip, port):
continue
if ping_separately:
pingout = ping(hostip)
if not pingout:
continue
mac = arp(hostip)
if not mac:
continue
if match_mac:
oui = match_mac(mac)
else:
oui = ''
try:
hostname, blah1, blah2 = socket.gethostbyaddr(hostip)
except:
hostname = '--'
if hostip == myip:
print(fmt % (hostip, mac, hostname, oui), "(that's me)")
else:
print(fmt % (hostip, mac, hostname, oui))
def net_interfaces():
ifaces = []
with open("/proc/net/dev") as fp:
for line in fp:
match = re.search('([a-z0-9]+): ', line)
if match:
iface = match.group(1)
if not iface.startswith('lo'):
ifaces.append(iface)
return ifaces
if __name__ == "__main__":
def Usage():
print("""Usage: %s [-a] [-p]
-p: ping each host first, in case they weren't in the arp cache already
-a: Use arp -a to ping.
""" % sys.argv[0])
sys.exit(1)
parser = argparse.ArgumentParser()
parser.add_argument('-d', "--debug", dest="debug", default=False,
action="store_true", help="Verbose debugging")
parser.add_argument('-p', action="store", dest="port", type=int,
default=None, help='Check if this port is open')
args = parser.parse_args(sys.argv[1:])
if args.debug:
g_debugging = True
ifaces = net_interfaces()
if g_debugging:
print("Net interfaces:", ' '.join(ifaces))
myip = None
for iface in ifaces:
try:
myip = ip_addr(iface)
break
except OSError:
continue
if not myip:
print("Couldn't find my IP address", file=sys.stderr)
sys.exit(1)
# Can we ping or arp?
try:
g_can_ping = bool(ping(myip))
except FileNotFoundError:
print("Can't ping", file=sys.stderr)
# sys.exit(1)
if not arpreq:
try:
arpout = arp(myip)
if g_debugging:
print("Will use individual arp calls")
except FileNotFoundError:
print("Can't arp", file=sys.stderr)
g_can_arp = False
sys.exit(1)
elif g_debugging:
print("Using arpreq library")
ifaces = net_interfaces()
if g_debugging:
print("Net interfaces:", ' '.join(ifaces))
myip = None
for iface in ifaces:
try:
myip = ip_addr(iface)
break
except OSError:
continue
if not myip:
print("Couldn't find my IP address")
sys.exit(1)
try:
scan(iface, port=args.port)
except KeyboardInterrupt:
print("Interrupt")