This commit is contained in:
Thomas Lynch
2021-11-26 00:27:47 +11:00
parent 7b11645190
commit bec6bddf40
9 changed files with 140 additions and 39 deletions

View File

@ -21,6 +21,7 @@ Add some env vars to docker-compose file:
- HCAPTCHA_SECRET - your hcaptcha secret key
- CAPTCHA_COOKIE_SECRET - random string, a salt for cookies
- POW_COOKIE_SECRET - random string a salt for cookies
- RAY_ID - string to identify the haproxy node by
Run docker compose:
@ -40,6 +41,7 @@ Before installing the tool, ensure that HaProxy is built with Lua support.
- Copy [libs](src/libs) to a path where Lua looks for modules.
- Copy [ddos-cli](src/cli/ddos-cli) to any convenient path.
- Create `/etc/haproxy/domains_under_ddos.txt` with write permissions for HaProxy (feel free to change the map file path, update the HaProxy config correspondingly)
- If you want to try with tor, change the haproxy mount in docker-compose to the haproxy/haproxy.tor.cfg and include your hidden_service folder (with keys, etc) in the tor folder
#### CLI
The system comes with CLI. It can be used to manage global and per-domain protection.
@ -50,18 +52,20 @@ Usage: ddos-cli <command> [options]
Command line interface to manage per-domain and global DDoS protection.
optional arguments:
-h, --help Show this help message and exit.
-h, --help Show this help message and exit.
Commands:
Global management:
ddos-cli global status Show status of global server ddos mode.
ddos-cli global enable Enable global ddos mode.
ddos-cli global disable Disable global ddos mode.
Global management:
src/cli/ddos-cli global status Show status of global server ddos mode.
src/cli/ddos-cli global enable Enable global ddos mode.
src/cli/ddos-cli global disable Disable global ddos mode.
Domain management:
ddos-cli domain list List all domains with ddos mode on.
ddos-cli domain status <domain> Get ddos mode status for a domain.
ddos-cli domain enable <domain> Enable ddos mode for a domain.
ddos-cli domain disable <domain> Disable ddos mode for a domain.
Domain management:
src/cli/ddos-cli domain list List all domains with ddos mode on.
src/cli/ddos-cli domain nocaptcha List all domains with nocaptcha mode on.
src/cli/ddos-cli domain status <domain> Get ddos mode status for a domain.
src/cli/ddos-cli domain enable <domain> Enable ddos mode for a domain.
src/cli/ddos-cli domain disable <domain> Disable ddos mode for a domain.
src/cli/ddos-cli domain mode <domain> Toggle nocaptcha mode for a domain.
```
```

View File

@ -1,15 +1,20 @@
version: "3.9"
services:
tor:
build:
context: ./
dockerfile: tor/Dockerfile
haproxy:
build:
context: ./
dockerfile: haproxy/Dockerfile
ports:
- 80:80
volumes:
- ./haproxy/haproxy.cfg:/etc/haproxy/haproxy.cfg
- ./haproxy/ddos.map:/etc/haproxy/ddos.map
- ./haproxy/no_captcha.map:/etc/haproxy/no_captcha.map
- ./src/scripts/:/etc/haproxy/scripts/
- ./src/libs/:/etc/haproxy/libs/
- ./haproxy/js/:/var/www/js/
environment:
- HCAPTCHA_SECRET=
- HCAPTCHA_SITEKEY=

View File

@ -1,43 +1,47 @@
global
daemon
maxconn 256
log stdout format raw local0 debug
lua-load /etc/haproxy/scripts/register.lua
stats socket /var/run/haproxy.sock mode 666 level admin
daemon
maxconn 256
log stdout format raw local0 debug
lua-load /etc/haproxy/scripts/register.lua
stats socket /var/run/haproxy.sock mode 666 level admin
defaults
mode http
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms
mode http
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms
frontend http-in
bind *:80
bind *:80
# acl for ddos_mode_enabled = global enabled OR domain enabled
acl ddos_mode_enabled hdr_cnt(xr3la1rfFc) eq 0
acl ddos_mode_enabled hdr(host) -i -f /etc/haproxy/ddos.map
#TODO: add ORs here for auto enable on traffic pattern
# check captcha cookie, separate map allows to disable captcha (still keeping POW)
acl captcha_passed var(txn.captcha_passed) -m bool
acl captcha_passed hdr(host),map_str(/etc/haproxy/no_captcha.map) -m found
acl ddos_mode_enabled hdr(host) -i -f /etc/haproxy/ddos.map
# you can repeat this acl (which ORs them) to add more conditions where ddos_mode_enabled
# check captcha cookie
acl captcha_passed var(txn.captcha_passed) -m bool
acl captcha_passed hdr(host),map_str(/etc/haproxy/no_captcha.map) -m found
# check proof of work cookie
acl pow_passed var(txn.pow_passed) -m bool
acl on_captcha_url path -m beg /bot-check
acl is_excluded path_end -i .js .ico
# exclude favicon, and serve script files directly in haproxy
acl on_captcha_url path -m beg /bot-check
acl is_favicon path /favicon.ico
acl is_sha1_js path /js/sha1.js
acl is_worker_js path /js/worker.js
http-request return file /var/www/js/sha1.js status 200 content-type "application/javascript; charset=utf-8" hdr "cache-control" "public, max-age=300" if is_sha1_js
http-request return file /var/www/js/worker.js status 200 content-type "application/javascript; charset=utf-8" hdr "cache-control" "public, max-age=300" if is_worker_js
http-request use-service lua.hcaptcha-view if on_captcha_url !is_excluded
http-request lua.hcaptcha-check if !is_excluded !on_captcha_url ddos_mode_enabled
http-request lua.pow-check if !is_excluded !on_captcha_url ddos_mode_enabled
http-request redirect location /bot-check?%[capture.req.uri] code 302 if !captcha_passed !on_captcha_url ddos_mode_enabled !is_excluded OR !pow_passed !on_captcha_url ddos_mode_enabled !is_excluded
# check pow/captcha and show page if necessary
http-request use-service lua.hcaptcha-view if on_captcha_url !is_favicon
http-request lua.hcaptcha-check if !is_favicon !on_captcha_url ddos_mode_enabled
http-request lua.pow-check if !is_favicon !on_captcha_url ddos_mode_enabled
http-request redirect location /bot-check?%[capture.req.uri] code 302 if !captcha_passed !on_captcha_url ddos_mode_enabled !is_favicon OR !pow_passed !on_captcha_url ddos_mode_enabled !is_favicon
default_backend servers
default_backend servers
backend servers
server server1 nginx:80 maxconn 32
server server1 nginx:80 maxconn 32
backend hcaptcha
mode http

