Saturday, May 09, 2026 AM03:21:24 HKT
This commit is contained in:
@@ -0,0 +1,358 @@
|
||||
upstream tor {
|
||||
server unix:/run/tor_pass1.sock weight=10 fail_timeout=30s;
|
||||
server unix:/run/tor_pass2.sock weight=10 fail_timeout=30s;
|
||||
keepalive 128;
|
||||
}
|
||||
|
||||
access_by_lua_no_postpone on;
|
||||
lua_package_path "/etc/nginx/resty/?.lua;;";
|
||||
|
||||
init_by_lua_block {
|
||||
allowed_hosts = {
|
||||
"mainonion",
|
||||
"masterbalanceonion",
|
||||
}
|
||||
|
||||
function in_array(tab, val)
|
||||
for index, value in ipairs(tab) do
|
||||
if value == val then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function split(str, sep)
|
||||
local result = {}
|
||||
local regex = ("([^%s]+)"):format(sep)
|
||||
for each in str:gmatch(regex) do
|
||||
table.insert(result, each)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
local function calc_circuit(proxyheaderip)
|
||||
if not proxyheaderip then
|
||||
return
|
||||
end
|
||||
|
||||
local cg = split(proxyheaderip, ":")
|
||||
|
||||
local offset = #cg > 6 and 2 or 0
|
||||
|
||||
local g1 = cg[5 + offset]
|
||||
local g2 = cg[6 + offset]
|
||||
|
||||
local function pad_to_four(val)
|
||||
while string.len(val) < 4 do
|
||||
val = "0" .. val
|
||||
end
|
||||
return val
|
||||
end
|
||||
|
||||
g1 = pad_to_four(g1)
|
||||
g2 = pad_to_four(g2)
|
||||
|
||||
local d1 = (string.sub(g1,1,1) .. string.sub(g1,2,2))
|
||||
local d2 = (string.sub(g1,3,3) .. string.sub(g1,4,4))
|
||||
local d3 = (string.sub(g2,1,1) .. string.sub(g2,2,2))
|
||||
local d4 = (string.sub(g2,3,3) .. string.sub(g2,4,4))
|
||||
local circuit_id = ((((bit.lshift(tonumber(d1, 16), 24)) + (bit.lshift(tonumber(d2, 16), 16))) + (bit.lshift(tonumber(d3, 16), 8))) + tonumber(d4, 16))
|
||||
return circuit_id
|
||||
end
|
||||
|
||||
function kill_circuit(premature, clientip, headerip)
|
||||
local circuitid = calc_circuit(headerip)
|
||||
if not circuitid then
|
||||
return
|
||||
end
|
||||
local sockfile = "unix:/etc/tor/c1"
|
||||
local response = "Closing circuit " .. circuitid .. " "
|
||||
local sock = ngx.socket.tcp()
|
||||
sock:settimeout(1000)
|
||||
local ok, err = sock:connect(sockfile)
|
||||
if not ok then
|
||||
ngx.log(ngx.ERR, "failed to connect to tor: " .. err)
|
||||
return
|
||||
end
|
||||
ngx.log(ngx.ERR, "connected to tor")
|
||||
|
||||
local bytes, err = sock:send("authenticate \"torauthpassword\"\n")
|
||||
if not bytes then
|
||||
ngx.log(ngx.ERR, "failed authenticate to tor: " .. err)
|
||||
return
|
||||
end
|
||||
local data, err, partial = sock:receive()
|
||||
if not data then
|
||||
ngx.log(ngx.ERR, "failed receive data from tor: " .. err)
|
||||
return
|
||||
end
|
||||
local response = response .. " " .. data
|
||||
|
||||
local bytes, err = sock:send("closecircuit " .. circuitid .. "\n")
|
||||
if not bytes then
|
||||
ngx.log(ngx.ERR, "failed send data to tor: " .. err)
|
||||
return
|
||||
end
|
||||
local data, err, partial = sock:receive()
|
||||
if not data then
|
||||
ngx.log(ngx.ERR, "failed receive data from tor: " .. err)
|
||||
return
|
||||
end
|
||||
local response = response .. " " .. data
|
||||
|
||||
ngx.log(ngx.ERR, response)
|
||||
sock:close()
|
||||
return
|
||||
end
|
||||
}
|
||||
|
||||
limit_req_zone $proxy_protocol_addr zone=circuits:50m rate=requestratelimitvaluer/s;
|
||||
limit_req_zone $cookie_dcap zone=capcookie:50m rate=requestratelimitvaluer/s;
|
||||
|
||||
#proxy_cache_path /etc/nginx/cache/ levels=1:2 keys_zone=static:60m use_temp_path=off max_size=500m;
|
||||
|
||||
#this area will kill any request going for port 80 but doesn't have a valid hostname, redirect if the domain is the main or master.
|
||||
server {
|
||||
listen unix:/var/run/nginx1 proxy_protocol bind;
|
||||
allow unix:;
|
||||
deny all;
|
||||
|
||||
server_name _;
|
||||
|
||||
if ($host = "mainonion") {
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
|
||||
if ($host = "masterbalanceonion") {
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
|
||||
location / {
|
||||
access_by_lua_block {
|
||||
local proxyip = "no_proxy"
|
||||
local torip = ngx.var.remote_addr
|
||||
|
||||
if ngx.var.proxy_protocol_addr ~= nil then
|
||||
proxyip = ngx.var.proxy_protocol_addr
|
||||
end
|
||||
|
||||
ngx.log(ngx.ERR, "Bad Host (No SSL) Blocked: " .. ngx.var.host .. ", TorIP: " .. torip .. ", ProxyIP: " .. proxyip)
|
||||
|
||||
local cook = require "resty.cookie"
|
||||
local cookie, err = cook:new()
|
||||
if not cookie then
|
||||
ngx.log(ngx.ERR, "Failed to initialize resty.cookie: ", err)
|
||||
else
|
||||
local field, err = cookie:get("dcap")
|
||||
if field then
|
||||
local blocked_cookies = ngx.shared.blocked_cookies
|
||||
blocked_cookies:set(field, 1, 43200)
|
||||
end
|
||||
end
|
||||
|
||||
if proxyip ~= "no_proxy" then
|
||||
local ok, err = ngx.timer.at(0, kill_circuit, torip, proxyip)
|
||||
if not ok then
|
||||
ngx.log(ngx.ERR, "Failed to create kill_circuit timer: ", err)
|
||||
end
|
||||
end
|
||||
|
||||
-- terminate the connection.
|
||||
return ngx.exit(444)
|
||||
}
|
||||
|
||||
# This return is required by Nginx but it will never be reached
|
||||
return 404;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen unix:/var/run/nginx_ssl1 proxy_protocol ssl bind;
|
||||
http2 on;
|
||||
allow unix:;
|
||||
deny all;
|
||||
|
||||
server_name mainonion
|
||||
masterbalanceonion;
|
||||
|
||||
ssl_certificate /etc/nginx/ssl/$ssl_server_name.crt;
|
||||
ssl_certificate_key /etc/nginx/ssl/$ssl_server_name.key;
|
||||
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384;
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_dhparam /etc/nginx/ssl/dhparams.pem;
|
||||
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
|
||||
|
||||
# proxy_cache_key "$host$request_uri$is_args$args";
|
||||
# proxy_cache_valid 200 1d;
|
||||
# proxy_cache_min_uses 1;
|
||||
# proxy_cache_use_stale error timeout invalid_header http_500 http_502 http_503 http_504;
|
||||
# proxy_ignore_headers X-Accel-Expires Expires Cache-Control;
|
||||
# proxy_set_header Host $host;
|
||||
# proxy_cache_lock on;
|
||||
# proxy_cache_background_update on;
|
||||
# proxy_cache_revalidate on;
|
||||
# proxy_cache_methods GET;
|
||||
|
||||
more_clear_headers 'Server:*';
|
||||
more_clear_headers 'Vary*';
|
||||
more_clear_headers 'kill*';
|
||||
|
||||
location @ratelimit {
|
||||
error_log /var/log/nginx/ratelimit.log;
|
||||
access_by_lua_block {
|
||||
local pa = "no_proxy"
|
||||
if ngx.var.proxy_protocol_addr ~= nil then
|
||||
pa = ngx.var.proxy_protocol_addr
|
||||
end
|
||||
local cook = require "resty.cookie"
|
||||
local cookie, err = cook:new()
|
||||
if not cookie then
|
||||
ngx.log(ngx.ERR, err)
|
||||
return
|
||||
end
|
||||
local field, err = cookie:get("dcap")
|
||||
if field then
|
||||
local blocked_cookies = ngx.shared.blocked_cookies
|
||||
blocked_cookies:set(field, 1, sessionconfigvalue)
|
||||
end
|
||||
|
||||
ngx.log(ngx.ERR, "Rate limited " .. ngx.var.remote_addr .. "|" .. pa)
|
||||
|
||||
if pa ~= "no_proxy" then
|
||||
local ok, err = ngx.timer.at(0, kill_circuit, ngx.var.remote_addr, ngx.var.proxy_protocol_addr)
|
||||
if not ok then
|
||||
ngx.log(ngx.ERR, "failed to create timer: ", err)
|
||||
return
|
||||
end
|
||||
end
|
||||
ngx.exit(444)
|
||||
}
|
||||
}
|
||||
|
||||
location /waf {
|
||||
error_log /var/log/nginx/error.log;
|
||||
default_type text/html;
|
||||
content_by_lua_block {
|
||||
ngx.say("<head><title>Error</title></head>")
|
||||
ngx.say("<body bgcolor=\"white\">")
|
||||
ngx.say("<center><h1>Error</h1></center>")
|
||||
ngx.say("<hr><center><p>Your browser sent a request that this server could not understand.</p></center>")
|
||||
ngx.say("<center><p>Most likely your input contains invalid characters (\" , `, etc.) that except for passwords should not be used.</p></center>")
|
||||
ngx.say("<center><p>This may also happen if you are trying to send contact information or external links.</p></center>")
|
||||
ngx.say("<center><p>Please go back, check your input and try again.</p></center></body>")
|
||||
|
||||
proxyip = "no_proxy"
|
||||
torip = ngx.var.remote_addr
|
||||
if ngx.var.proxy_protocol_addr ~= nil then
|
||||
proxyip = ngx.var.proxy_protocol_addr
|
||||
end
|
||||
|
||||
ngx.log(ngx.ERR, "WAF triggered " .. torip .. "|" .. proxyip)
|
||||
if proxyip ~= "no_proxy" then
|
||||
local ok, err = ngx.timer.at(0, kill_circuit, torip, proxyip)
|
||||
if not ok then
|
||||
ngx.log(ngx.ERR, "failed to create timer: ", err)
|
||||
return
|
||||
end
|
||||
end
|
||||
}
|
||||
}
|
||||
|
||||
location @502 {
|
||||
default_type text/html;
|
||||
content_by_lua_block {
|
||||
ngx.say("<head><title>502 Timeout</title></head>")
|
||||
ngx.say("<body bgcolor=\"white\">")
|
||||
ngx.say("<center><h1>502 Timeout</h1></center>")
|
||||
ngx.say("<hr><center><p>It seems this endgame front doesn't have a stable connection to the backend right now.</p></center>")
|
||||
ngx.say("<center><p>To fix it you can try to reload the page. If that doesn't work, and you end back here, try the following:</p></center>")
|
||||
ngx.say("<center><p>If getting a new circuit doesn't work, Try to get a brand new Tor identity. If that doesn't work come back later.</p></center>")
|
||||
}
|
||||
}
|
||||
|
||||
location /kill {
|
||||
access_by_lua_block {
|
||||
proxyip = "no_proxy"
|
||||
torip = ngx.var.remote_addr
|
||||
if ngx.var.proxy_protocol_addr ~= nil then
|
||||
proxyip = ngx.var.proxy_protocol_addr
|
||||
end
|
||||
|
||||
ngx.log(ngx.ERR, "Kill area visited" .. torip .. "|" .. proxyip)
|
||||
|
||||
local cook = require "resty.cookie"
|
||||
local cookie, err = cook:new()
|
||||
if not cookie then
|
||||
ngx.log(ngx.ERR, err)
|
||||
return
|
||||
end
|
||||
|
||||
local field, err = cookie:get("dcap")
|
||||
if field then
|
||||
local blocked_cookies = ngx.shared.blocked_cookies
|
||||
blocked_cookies:set(field, 1, sessionconfigvalue)
|
||||
end
|
||||
|
||||
if proxyip ~= "no_proxy" then
|
||||
local ok, err = ngx.timer.at(0, kill_circuit, torip, proxyip)
|
||||
if not ok then
|
||||
ngx.log(ngx.ERR, "failed to create timer: ", err)
|
||||
return
|
||||
end
|
||||
end
|
||||
ngx.exit(444)
|
||||
}
|
||||
}
|
||||
|
||||
location / {
|
||||
aio threads;
|
||||
aio_write on;
|
||||
error_log /var/log/nginx/error.log;
|
||||
|
||||
limit_req zone=circuits burst=streamratelimitvalue nodelay;
|
||||
error_page 503 =503 @ratelimit;
|
||||
|
||||
limit_req zone=capcookie burst=streamratelimitvalue nodelay;
|
||||
error_page 503 =503 @ratelimit;
|
||||
error_page 502 =502 @502;
|
||||
|
||||
access_by_lua_file lua/cap.lua;
|
||||
|
||||
SecRulesEnabled;
|
||||
LibInjectionSql;
|
||||
LibInjectionXss;
|
||||
DeniedUrl /waf;
|
||||
CheckRule "$SQL >= 8" BLOCK;
|
||||
CheckRule "$XSS >= 8" BLOCK;
|
||||
CheckRule "$RFI >= 8" BLOCK;
|
||||
CheckRule "$UWA >= 8" BLOCK;
|
||||
CheckRule "$EVADE >= 8" BLOCK;
|
||||
CheckRule "$UPLOAD >= 5" BLOCK;
|
||||
CheckRule "$TRAVERSAL >= 5" BLOCK;
|
||||
CheckRule "$LIBINJECTION_XSS >= 8" BLOCK;
|
||||
CheckRule "$LIBINJECTION_SQL >= 8" BLOCK;
|
||||
include "/etc/nginx/naxsi_whitelist.rules";
|
||||
proxy_set_header Host $host;
|
||||
proxy_pass http://backendurl;
|
||||
header_filter_by_lua_block {
|
||||
local cook = require "resty.cookie"
|
||||
local cookie, err = cook:new()
|
||||
if not cookie then
|
||||
ngx.log(ngx.ERR, err)
|
||||
return
|
||||
end
|
||||
|
||||
if ngx.resp.get_headers()['kill'] ~= nil then
|
||||
local field, err = cookie:get("dcap")
|
||||
if field then
|
||||
local blocked_cookies = ngx.shared.blocked_cookies
|
||||
blocked_cookies:set(field, 1, sessionconfigvalue)
|
||||
end
|
||||
end
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user