Initial commit

This commit is contained in:
ltning 2024-04-27 01:49:08 +00:00
commit 66b2b12576
2 changed files with 216 additions and 0 deletions

113
bbs_math.lua Normal file
View file

@ -0,0 +1,113 @@
-- ****************************************************
-- *** Nginx/LUA stream module "CAPTCHA" for Telnet ***
-- ****************************************************
-- Steal the socket to the connecting client
local sock = assert(ngx.req.socket(true))
-- Get ourselves some randomness, use the system time as a rudimentary seed
-- (otherwise we'd be asking the same question every time we restart nginx).
math.randomseed(os.time())
-- Generate the actual math quiz..
local num1 = math.random(2,5)
local num2 = math.random(2,4)
-- ...we should probably know the answer, too..
local ans = num1+num2
-- Use 'ngx.say()' to talk to the connecting client. This function will add
-- a newline ('\n') to the end of each line, but we need to add the carriage
-- return as well, since, well, DOS and Windows and whatnot. Start with a
-- couple blank lines to make sure the text is easy to read.
ngx.say("\r\n\r")
ngx.say("Hello!\r\n\r")
ngx.say("\r")
ngx.say(" ===================================================== \r")
ngx.say(" If you experience trouble, especially with the mail-\r")
ngx.say(" to-sysop, let me know (@ltning@pleroma.anduin.net) or\r")
ngx.say(" ltning AT anduin dot net.\r")
ngx.say(" ===================================================== \r")
ngx.say("\r")
ngx.say("To make sure you're human, please answer this simple question:\r")
ngx.say(" If you have ", num1, " modems, then your friendly but a bit weird aunt\r")
ngx.say(" gives you ", num2, " more, how many BBS nodes can you spin up (assuming\r")
ngx.say(" you have enough serial ports)?\r")
ngx.say("\r")
-- Use 'ngx.print()' this time, as we specifically do *not* want a newline
-- after the prompt..
ngx.print("(Count your modems and hit ENTER): ")
-- Read a single line of data from the client, presumably the answer to our
-- quiz.
-- local data = sock:receive(1)
local data
local reader = sock:receiveuntil("\n")
local _data, err, partial = reader(1)
if err then
ngx.say("failed to read the data stream: ", err)
else
local strval = string.byte(_data)
if strval >= 128 then
local junk, err, partial = reader(5)
if err then
ngx.say("failed to read the data stream: ", err)
end
_data, err, partial = reader(1)
strval = string.byte(_data)
-- ngx.say("first read chunk: [", _data, ",", strval, "]\r")
end
while true do
if not _data then
if err then
ngx.say("failed to read the data stream: ", err)
break
end
-- ngx.say("read done")
break
end
strval = string.byte(_data)
if strval == 13 or strval == 0 then
-- ngx.say("read done")
break
else
ngx.print(_data)
data = _data
end
-- ngx.say("read chunk: [", string.byte(data), ",", strval, "]\r")
_data, err, partial = reader(1)
end
end
-- ngx.say("read the data stream:", s, ", :", data, ":end\r\n" )
-- Pick any consecutive number of digits from the given answer.
-- string.find(): %d+ represents 'digits, one or more'.
-- Wrapping that in (..) captures the first instance into the 'res'
-- variable (the two '_' variables are throwaways).
local _,_,res = string.find(data, "(%d+)")
-- Compare the given answer to our precomputed one. Make sure the answer is
-- cast into a number, otherwise the comparison will fail.
if tonumber(res) == ans then
-- Confirm to the user, then continue to end of script.
ngx.say("\r\n\rYou lucky duck, you! Now step into my office..\r\n\r")
-- Here we're checking if the answer is actually a number, and if it is..
elseif tonumber(res) then
-- ..we gently mock the math skills of our guest.
ngx.say("\r\n\rBLEEP! ", tostring(res), " ?? Try again after brushing up on your maths..\r\n\r")
-- Wait for a few seconds (to slow down bots that hammer us)
ngx.sleep(3)
-- Exit with 403 (which is meaningless here, but the ngx.exit() function
-- needs an exit code)
ngx.exit(403)
-- The answer did not contain a number, so we're assuming it is nonsensical.
else
-- Tell the user to give us a sensible answer next time.
ngx.say("\r\n\rBLEEP! Try entering an actual number next time!\r\n\r")
-- Wait for a few seconds (to slow down bots that hammer us)
ngx.sleep(3)
-- Exit with 403 (which is meaningless here, but the ngx.exit() function
-- needs an exit code)
ngx.exit(403)
end

103
nginx.conf Normal file
View file

@ -0,0 +1,103 @@
# Load the necessary dynamic modules
# This is FreeBSD-specific, and requires the LUA and LUASTREAM build-time
# options for the www/nginx port. Other OSes will have different
# requirements.
# The 'openresty' bundle, available on various Linux distributions, comes
# with all of these modules, and probably won't need these load_module lines.
load_module "/usr/local/libexec/nginx/ndk_http_module.so";
load_module "/usr/local/libexec/nginx/ngx_stream_module.so";
load_module "/usr/local/libexec/nginx/ngx_http_lua_module.so";
load_module "/usr/local/libexec/nginx/ngx_stream_lua_module.so";
# Adjust if you have thousands of nodes...
worker_processes 1;
events {
# Ditto; threads per worker, really don't need much. For reference,
# several (tens of) thousands is common for a busy webserver; clearly
# not our case here.
worker_connections 8;
}
# We use the 'stream' service, which is essentially just a TCP proxy with
# some bells and whistles.
stream {
# Make sure TCP_NODELAY is set; this prevents unnecessary waits in order
# to fill data segments prior to sending. This is an interactive service
# so any delay would make it seem like a slower BBS/phone line than it
# really is :)
tcp_nodelay on;
# Define our upstreams - the BBS nodes/machines themselves. In my case,
# there is only one, since all my BBS nodes live on the same machine. If
# yours are distributed across several machines, add them here.
upstream backend {
# Using a hostname; IP might be preferable. I limit the connection
# count to the number of virtual modems on my OS/2 installation ..
server 192.88.99.15:8023 max_conns=2;
}
# Define our actual listeners, math quiz and all.
server {
# Listen on port 23 (duh); the whole point of this exercise is to be
# able to run a BBS on old hardware, answering on port 23, without
# spending all our time dealing with garbage from the internet.
listen 23;
# The real magic: A block of LUA code which takes over the
# connection before it gets proxied to the BBS nodes.
# See https://anduin.net/~ltning/bbs/bbs_math.lua ..
preread_by_lua_file bbs_math.lua;
# Don't wait too long when we attempt to connect to the BBS. If it
# doesn't want to talk to us (dead?), we drop the connection.
proxy_connect_timeout 10s;
# Set the size of the buffer used for input/output. The default
# (16k) is much too large for our use case. Experiment with this
# when using file transfer protocols with large block sizes.
proxy_buffer_size 1k;
# If there is *no* activity on an established connection (between
# the client and the actual BBS), close the connection after this
# many seconds.
proxy_timeout 600s;
# FOR NEWER Synchronet ONLY:
# Use the PROXY protocol to connect; this will pass the real IP of
# the connecting client to the upstream (BBS). SBBS needs to be
# configured to accept PROXY type inbound connections. Set to
# 'on' to enable this.
proxy_protocol off;
# Assuming we didn't bomb out during the math challenge, we pass the
# connection to "backend" (defined in the "upstream" section above).
proxy_pass backend;
}
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
reset_timedout_connection off;
client_body_timeout 10s;
send_timeout 2s;
lingering_timeout 5s;
client_header_timeout 5s;
keepalive_timeout 65;
server {
listen 443 ssl;
server_name bbs.anduin.net;
ssl_certificate_key /usr/local/etc/ssl/acme/bbs.anduin.net/cert.key;
ssl_certificate /usr/local/etc/ssl/acme/bbs.anduin.net/cert.fullchain;
location / {
allow all;
proxy_pass http://192.88.99.15:80;
}
}
}