Initial commit
This commit is contained in:
commit
66b2b12576
2 changed files with 216 additions and 0 deletions
113
bbs_math.lua
Normal file
113
bbs_math.lua
Normal 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
103
nginx.conf
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue