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 - HCAPTCHA_SECRET - your hcaptcha secret key
- CAPTCHA_COOKIE_SECRET - random string, a salt for cookies - CAPTCHA_COOKIE_SECRET - random string, a salt for cookies
- POW_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: 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 [libs](src/libs) to a path where Lua looks for modules.
- Copy [ddos-cli](src/cli/ddos-cli) to any convenient path. - 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) - 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 #### CLI
The system comes with CLI. It can be used to manage global and per-domain protection. 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. Command line interface to manage per-domain and global DDoS protection.
optional arguments: optional arguments:
-h, --help Show this help message and exit. -h, --help Show this help message and exit.
Commands: Commands:
Global management: Global management:
ddos-cli global status Show status of global server ddos mode. src/cli/ddos-cli global status Show status of global server ddos mode.
ddos-cli global enable Enable global ddos mode. src/cli/ddos-cli global enable Enable global ddos mode.
ddos-cli global disable Disable global ddos mode. src/cli/ddos-cli global disable Disable global ddos mode.
Domain management: Domain management:
ddos-cli domain list List all domains with ddos mode on. src/cli/ddos-cli domain list List all domains with ddos mode on.
ddos-cli domain status <domain> Get ddos mode status for a domain. src/cli/ddos-cli domain nocaptcha List all domains with nocaptcha mode on.
ddos-cli domain enable <domain> Enable ddos mode for a domain. src/cli/ddos-cli domain status <domain> Get ddos mode status for a domain.
ddos-cli domain disable <domain> Disable ddos mode 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" version: "3.9"
services: services:
tor:
build:
context: ./
dockerfile: tor/Dockerfile
haproxy: haproxy:
build: build:
context: ./ context: ./
dockerfile: haproxy/Dockerfile dockerfile: haproxy/Dockerfile
ports:
- 80:80
volumes: volumes:
- ./haproxy/haproxy.cfg:/etc/haproxy/haproxy.cfg - ./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/scripts/:/etc/haproxy/scripts/
- ./src/libs/:/etc/haproxy/libs/ - ./src/libs/:/etc/haproxy/libs/
- ./haproxy/js/:/var/www/js/
environment: environment:
- HCAPTCHA_SECRET= - HCAPTCHA_SECRET=
- HCAPTCHA_SITEKEY= - HCAPTCHA_SITEKEY=

View File

@@ -1,43 +1,47 @@
global global
daemon daemon
maxconn 256 maxconn 256
log stdout format raw local0 debug log stdout format raw local0 debug
lua-load /etc/haproxy/scripts/register.lua lua-load /etc/haproxy/scripts/register.lua
stats socket /var/run/haproxy.sock mode 666 level admin stats socket /var/run/haproxy.sock mode 666 level admin
defaults defaults
mode http mode http
timeout connect 5000ms timeout connect 5000ms
timeout client 50000ms timeout client 50000ms
timeout server 50000ms timeout server 50000ms
frontend http-in 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_cnt(xr3la1rfFc) eq 0
acl ddos_mode_enabled hdr(host) -i -f /etc/haproxy/ddos.map acl ddos_mode_enabled hdr(host) -i -f /etc/haproxy/ddos.map
#TODO: add ORs here for auto enable on traffic pattern # you can repeat this acl (which ORs them) to add more conditions where ddos_mode_enabled
# 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
# 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 # check proof of work cookie
acl pow_passed var(txn.pow_passed) -m bool 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
http-request use-service lua.hcaptcha-view if on_captcha_url !is_excluded # exclude favicon, and serve script files directly in haproxy
http-request lua.hcaptcha-check if !is_excluded !on_captcha_url ddos_mode_enabled acl on_captcha_url path -m beg /bot-check
http-request lua.pow-check if !is_excluded !on_captcha_url ddos_mode_enabled acl is_favicon path /favicon.ico
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 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
default_backend servers # 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 backend servers
server server1 nginx:80 maxconn 32 server server1 nginx:80 maxconn 32
backend hcaptcha backend hcaptcha
mode http 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