From e5937d8ab3f1422db61ea9d29131fc3d06b373c9 Mon Sep 17 00:00:00 2001 From: xiaomlove Date: Thu, 1 May 2025 21:42:31 +0700 Subject: [PATCH] add tracker filter by lua --- .docker/openresty/lua/tracker_filter.lua | 108 ++++++++++++++++++ .docker/openresty/nginx.conf | 95 +++++++++++++++ .docker/openresty/sites/app.conf.template | 20 ++-- .../openresty/sites/phpmyadmin.conf.template | 3 - app/Exceptions/Handler.php | 2 +- docker-compose.yml | 2 + 6 files changed, 218 insertions(+), 12 deletions(-) create mode 100644 .docker/openresty/lua/tracker_filter.lua create mode 100644 .docker/openresty/nginx.conf diff --git a/.docker/openresty/lua/tracker_filter.lua b/.docker/openresty/lua/tracker_filter.lua new file mode 100644 index 00000000..bc463c50 --- /dev/null +++ b/.docker/openresty/lua/tracker_filter.lua @@ -0,0 +1,108 @@ +-- tracker_filter.lua + +-- 简易 BEncode 编码器,只编码 {"failure reason": msg} +local function bencode_error(msg) + local key = "failure reason" + return "d14:" .. key .. string.format("%d:%s", #msg, msg) .. "e" +end + +local function reject(msg) + ngx.status = 400 + ngx.header.content_type = "text/plain" + ngx.say(bencode_error(msg or "Forbidden")) + ngx.exit(ngx.status) +end + +-- 常见浏览器 User-Agent 拒绝 +local common_browsers = { + "Mozilla", "Chrome", "Safari", "Edge", "Firefox", "Opera", "Trident" +} + +local function is_browser(ua) + if not ua then return false end + for _, keyword in ipairs(common_browsers) do + if ua:find(keyword) then + return true + end + end + return false +end + +local function is_valid_passkey(passkey) + return type(passkey) == "string" and #passkey == 32 +end + +local function is_positive_integer(val) + local num = tonumber(val) + return num and num >= 0 and math.floor(num) == num +end + +local function is_valid_port(val) + local port = tonumber(val) + return port and port >= 1 and port <= 65535 and math.floor(port) == port +end + +local function main() + -- 拒绝浏览器 User-Agent + local ua = ngx.var.http_user_agent + if is_browser(ua) then + return reject("Browser access blocked !") + end + + -- 拒绝 URL path 含 api/announce + if ngx.var.uri and ngx.var.uri:find("api/announce") then + return reject("Not support, please use announce.php") + end + + -- 获取 query 参数 + local args = ngx.req.get_uri_args() + + if args["auth_key"] then + return reject("auth_key is not allowed") + end + + if not is_valid_passkey(args["passkey"]) then + return reject("Invalid or missing passkey") + end + + local required_fields = { + "info_hash", + "peer_id", + "port", + "downloaded", + "uploaded", + "left" + } + + for _, field in ipairs(required_fields) do + if not args[field] then + return reject("Missing parameter: " .. field) + end + end + + if not is_valid_port(args["port"]) then + return reject("Invalid port") + end + + for _, field in ipairs({"downloaded", "uploaded", "left"}) do + if not is_positive_integer(args[field]) then + return reject("Invalid value for " .. field) + end + end + + if args["event"] then + local valid_events = { + started = true, + completed = true, + stopped = true, + paused = true + } + if not valid_events[args["event"]] then + return reject("Invalid event") + end + end + + -- 一切 OK,放行 +end + +return main diff --git a/.docker/openresty/nginx.conf b/.docker/openresty/nginx.conf new file mode 100644 index 00000000..247fe106 --- /dev/null +++ b/.docker/openresty/nginx.conf @@ -0,0 +1,95 @@ +# nginx.conf -- docker-openresty +# +# This file is installed to: +# `/usr/local/openresty/nginx/conf/nginx.conf` +# and is the file loaded by nginx at startup, +# unless the user specifies otherwise. +# +# It tracks the upstream OpenResty's `nginx.conf`, but removes the `server` +# section and adds this directive: +# `include /etc/nginx/conf.d/*.conf;` +# +# The `docker-openresty` file `nginx.vh.default.conf` is copied to +# `/etc/nginx/conf.d/default.conf`. It contains the `server section +# of the upstream `nginx.conf`. +# +# See https://github.com/openresty/docker-openresty/blob/master/README.md#nginx-config-files +# + +#user nobody; +#worker_processes 1; + +# Enables the use of JIT for regular expressions to speed-up their processing. +pcre_jit on; + + + +#error_log logs/error.log; +#error_log logs/error.log notice; +#error_log logs/error.log info; + +#pid logs/nginx.pid; + + +events { + worker_connections 1024; +} + + +http { + include mime.types; + default_type application/octet-stream; + + lua_package_path "/usr/local/openresty/lua/?.lua;;"; + + # Enables or disables the use of underscores in client request header fields. + # When the use of underscores is disabled, request header fields whose names contain underscores are marked as invalid and become subject to the ignore_invalid_headers directive. + # underscores_in_headers off; + + log_format main '$remote_addr - $remote_user [$time_iso8601] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for" "$request_body" "$http_cookie" "$request_id" $request_time'; + + error_log /dev/stderr debug; + access_log /dev/stdout main; + + # Log in JSON Format + # log_format nginxlog_json escape=json '{ "timestamp": "$time_iso8601", ' + # '"remote_addr": "$remote_addr", ' + # '"body_bytes_sent": $body_bytes_sent, ' + # '"request_time": $request_time, ' + # '"response_status": $status, ' + # '"request": "$request", ' + # '"request_method": "$request_method", ' + # '"host": "$host",' + # '"upstream_addr": "$upstream_addr",' + # '"http_x_forwarded_for": "$http_x_forwarded_for",' + # '"http_referrer": "$http_referer", ' + # '"http_user_agent": "$http_user_agent", ' + # '"http_version": "$server_protocol", ' + # '"nginx_access": true }'; + # access_log /dev/stdout nginxlog_json; + + # See Move default writable paths to a dedicated directory (#119) + # https://github.com/openresty/docker-openresty/issues/119 + client_body_temp_path /var/run/openresty/nginx-client-body; + proxy_temp_path /var/run/openresty/nginx-proxy; + fastcgi_temp_path /var/run/openresty/nginx-fastcgi; + uwsgi_temp_path /var/run/openresty/nginx-uwsgi; + scgi_temp_path /var/run/openresty/nginx-scgi; + + sendfile on; + #tcp_nopush on; + + #keepalive_timeout 0; + keepalive_timeout 65; + + #gzip on; + + include /etc/nginx/conf.d/*.conf; + + # Don't reveal OpenResty version to clients. + # server_tokens off; +} + +include /etc/nginx/conf.d/*.main; diff --git a/.docker/openresty/sites/app.conf.template b/.docker/openresty/sites/app.conf.template index a2b4a4d5..004036ce 100644 --- a/.docker/openresty/sites/app.conf.template +++ b/.docker/openresty/sites/app.conf.template @@ -14,12 +14,6 @@ server { access_log off; } - location = /robots.txt { - allow all; - log_not_found off; - access_log off; - } - location / { try_files $uri $uri/ /nexus.php?$query_string; } @@ -29,6 +23,18 @@ server { try_files $uri $uri/ /nexus.php$is_args$args; } + location = /announce.php { + access_by_lua_block { + local filter = require("tracker_filter") + filter() + } + fastcgi_pass php:9000; + fastcgi_index index.php; + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param REQUEST_ID $request_id; + } + location ~ \.php$ { fastcgi_pass php:9000; fastcgi_index index.php; @@ -37,6 +43,4 @@ server { fastcgi_param REQUEST_ID $request_id; } - error_log /dev/stderr; - access_log /dev/stdout; } diff --git a/.docker/openresty/sites/phpmyadmin.conf.template b/.docker/openresty/sites/phpmyadmin.conf.template index 211a90af..080c979f 100644 --- a/.docker/openresty/sites/phpmyadmin.conf.template +++ b/.docker/openresty/sites/phpmyadmin.conf.template @@ -11,7 +11,4 @@ server { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } - - error_log /dev/stderr; - access_log /dev/stdout; } diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index 40455824..d4c7e947 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -58,7 +58,7 @@ class Handler extends ExceptionHandler }); //Other Only handle in json request - if (!$request->expectsJson()) { + if (!$request->expectsJson() && !$request->ajax()) { $this->renderable(function (NexusException $e) use ($request) { return redirect(url('/error?error=' . urlencode($e->getMessage()))); }); diff --git a/docker-compose.yml b/docker-compose.yml index 2c17c2dc..466653f9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -67,6 +67,8 @@ services: - ./.docker/openresty/sites:/etc/nginx/conf.d/sites - ./.docker/openresty/certs:/certs - ./.docker/openresty/entrypoint.sh:/usr/local/bin/entrypoint.sh + - ./.docker/openresty/nginx.conf:/usr/local/openresty/nginx/conf/nginx.conf + - ./.docker/openresty/lua:/usr/local/openresty/lua - .:/var/www/html depends_on: - php