61
haproxy/haproxy.tor.cfg Normal file
View File

@ -0,0 +1,61 @@
global
daemon
maxconn 256
log stdout format raw local0 notice
lua-load /etc/haproxy/scripts/register.lua
stats socket /var/run/haproxy.sock mode 666 level admin
defaults
log global
mode http
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms
frontend tor-proxy
#this can be a unix socket to tor, too but not between separate docker containers
bind *:80 accept-proxy
mode tcp
default_backend strip-tor-proxy
backend strip-tor-proxy
mode tcp
server forward unix@/var/run/haproxy-haproxy.sock check send-proxy
frontend http-in
bind unix@/var/run/haproxy-haproxy.sock accept-proxy
#forwardfor sets the circuit identifier sent by tor daemon in haproxy PROXY protocol header as the x-forwarded-for header
option forwardfor
acl ddos_mode_enabled hdr_cnt(xr3la1rfFc) eq 0
acl ddos_mode_enabled hdr(host) -i -f /etc/haproxy/ddos.map
# you can repeat this acl (which ORs them) to add more conditions where ddos_mode_enabled
# check captcha cookie
acl captcha_passed var(txn.captcha_passed) -m bool
acl captcha_passed hdr(host),map_str(/etc/haproxy/no_captcha.map) -m found
# check proof of work cookie
acl pow_passed var(txn.pow_passed) -m bool
# exclude favicon, and serve script files directly in haproxy
acl on_captcha_url path -m beg /bot-check
acl is_favicon path /favicon.ico
acl is_sha1_js path /js/sha1.js
acl is_worker_js path /js/worker.js
http-request return file /var/www/js/sha1.js status 200 content-type "application/javascript; charset=utf-8" hdr "cache-control" "public, max-age=300" if is_sha1_js
http-request return file /var/www/js/worker.js status 200 content-type "application/javascript; charset=utf-8" hdr "cache-control" "public, max-age=300" if is_worker_js
# check pow/captcha and show page if necessary
http-request use-service lua.hcaptcha-view if on_captcha_url !is_favicon
http-request lua.hcaptcha-check if !is_favicon !on_captcha_url ddos_mode_enabled
http-request lua.pow-check if !is_favicon !on_captcha_url ddos_mode_enabled
http-request redirect location /bot-check?%[capture.req.uri] code 302 if !captcha_passed !on_captcha_url ddos_mode_enabled !is_favicon OR !pow_passed !on_captcha_url ddos_mode_enabled !is_favicon
default_backend servers
backend servers
server server1 nginx:80
backend hcaptcha
server hcaptcha hcaptcha.com:443

11
nginx/index.html Normal file
View File

@ -0,0 +1,11 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>test</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<p>hello, world</p>
</body>
</html>

11
tor/Dockerfile Normal file
View File

@ -0,0 +1,11 @@
FROM alpine:latest
RUN apk update && apk add tor
COPY ./tor/torrc.default /etc/tor/torrc
ADD ./tor/hidden_service/ /var/lib/tor/hidden_service
RUN chmod -R 700 /var/lib/tor/
RUN chmod -R 600 /var/lib/tor/hidden_service/hs_ed25519_secret_key
RUN chown -R tor /var/lib/tor/
RUN chown -R tor /etc/tor
USER tor
ENTRYPOINT [ "tor" ]
CMD [ "-f", "/etc/tor/torrc" ]

5
tor/torrc.default Normal file
View File

@ -0,0 +1,5 @@
Log notice stdout
DataDirectory /var/lib/tor
HiddenServiceDir /var/lib/tor/hidden_service/
HiddenServicePort 80 haproxy:80
HiddenServiceExportCircuitID haproxy