diff --git a/README b/README index 2435d3b..fb279fc 100644 --- a/README +++ b/README @@ -6,6 +6,7 @@ daemon. It is licensed under the BSD license. Command line options: -h hostname Change server hostname (FQDN) [$HOSTNAME] -p port Change server port [70] + -T port Change TLS/SSL port [0 = disabled] -r root Change gopher root [/var/gopher] -t type Change default gopher filetype [0] -g mapfile Change gophermap file [gophermap] @@ -251,6 +252,12 @@ address. The below sample stunnel configuration is all you need to TLS-enable your gopher server. Well, you'll need a certificate too and for that I recommend Let's Encrypt. +In addition to configuring Stunnel for TLS you should add -T +to Gophernicus options so that it knows which connetions are coming in +encrypted and which are not. Using proper -T also makes it possible for +CGI programs to use the $TLS environment variable to know whether the +current request was encrypted or not. + ; ; Gophernicus behind Stunnel4 for gopher over TLS diff --git a/file.c b/file.c index dba0ed6..206c6ab 100644 --- a/file.c +++ b/file.c @@ -261,12 +261,14 @@ void caps_txt(state *st, shm_state *shm) "PathKeepPreDelimeter=FALSE" CRLF "ServerSupportsStdinScripts=TRUE" CRLF "ServerDefaultEncoding=%s" CRLF + "ServerTLSPort=%i" CRLF CRLF "ServerSoftware=" SERVER_SOFTWARE CRLF "ServerSoftwareVersion=" VERSION " \"" CODENAME "\"" CRLF "ServerArchitecture=%s" CRLF, st->session_timeout, strcharset(st->out_charset), + st->server_tls_port, st->server_platform); /* Optional keys */ @@ -305,9 +307,16 @@ void setenv_cgi(state *st, char *script) else setenv("SERVER_PROTOCOL", "RFC1436", 1); + if (st->server_port == st->server_tls_port) { + setenv("HTTPS", "on", 1); + setenv("TLS", "on", 1); + } + setenv("SERVER_NAME", st->server_host, 1); snprintf(buf, sizeof(buf), "%i", st->server_port); setenv("SERVER_PORT", buf, 1); + snprintf(buf, sizeof(buf), "%i", st->server_tls_port); + setenv("SERVER_TLS_PORT", buf, 1); setenv("REQUEST_METHOD", "GET", 1); setenv("DOCUMENT_ROOT", st->server_root, 1); setenv("SCRIPT_NAME", st->req_selector, 1); diff --git a/gophernicus.c b/gophernicus.c index 77bf32f..6e53cc8 100644 --- a/gophernicus.c +++ b/gophernicus.c @@ -414,6 +414,7 @@ void init_state(state *st) sstrlcpy(st->server_host, buf); st->server_port = DEFAULT_PORT; + st->server_tls_port = DEFAULT_TLS_PORT; st->default_filetype = DEFAULT_TYPE; sstrlcpy(st->map_file, DEFAULT_MAP); diff --git a/gophernicus.h b/gophernicus.h index f6337ae..b075f7f 100644 --- a/gophernicus.h +++ b/gophernicus.h @@ -195,18 +195,19 @@ size_t strlcat(char *dst, const char *src, size_t siz); #define HTTP_USERAGENT "Unknown gopher client" /* Defaults for settings */ -#define DEFAULT_HOST "localhost" -#define DEFAULT_PORT 70 -#define DEFAULT_TYPE TYPE_TEXT -#define DEFAULT_MAP "gophermap" -#define DEFAULT_TAG "gophertag" -#define DEFAULT_CGI "/cgi-bin/" -#define DEFAULT_USERDIR "public_gopher" -#define DEFAULT_WIDTH 76 -#define DEFAULT_CHARSET US_ASCII -#define MIN_WIDTH 33 -#define MAX_WIDTH 200 -#define UNKNOWN_ADDR "unknown" +#define DEFAULT_HOST "localhost" +#define DEFAULT_PORT 70 +#define DEFAULT_TLS_PORT 0 +#define DEFAULT_TYPE TYPE_TEXT +#define DEFAULT_MAP "gophermap" +#define DEFAULT_TAG "gophertag" +#define DEFAULT_CGI "/cgi-bin/" +#define DEFAULT_USERDIR "public_gopher" +#define DEFAULT_WIDTH 76 +#define DEFAULT_CHARSET US_ASCII +#define MIN_WIDTH 33 +#define MAX_WIDTH 200 +#define UNKNOWN_ADDR "unknown" /* Session defaults */ #define DEFAULT_SESSION_TIMEOUT 1800 @@ -310,6 +311,7 @@ typedef struct { char server_host_default[64]; char server_host[64]; int server_port; + int server_tls_port; char default_filetype; char map_file[64]; diff --git a/options.c b/options.c index 6ef0148..fe9e12a 100644 --- a/options.c +++ b/options.c @@ -97,10 +97,11 @@ void parse_args(state *st, int argc, char *argv[]) int opt; /* Parse args */ - while ((opt = getopt(argc, argv, "h:p:r:t:g:a:c:u:m:l:w:o:s:i:k:f:e:R:D:L:A:P:n:dbv?-")) != ERROR) { + while ((opt = getopt(argc, argv, "h:p:T:r:t:g:a:c:u:m:l:w:o:s:i:k:f:e:R:D:L:A:P:n:dbv?-")) != ERROR) { switch(opt) { case 'h': sstrlcpy(st->server_host, optarg); break; case 'p': st->server_port = atoi(optarg); break; + case 'T': st->server_tls_port = atoi(optarg); break; case 'r': sstrlcpy(st->server_root, optarg); break; case 't': st->default_filetype = *optarg; break; case 'g': sstrlcpy(st->map_file, optarg); break;