diff --git a/.gitignore b/.gitignore index 89fcec6..815c893 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,6 @@ tor/hidden_service/ haproxy/*.pem haproxy/*.crt haproxy/dataplaneapi +src/lua/scripts/tfp.lua +#ignore self-signed cert +certs/* diff --git a/docker-compose.yml b/docker-compose.yml index 9e4c460..e33f19f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -17,6 +17,7 @@ services: - ./src/lua/libs/:/etc/haproxy/libs/ - ./src/js/:/etc/haproxy/js/ - ./src/locales/:/etc/haproxy/locales/ + - ./certs:/etc/haproxy/certs - ../../Documents/dataplaneapi/build/dataplaneapi:/usr/local/bin/dataplaneapi environment: # These are the hcaptcha and recaptcha test keys, not leaking any dont worry :^) diff --git a/haproxy/Dockerfile b/haproxy/Dockerfile index 414905a..fd82ab3 100644 --- a/haproxy/Dockerfile +++ b/haproxy/Dockerfile @@ -18,7 +18,7 @@ RUN set -eux; \ --uid 99 \ haproxy -ENV HAPROXY_URL http://www.haproxy.org/download/3.0/src/snapshot/haproxy-ss-LATEST.tar.gz +ENV HAPROXY_URL http://www.haproxy.org/download/3.1/src/snapshot/haproxy-ss-LATEST.tar.gz ENV DATAPLANEAPI_URL https://github.com/haproxytech/dataplaneapi/releases/download/v2.7.5/dataplaneapi_2.7.5_Linux_x86_64.tar.gz # see https://sources.debian.net/src/haproxy/jessie/debian/rules/ for some helpful navigation of the possible "make" arguments diff --git a/haproxy/haproxy.cfg b/haproxy/haproxy.cfg index fd25145..afe0fe2 100644 --- a/haproxy/haproxy.cfg +++ b/haproxy/haproxy.cfg @@ -6,12 +6,15 @@ global maxconn "${HAPROXY_MAXCONN}" log stdout format raw local0 debug lua-load /etc/haproxy/scripts/register-servers.lua + lua-load-per-thread /etc/haproxy/scripts/tfp.lua lua-load-per-thread /etc/haproxy/scripts/register-bot-check.lua stats socket /var/run/haproxy.sock mode 666 level admin stats socket 127.0.0.1:1999 level admin httpclient.ssl.verify none # Allow larger buffer size for return-file of argon scripts tune.bufsize 51200 + expose-deprecated-directives + tune.ssl.capture-buffer-size 200 defaults log global @@ -51,7 +54,7 @@ frontend http-in # Clearnet http (you'll have to figure out https yourself) bind *:80 - # bind *:443 ssl crt /etc/haproxy/certs/haproxy.pem alpn h3,h2,http/1.1 + bind *:443 ssl crt /etc/haproxy/certs/haproxy.pem alpn h2,http/1.1 # bind quic4@*:443 ssl crt /etc/haproxy/certs/haproxy.pem # http-response set-header alt-svc "h3=\":443\";ma=900;" @@ -59,9 +62,12 @@ frontend http-in # bind 127.0.0.1:80 accept-proxy option forwardfor + # tfp lua dev test + http-request lua.set_tfp + # custom log format - log-format "{\"cc\":%{+Q}[capture.req.hdr(1)],\"cip\":\"%ci\",\"cp\":\"%cp\",\"hh\":%{+Q}[capture.req.hdr(0)],\"backend\":\"%b\",\"server\":\"%s\",\"timers\":\"%TR/%Tw/%Tc/%Tr/%Ta\",\"status\":\"%ST\",\"bytes\":\"%B\",\"bs\":\"%U\",\"conns\":\"%ac/%fc/%bc/%sc/%rc\",\"q\":\"%sq/%bq\",\"req\":%{+Q,+E}r,\"GeoIP_Source\":\"GeoIP_Source=%ci\"}" - + log-format "{\"cc\":%{+Q}[capture.req.hdr(1)],\"tp\":%{+Q}[var(txn.fp_custom)],\"cip\":\"%ci\",\"cp\":\"%cp\",\"hh\":%{+Q}[capture.req.hdr(0)],\"backend\":\"%b\",\"server\":\"%s\",\"timers\":\"%TR/%Tw/%Tc/%Tr/%Ta\",\"status\":\"%ST\",\"bytes\":\"%B\",\"bs\":\"%U\",\"conns\":\"%ac/%fc/%bc/%sc/%rc\",\"q\":\"%sq/%bq\",\"req\":%{+Q,+E}r,\"GeoIP_Source\":\"GeoIP_Source=%ci\"}" + # optional geoip handling (maps required) and alt-svc header addition http-request set-var(req.xcc) src,map_ip(/etc/haproxy/map/geoip.map) http-request set-var(req.asn) src,map_ip(/etc/haproxy/map/iptoasn.map) @@ -169,7 +175,7 @@ backend haproxy-to-varnish-cache backend servers balance roundrobin - default-server ssl verify required ca-file ca-certificates.crt sni req.hdr(Host) check observe layer4 inter 30 + default-server ssl verify required ca-file ca-certificates.crt sni req.hdr(Host) check observe layer4 inter 30s use-server %[lua.get_server_names] if TRUE backend bot_check_post_throttle diff --git a/haproxy/map/bfp.map b/haproxy/map/bfp.map new file mode 100644 index 0000000..792d600 --- /dev/null +++ b/haproxy/map/bfp.map @@ -0,0 +1 @@ +# diff --git a/haproxy/map/ddos.map b/haproxy/map/ddos.map index e69de29..7e7b8fa 100644 --- a/haproxy/map/ddos.map +++ b/haproxy/map/ddos.map @@ -0,0 +1 @@ +localhost {"m":0,"t":false} diff --git a/haproxy/map/ddos_config.map b/haproxy/map/ddos_config.map index 2fb1853..cdae63c 100644 --- a/haproxy/map/ddos_config.map +++ b/haproxy/map/ddos_config.map @@ -1 +1 @@ -localhost {"pd":27,"pt":"sha256","cex":999,"cip":false,"js":true} +localhost {"pd":21,"pt":"sha256","cex":999,"cip":true,"js":true} diff --git a/haproxy/map/lfp.map b/haproxy/map/lfp.map new file mode 100644 index 0000000..792d600 --- /dev/null +++ b/haproxy/map/lfp.map @@ -0,0 +1 @@ +# diff --git a/src/lua/scripts/bot-check.lua b/src/lua/scripts/bot-check.lua index 5cbff84..1664f29 100644 --- a/src/lua/scripts/bot-check.lua +++ b/src/lua/scripts/bot-check.lua @@ -52,6 +52,7 @@ local pow_cookie_secret = os.getenv("POW_COOKIE_SECRET") local hmac_cookie_secret = os.getenv("HMAC_COOKIE_SECRET") local ray_id = os.getenv("RAY_ID") -- load captcha map and set hcaptcha/recaptch based off env vars +local bfp_map = Map.new("/etc/haproxy/map/bfp.map", Map._str); local ddos_map = Map.new("/etc/haproxy/map/ddos.map", Map._str); local captcha_provider_domain = "" local captcha_siteverify_path = "" @@ -156,7 +157,9 @@ function _M.view(applet) local ddos_map_lookup = ddos_map:lookup(host .. path) or ddos_map:lookup(host) if ddos_map_lookup ~= nil then local ddos_map_json = json.decode(ddos_map_lookup) - if ddos_map_json.m == 2 then + local fp = applet:get_var("txn.fp_custom") + local bfp_map_lookup = bfp_map:lookup(fp) + if ddos_map_json.m == 2 or bfp_map_lookup ~= nil then captcha_enabled = true end end @@ -476,6 +479,13 @@ function _M.decide_checks_necessary(txn) local path = txn.sf:path(); local ddos_map_lookup = ddos_map:lookup(host .. path) or ddos_map:lookup(host) if ddos_map_lookup ~= nil then + local fp = txn:get_var("txn.fp_custom") + local bfp_map_lookup = bfp_map:lookup(fp) + if bfp_map_lookup ~= nil then + txn:set_var("txn.validate_pow", true) + txn:set_var("txn.validate_captcha", true) + return + end local ddos_map_json = json.decode(ddos_map_lookup) if ddos_map_json.m == 0 or (ddos_map_json.t == true and txn.sf:hdr("X-Country-Code") ~= "T1") then @@ -486,6 +496,7 @@ function _M.decide_checks_necessary(txn) txn:set_var("txn.validate_captcha", true) end end + end -- no entry in the map end diff --git a/src/lua/scripts/tfp.lua b/src/lua/scripts/tfp.lua new file mode 100644 index 0000000..57dd450 --- /dev/null +++ b/src/lua/scripts/tfp.lua @@ -0,0 +1,5 @@ +function set_tfp_var(txn) + txn:set_var('txn.fp_custom', 'changeme') +end + +core.register_action('set_tfp', {'tcp-req', 'http-req'}, set_tfp_var)