-
Notifications
You must be signed in to change notification settings - Fork 81
/
Copy pathipscan.sh
executable file
·288 lines (228 loc) · 7.67 KB
/
ipscan.sh
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
278
279
280
281
282
283
284
285
286
287
288
#!/usr/bin/env bash
#
# Copyright (C) 2017 Hiveon Holding LTD
# Distributed under Business Source License 1.1
# License information can be found in the LICENSE.txt file or at https://github.com/minershive/hiveos-asic/blob/master/LICENSE.txt
#
# Linted by shellcheck 0.7.0
#
readonly script_mission='Client for ASICs: Network ASIC scanner (Antminers only)'
readonly script_version='1.3.0'
readonly script_basename="${0##*/}"
# !!! bash strict mode, no unbound variables
set -o nounset # commented out for production bc still not tested thoroughly
# functions
function echo_error {
echo -e "${BRED-}${*}${NOCOLOR-}"
} 1>&2
function print_script_version {
echo -e "${YELLOW-}${script_mission}, version ${script_version}${NOCOLOR-}"
echo
} 1>&2
function print_script_usage {
echo -e "Usage ${CYAN-}$script_basename network/prefix [network/prefix...]${NOCOLOR-}"
echo
echo -e " ${CYAN-}$script_basename${NOCOLOR-} 192.168.0.0/24"
echo -e " ${CYAN-}$script_basename${NOCOLOR-} 192.168.0.0/24 192.168.100.0/24"
echo -e " ${CYAN-}$script_basename${NOCOLOR-} 172.16.1.0/16 192.168.1.0/24 10.0.1.0/24"
echo -e " ${CYAN-}$script_basename${NOCOLOR-} 192.168.0.0/24 > ips.txt"
echo
} 1>&2
is_on_busybox() {
# vars
local canonical_path
# code
canonical_path="$( readlink -f "$( command -v timeout )" )" && [[ "$canonical_path" == *'/busybox'* ]] #" syntax highlighting fix
}
function are_programs_available {
# args
#local -r program_list="$@"
# flags
local -i something_is_not_available_FLAG=0
# vars
local this_program
# code
for this_program in "$@"; do
if ! hash "$this_program" 2> /dev/null; then
something_is_not_available_FLAG=1
break
fi
done
return $(( something_is_not_available_FLAG ))
}
function trim_string {
# args
local -r string_to_trim="$1"
# vars
local trimmed_string
# code
shopt -s extglob
trimmed_string="${string_to_trim##+([[:space:]])}" # trim leading
trimmed_string="${trimmed_string%%+([[:space:]])}" # trim trailing
echo "$trimmed_string"
}
function prefix_to_bit_netmask {
# args
local -r prefix="$1"
# vars
local bitmask='' space
local -i this_bit num
# code
for (( this_bit = 0; this_bit < 32; this_bit++ )); do
(( this_bit < prefix )) && num=1 || num=0
(( this_bit % 8 == 0 )) && space=' ' || space=''
bitmask="${bitmask}${space}${num}"
done
trim_string "$bitmask"
}
function bit_netmask_to_wildcard_netmask {
# args
local -r bitmask="$1"
# vars
local this_octet wildcard_mask=''
# code
for this_octet in $bitmask; do
wildcard_mask="${wildcard_mask} $(( 255 - 2#$this_octet ))"
done
trim_string "$wildcard_mask"
}
function is_valid_cidr {
# args
local -r cidr_to_validate="$1"
# const
local -r valid_ip_range_RE='^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})/([0-9]{1,2})$'
# vars
local -i ip ip1 ip2 ip3 ip4 N
# code
if [[ "$cidr_to_validate" =~ $valid_ip_range_RE ]]; then
ip1="${BASH_REMATCH[1]}"
ip2="${BASH_REMATCH[2]}"
ip3="${BASH_REMATCH[3]}"
ip4="${BASH_REMATCH[4]}"
N="${BASH_REMATCH[5]}"
(( ip = ip1 * 256 ** 3 + ip2 * 256 ** 2 + ip3 * 256 + ip4 ))
if (( ip % 2**(32-N) != 0 )); then
echo_error "'$cidr_to_validate' is not a valid IP range (address or netmask part is wrong by means of the address arithmetic)"
return 1
fi
else
echo_error "'$cidr_to_validate' is not a valid IP range"
return 1
fi
}
function get_asic_model {
# args
local -r asic_ip="$1"
# vars
local timeout_options
# code
if is_on_busybox; then
timeout_options='-t 7'
else
timeout_options='7'
fi
echo '{"command":"stats"}' | timeout $timeout_options nc "$asic_ip" 4028 | tr -d '\0\n' | sed 's/}{/\},{/' | jq --raw-output '.STATS[0].Type'
}
function process_ip_ranges {
# vars
local this_ip_range net_part prefix_part bit_netmask wildcard_mask str range ip_list_for_eval ip_list_for_display this_ip
local -i this_octet mask_octet
# code
for this_ip_range in "$@"; do
# assert: ip address range is valid
is_valid_cidr "$this_ip_range" || continue
net_part="${this_ip_range%/*}"
prefix_part="${this_ip_range#*/}"
bit_netmask="$( prefix_to_bit_netmask "$prefix_part" )"
wildcard_mask="$( bit_netmask_to_wildcard_netmask "$bit_netmask" )"
# debug
#echo "this_ip_range '$this_ip_range', net_part '$net_part', prefix_part '$prefix_part', bit_netmask '$bit_netmask', wildcard_mask '$wildcard_mask'"
str=''
for (( this_octet = 1; this_octet <= 4; this_octet++ )); do
range="$( cut -d '.' -f "$this_octet" <<< "$net_part" )"
mask_octet="$( cut -d ' ' -f "$this_octet" <<< "$wildcard_mask" )"
if (( mask_octet > 0 )); then
range="{0..$mask_octet}"
fi
str="$str $range"
done
: "$( trim_string "$str" )"
ip_list_for_eval="${_// /.}"
: "${ip_list_for_eval//{/[}"
: "${_//\}/]}"
: "${_//../-}"
ip_list_for_display="$_"
message="Scanning range ${WHITE}${ip_list_for_display}${NOCOLOR}"
for this_ip in $( eval echo "$ip_list_for_eval" ); do # eval is to expand "{n..m}" template(s)
echo -e -n "\r${message}: $this_ip" 1>&2
# --verbose and --silent options at the same time does make a verbose output (we need that) but hides curl errors (we don't need them)
curl --verbose --silent --max-time 5 "$this_ip:80" 2>&1 | grep -Fq 'Miner Configuration' && touch "/dev/shm/ip/$this_ip" & # let's parallelize!
{ sleep 0.1 || usleep 100000; } 2> /dev/null # only integer sleep on BusyBox
done
echo -e -n "\r${message} done. Processing answers..." 1>&2
wait
done
}
function print_antminers_found {
# arrays
local -a antminer_ip_list_ARR=() antminer_model_list_ARR=()
# vars
local this_antminer_ip this_antminer_model
local -i antminers_found this_element
# code
# shellcheck disable=SC2012
# bc there's a problem with only-filenames-find-from-busybox
readarray -t antminer_ip_list_ARR < <( ls /dev/shm/ip/ | sort -n -t . -k 1,1 -k 2,2 -k 3,3 -k 4,4 )
antminers_found="${#antminer_ip_list_ARR[@]}"
if (( antminers_found )); then
{
echo
echo "Antminers found: $antminers_found"
echo
printf '%-15.15s %s\n' 'IP address' 'Model'
for (( this_element = 0; this_element < antminers_found; this_element++ )); do
this_antminer_ip="${antminer_ip_list_ARR[this_element]-}"
[[ -z "$this_antminer_ip" ]] && continue # out of boundaries check
if are_programs_available 'timeout' 'nc' 'jq'; then
this_antminer_model="$( get_asic_model "$this_antminer_ip" 2>&1 )"
antminer_model_list_ARR[this_element]="$this_antminer_model"
else
this_antminer_model="${DGRAY-}<detection skipped>${NOCOLOR-}"
fi
printf '%-15.15s %b\n' "$this_antminer_ip" "$this_antminer_model"
done
echo
} 1>&2
if [[ ! -t 1 ]]; then # print this only if stdout redirected
printf '#\n# %s: range(s) %s scanned at %(%F %T)T, %d Antminers found\n#\n' "$script_basename" "$*" -1 "$antminers_found"
for (( this_element = 0; this_element < antminers_found; this_element++ )); do
this_antminer_ip="${antminer_ip_list_ARR[this_element]-}"
this_antminer_model="${antminer_model_list_ARR[this_element]-}"
[[ -z "$this_antminer_ip" ]] && continue # out of boundaries check
printf '# %s\n%s\n' "$this_antminer_model" "$this_antminer_ip"
done
fi
else
{
echo
echo 'No Antminers found'
echo
} 1>&2
fi
}
# sources
source /hive/bin/colors
# code
print_script_version
# assert: at least 1 argument does exist
[[ -n "${1-}" ]] || { print_script_usage; exit 1; }
# assert: curl is available
are_programs_available 'curl' || { echo -e "${CYAN-}curl${NOCOLOR-} is required, try ${CYAN-}apt-get install curl${NOCOLOR-}"; exit 1; }
# cleanup at exit or break
trap 'rm -rf /dev/shm/ip; exit' EXIT INT HUP
# create a directory in the shared memory
mkdir -p /dev/shm/ip
rm -rf /dev/shm/ip/*
# let's go!
process_ip_ranges "$@"
print_antminers_found "$@"