-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcrib
executable file
·251 lines (219 loc) · 5.27 KB
/
crib
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
#!/bin/bash -
# Print a country's IPv4 prefixes in CIDR notation to standard output
# Version 3.0
# Written by Bernard Lim <bernard.lim@sands.com>
AUTHOR="Bernard Lim <lim.yiok.kia@gmail.com>"
VERSION="3.0"
PROG=$(basename $0)
# default: CC to IP blocks
ACTION=cc2ip
# fanciful output
b="\033[1m" # bold
u="\033[4m" # underline
o="\033[0m" # off
# clean up upon EXIT
clean() {
rm /tmp/*.xargs &>/dev/null
}
trap "clean" EXIT
# dependency message
depends() {
echo "$PROG: depends on \`$*'" >&2
echo "Install \`$*' and try again." >&2
exit 1
}
# die a graceful death!
die() {
echo "$PROG: $*" >&2
echo "Try \`$PROG -h' for more information" >&2
exit 1
}
# shorter usage
short() {
usage | sed 2q
echo "Try \`$PROG -h' for more information"
}
# usage
usage() {
cat <<EOF
Usage: $PROG [OPTION]... [CC]... (2-letter country code)
Print CC's IPv4 prefixes in CIDR notation to standard output.
$(echo -e ${b}Options${o})
-a Print ASN's IPv4 prefixes and exit
-c Print CC's ASNs and exit
-h Display this help and exit
-p n Run n processes in parallel (default n=64)
-v Show version information and exit
$PROG uses ISO 3166-1 alpha-2 codes to represent country.
They are 2-letter country codes used widely to represent
countries, dependent territories and special areas of
geographical interest. Examples: SG for Singapore or
US for United States.
When CC is -, read standard input. This can be useful if you
$(echo -ne ${b}cat${o})(1) a list of country codes to $PROG for bulk operations.
$(echo -e ${b}Examples${o})
$PROG SG # Print Singapore's IPv4 prefixes (fast)
$PROG US # Print United States' IPv4 prefixes (slow)
$PROG -p 100 SG # Same but run 100 processes in parallel
$PROG -a AS668 # Print IPv4 prefixes originating from AS668
$PROG -c SG # Print ASNs originating from SG
Report $PROG bugs to $AUTHOR
This software is distributed in the hope that it will be
useful but without any warranty. It is provided "as is".
EOF
}
# ASN to IP prefixes
asn2ip() {
if which whois &>/dev/null; then
local asn=$1
validate_asn $asn
if [[ -z "$asn" || "$asn" == "-" ]]; then
cat -
else
cat - <<<"$asn"
fi | \
$PARALLEL sh -c 'whois -h whois.radb.net !g"{}" > /tmp/"{}".xargs' 2>/dev/null
# awk to the rescue again
cat /tmp/*.xargs |
awk '\
BEGIN { RS = "(A[0-9]+|[CD])\n?"; FS = " "; }
{ for (i = 1; i <= NF; i++) print $i }' |
tr -d "\n" |
sed -r 's/(\/([0-9]|1[0-9]|2[0-9]|3[0-2]))/\1\n/g' |
sort -t. -n -k1,1 -k2,2 -k3,3 -k4,4 |
uniq -c |
awk '{ print $NF }'
else
depends "whois"
fi
}
# CC to ASN
cc2asn() {
if which curl &>/dev/null; then
local cc=$(tr 'a-z' 'A-Z' <<<"$1"); validate_cc $cc
local ua="Mozilla/5.0"
local url="https://bgp.he.net/country"
if [[ -z "$cc" || "$cc" == "-" ]]; then
cat -
else
cat - <<<"$cc"
fi |
($PARALLEL curl -sk -A "$ua" "$url/{}" | grep -Eo 'AS[0-9]+' &) |
uniq -c |
awk '{ print $NF }' |
tr -d 'AS' |
sort -n |
sed 's/^/AS/'
else
depends "curl"
fi
}
# CC to IP prefixes
cc2ip() {
if which curl &>/dev/null; then
local cc=$(tr 'a-z' 'A-Z' <<<"$1")
validate_cc $cc
if [[ -z "$cc" || "$cc" == "-" ]]; then
cc2asn -
else
cc2asn - <<<"$cc"
fi | asn2ip -
else
depends "curl"
fi
}
# validate ASN
validate_asn() {
local asn=$1
# sanity check
if [ -z "$asn" ]; then
die "missing argument: [ASN]"
else
# format check
if grep -Ev '^(-?|[aA][sS][0-9]+)$' <<<"$asn" > /dev/null; then
die "invalid ASN"
fi
fi
}
# validate CC
validate_cc() {
local cc=$1
# sanity check
if [ -z "$cc" ]; then
die "missing argument: [CC]"
else
# format check
if grep -Ev '^(-?|[a-zA-Z]{2})$' <<<"$cc" >/dev/null; then
die "invalid country code"
fi
fi
}
# parse short options
OPTIND=1
while getopts ":achp:v" opt; do
case $opt in
a)
if [[ "$LASTOPT" == "$opt" ]]; then
die "only one \`-$opt' may be specified"
fi
ACTION=asn2ip
LASTOPT=$opt
;;
c)
if [[ "$LASTOPT" == "$opt" ]]; then
die "only one \`$opt' may be specified"
fi
ACTION=cc2asn
LASTOPT=$opt
;;
h)
if [[ $# -ne 1 || $OPTIND -eq 1 ]]; then short; exit 1; fi
usage
exit 0
;;
p)
if [[ "$LASTOPT" == "$opt" ]]; then
die "only one \`$opt' may be specified"
fi
# validate option argument
if grep -Ev '^[0-9]+$' &>/dev/null <<<"$OPTARG"; then
die "invalid option argument -- '$OPTARG'"
exit 1
fi
MAX=$((10#$OPTARG))
LASTOPT=$opt
;;
v)
if [[ $# -ne 1 || $OPTIND -eq 1 ]]; then short; exit 1; fi
echo "$PROG $VERSION"
echo "Written by $AUTHOR"
exit 0
;;
:)
die "option requires an argument -- '$OPTARG'"
;;
\?)
die "invalid option -- '$OPTARG'"
;;
esac
done;
shift $((OPTIND-1))
# check for empty arguments
if [[ -n "$LASTOPT" && $# -eq 0 ]]; then
case $LASTOPT in
a) validate_asn; exit 1;;
c) validate_cc; exit 1;;
*) short; exit 1;;
esac
elif [ $# -eq 0 ]; then
short
exit 1
fi
# main
# release the kraken!
PARALLEL="xargs -P${MAX:=64} -I{}"
if [[ -z "$1" || "$1" == "-" ]]; then
$ACTION -
else
for i in $*; do $ACTION $i; done
fi