#!/usr/bin/env stack > -- stack script --resolver nightly-2025-12-01 whoami.lhs: what IP does Venusia think you are? =============================================== A throwaway diagnostic applet. The worry it answers: when an `.lhs` is invoked, `routes.toml` substitutes `$remote_ip` into the argv — but if Venusia is sitting behind `xinetd` (or any other inetd-style super-server) the connection it sees may come from `127.0.0.1`, so `$remote_ip` would echo *localhost* rather than the real visitor. This script doesn't try to be clever. It dumps every positional argument it was handed, numbered, plus the relevant connection environment variables, as gophermap info-lines. Whatever Venusia actually puts in the `$remote_ip` slot shows up verbatim — if it reads `127.0.0.1`, the fear is confirmed. argv layout ----------- `routes.toml`'s `[[files.script_extension]]` for `lhs` runs: run-cached-lhs $file $selector $search $pathinfo $remote_ip `run-cached-lhs` shifts off `$file` (the script path) before exec'ing the compiled binary, so *this* program's argv is: argv[0] = $selector argv[1] = $search argv[2] = $pathinfo argv[3] = $remote_ip <-- the value under suspicion We print them all rather than hard-coding "index 3 is the IP", so the output is self-checking: you can see which slot the address landed in. > import System.Environment (getArgs, lookupEnv) > import System.IO (BufferMode (..), hSetBuffering, stdout) Gophermap helpers. An info-line is item type `i`; the display field is the only one that matters, and it must not contain a tab or CRLF or it'll parse as multiple fields / rows on the wire. We replace any such byte with a space. > sanitize :: String -> String > sanitize = map (\c -> if c `elem` "\t\r\n" then ' ' else c) > infoLine :: String -> IO () > infoLine msg = putStr ("i" <> sanitize msg <> "\t\t\t0\r\n") > main :: IO () > main = do > hSetBuffering stdout NoBuffering > args <- getArgs > -- argv[3] is $remote_ip per routes.toml; guard in case it's absent. > let remoteIp = case drop 3 args of (ip:_) -> ip; [] -> "(no argv[3]!)" > infoLine "whoami.lhs — Venusia connection diagnostic" > infoLine "" > infoLine ("Venusia says your IP is: " <> remoteIp) > infoLine "" > infoLine "--- raw argv (script side, post run-cached-lhs shift) ---" > mapM_ (\(n, a) -> infoLine (" argv[" <> show n <> "] = " <> show a)) > (zip [0 :: Int ..] args) > infoLine "" > infoLine "--- connection environment variables ---" > mapM_ dumpEnv ["REMOTE_ADDR", "REMOTE_HOST", "TCPREMOTEIP", "GOPHER_REMOTE_IP", "SSH_CONNECTION"] > putStr ".\r\n" > dumpEnv :: String -> IO () > dumpEnv k = do > v <- lookupEnv k > infoLine (" " <> k <> " = " <> maybe "(unset)" show v)