Blob


1 #!/bin/sh
3 : "${HTTPBAN_WHITELIST:=127.0.0.1}"
4 : "${HTTPBAN_LIMIT_500:=10}"
5 : "${HTTPBAN_LIMIT_400:=10}"
6 : "${HTTPBAN_LIMIT_300:=10}"
7 : "${HTTPBAN_TABLE:=httpban}"
9 alias log="logger -st http-ban"
10 alias show="doas /sbin/pfctl -t players -T show"
11 alias ban="doas /sbin/pfctl -t players -T add -f-"
12 alias grace="doas /sbin/pfctl -t players -T delete -f-"
14 # Filter functions returning 'count IP' based on HTTP return code
15 IN_300_HOSTS() {
16 awk '$(NF-1) >= 300 && $(NF-1) < 400 { print $2 }' | sort | uniq -c
17 }
19 IN_400_HOSTS() {
20 awk '$(NF-1) >= 400 && $(NF-1) < 500 { print $2 }' | sort | uniq -c
21 }
23 IN_500_HOSTS() {
24 awk '$(NF-1) >= 500 && $(NF-1) < 600 { print $2 }' | sort | uniq -c
25 }
27 # Our local logs
28 access() {
29 doas /bin/cat /var/www/logs/access.log
30 doas /usr/bin/zcat /var/www/logs/access.log.*gz 2>/dev/null
31 }
33 limit() {
34 awk -vtrig="${1:-10}" ' $1 >= trig { print $2 }'
35 }
37 # shellcheck disable=SC2086,SC2046
38 block() {
39 set -- $HTTPBAN_WHITELIST
40 set -- $(for ip; do printf -- '-e %s ' "$ip"; done)
41 {
42 access | IN_500_HOSTS | limit "$HTTPBAN_LIMIT_500"
43 access | IN_400_HOSTS | limit "$HTTPBAN_LIMIT_400"
44 access | IN_300_HOSTS | limit "$HTTPBAN_LIMIT_300"
45 } | sort | uniq | {
46 if test -n "$*"; then grep -v "$@"; else cat; fi
47 }
48 }
50 umask 127
52 block | sort >/tmp/http-ban.new
54 # Diff processing
55 show | sort | awk '{ print $1 }' >/tmp/http-ban.current
56 NEW=$(comm -23 /tmp/http-ban.new /tmp/http-ban.current)
57 GRACE=$(comm -13 /tmp/http-ban.new /tmp/http-ban.current)
59 rm /tmp/http-ban.*
61 test -n "$NEW" -o -n "$GRACE" || exit 0
63 # There's new IP's
64 if test -n "$NEW"; then
65 log Banning new IPs:
66 log <<..
67 $NEW
68 ..
69 ban <<..
70 $NEW
71 ..
72 fi
74 # There's Old IP's not attacking anymore
75 if test -n "$GRACE"; then
76 log Gracing old IPs:
77 log <<..
78 $GRACE
79 ..
81 grace <<..
82 $GRACE
83 ..
84 fi