-
Notifications
You must be signed in to change notification settings - Fork 6
/
blackhole
executable file
·132 lines (113 loc) · 4.48 KB
/
blackhole
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
#!/bin/sh
set -e
_allowlist="(10\.0\.0\.0/8|172\.16\.0\.0/12|192\.168\.0\.0/16)"
__usage () {
cat << EOF
$0 [-d] [-a "allowlist"] [-o out]
$0 -h
Create a list of known-bad IPs, both IPv4 and IPv6
o -a "allowlist": regex allowlist (will be filtered out from the input files
and shouldn't land in the output)
Default: $_allowlist (RFC1918)
o -d: enable debug (set -x)
o -o out: specify an output file.
Default: <stdout>
MAKE SURE THAT YOU ARE ALLOWED TO USE THE LISTS IN YOUR SITUATION
EOF
}
while getopts ":a:dho:" _opt; do
case "$_opt" in
a) _allowlist="$OPTARG" ;;
d) set -x ;;
h) __usage; exit 0 ;;
o) _output_file="$OPTARG" ;;
*) __usage >&2 ; exit 1 ;;
esac
done
shift "$((OPTIND-1))"
true() {
:
}
# first choice is curl(1), should be OK for Linux
if command -v curl >/dev/null 2>&1; then
__download () {
curl -Ls --compressed "$1"
}
# second is fetch(1), for FreeBSD
elif command -v fetch >/dev/null 2>&1; then
__download () {
fetch -q -o - "$1"
}
# last comes ftp(1), which does far more than its name implies (OpenBSD only)
elif [ "$(uname -s)" = OpenBSD ] && command -v ftp >/dev/null 2>&1; then
__download () {
ftp -o - "$1"
}
else
printf '%s\n' "Oh no! You don't seem to have curl(1) or fetch(1)" >&2
printf '%s\n' "I'm cowardly exiting" >&2
exit 4
fi
# If we're here, we're actually going to do something
_temp_dir="$(mktemp -d -t "$(basename "$0").XXXXXX")"
_temp="$_temp_dir/badips"
_temp_ack="$_temp_dir/acks"
# This regex matches any valid IPv4, along with its subnet UP TO /11, to avoid
# shooting ourselves in the foot and making a too large part of the big internet
# unavailable. If the subnet is larger, then only match the host part.
ipv4='(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(/(1[1-9]|2[0-9]|3[012]))?'
# For instance:
# % echo '123.123.123.0/24 ; hello' | grep -Eo "$ipv4"
# 123.123.123.0/24
# % echo '123.123.123.0/8 ; no no' | grep -Eo "$ipv4"
# 123.123.123.0
# This regex matches any valid IPv6, along with its subnet UP TO /24
ipv6='(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))(/(2[4-9]|[3-9][0-9]|1[01][0-9]|12[0-8]))?'
__cleanup () {
[ -d "$_temp_dir" ] && rm -fr "$_temp_dir"
}
trap __cleanup INT TERM
__add () {
printf '# Original file at %s (fetched on %s)\n' "$1" "$(date)" >> "$_temp_ack"
__download "$1" >> "$_temp" || true
}
__to_unix () {
# We remove weird characters
tr -d '\r' < "$_temp" |
# We remove the IPs in the allow list (required because some lists include the
# RFC1918 IPs: this makes sense on public-facing IPs, but for some cheap-o
# setups, that public-facing IP is also the administration IP...)
grep -vE "$_allowlist" |
# We filter to only get IPs
grep -Eo "($ipv4|$ipv6)" |
# We sort the file
sort -u > "$_temp".2
# We replace the original file
mv "$_temp".2 "$_temp"
}
__to_output () {
if [ -z "$_output_file" ]; then
cat -
else
if [ -e "$_output_file" ]; then
# just in case something goes wrong
# I wrote that script though. It shouldn't go wrong.
# Right...?
cp "$_output_file" "$_output_file".bak
fi
cat - > "$_output_file"
fi
}
__add "https://www.binarydefense.com/banlist.txt"
__add "https://www.malwaredomainlist.com/hostslist/ip.txt"
__add "https://www.spamhaus.org/drop/drop.lasso"
__add "https://www.spamhaus.org/drop/dropv6.txt"
__add "https://rules.emergingthreats.net/blockrules/compromised-ips.txt"
__add "https://feodotracker.abuse.ch/downloads/ipblocklist_recommended.txt"
__add "https://raw.githubusercontent.com/ktsaou/blocklist-ipsets/master/firehol_level1.netset"
__add "https://rules.emergingthreats.net/fwrules/emerging-Block-IPs.txt"
__add "https://lists.blocklist.de/lists/all.txt"
__to_unix
# We print the acks first
cat "$_temp_ack" "$_temp" | __to_output
__cleanup