From 8cbc34cc274c6d37baba2ce76757d1411430ebee Mon Sep 17 00:00:00 2001 From: jake Date: Mon, 15 Aug 2022 10:35:28 -0400 Subject: Make fork() toggleable. Touch up code that exit() - would end server otherwise. Touch up log entries. --- TO_FIX.md | 2 -- config.toml.sample | 6 +++++ gmi.pl | 67 +++++++++++++++++++++++++++++++++++++----------------- 3 files changed, 52 insertions(+), 23 deletions(-) diff --git a/TO_FIX.md b/TO_FIX.md index 16f30ee..e2998bd 100644 --- a/TO_FIX.md +++ b/TO_FIX.md @@ -13,5 +13,3 @@ make log output user adjustable add client certificate stuff add gmiaccess stuff - -set fork() usage toggleable diff --git a/config.toml.sample b/config.toml.sample index 3552ae3..ca6313f 100644 --- a/config.toml.sample +++ b/config.toml.sample @@ -21,6 +21,10 @@ cert_key_dir = "certs" # avoid putting final '/' # because generating cert/key pairs will fail and cause the program to die. # Setting the following to 'false' will not emit an error. cert_key_dir_write_warning = true +# For each accepted connection a fork() is called. This toggles if that should happen or not. +# For debugging or memory reasons, it may help to set this to false, though it may result in clients timing out if your server is busy serving a client. +# Will cause 'timed-out' and 'sysread failed' to appear at the same time in log files. +fork = true ## These are not specific to default and can be used with vhost ## Vhost options will override default options @@ -43,6 +47,8 @@ default_mime = 'text/plain' # A Vhost is *required* since it both serves as vhost and server name identification (sni) # Vhost example - probably you want to see that it actually works right away +# `$ ncat --ssl localhost 1965'. Quick! You have 5 seconds! type: 'gemini://localhost ' (don't forget the whitespace as required by gemini spec) +# (ncat (probably) packaged with nmap) ['localhost'] # Generate certificate and key automatically? Uses cert_key_dir auto_cert = true diff --git a/gmi.pl b/gmi.pl index 69a87e9..d950d50 100755 --- a/gmi.pl +++ b/gmi.pl @@ -7,7 +7,7 @@ use warnings; use 5.010; #use diagnostics; -our $VERSION = 'v0.0.6'; +our $VERSION = 'v0.0.7'; # Modules use IO::Socket::SSL; # CPAN @@ -15,7 +15,7 @@ use IO::Socket::SSL::Utils; # CPAN use URL::XS qw(parse_url split_url_path parse_url_query); # CPAN #use Term::ANSIColor; # Core use Path::Naive qw(normalize_path); # CPAN -use Smart::Comments; # CPAN +#use Smart::Comments; # CPAN use URI::Encode qw(uri_encode); # CPAN use IO::Select; use TOML qw(from_toml); @@ -50,7 +50,7 @@ our %GEM_RES_CODES = ( our @VALID_DEFAULT_SETTINGS = qw/bind ports tls assume_index dir_listing root working_dir cert_key_dir - log_file log_to_stdout default_mime cert_key_dir_write_warning/; + log_file log_to_stdout default_mime cert_key_dir_write_warning fork/; our @VALID_VHOST_SETTINGS = qw/auto_cert assume_index dir_listing root cert key default_mime/; @@ -275,6 +275,20 @@ for my $vhost (keys %{ $config }) { } } +# fork() toggle +my $fork_toggled = 1; +if (exists $config->{default}{fork}) { + if ($config->{default}{fork} eq 'true') { + $fork_toggled = 1; + } + elsif ($config->{default}{fork} eq 'false') { + $fork_toggled = 0; + } + else { + say STDERR "default: fork value ($config->{default}{fork}) is not true/false. Will assume true."; + } +} + # let the user know if an invalid option was used for my $option (keys %{ $config->{default} }) { my $valid = 0; @@ -312,14 +326,17 @@ say $out "Server Started on ". localtime(); # Main server loop while () { my $cl = $srv->accept() or next; - my $pid = fork(); - if (not defined $pid) { - warn "Cannot make a child: $!"; - next; - } - if ($pid) { - undef $cl; - next; + + if ($fork_toggled) { + my $pid = fork(); + if (not defined $pid) { + warn "Cannot make a child: $!"; + next; + } + if ($pid) { + undef $cl; + next; + } } #close STDIN; @@ -334,14 +351,14 @@ while () { } elsif ($opened == -1) { print $out "IO::Handle opened but the SSL handshake failed.\n"; $cl->close('SHUT_WR'); - exit; + exit if ($fork_toggled); } elsif (! $opened) { print $out "Socket could not be opened.\n"; - exit; + exit if ($fork_toggled); } else { print $out "Something is very wrong.\n"; - exit; + exit if ($fork_toggled); } my $data; @@ -351,17 +368,18 @@ while () { eval { # We do this because 'naughty' people/bots can clog up the ports doing nothing. - local $SIG{ALRM} = sub { + local $SIG{ALRM} = sub { + # cannot goto, we are in a subroutine that gets called when ALRM is triggered. say $out "$clhost - ($cl_sni) timed-out [". localtime(). ']'; $cl->close('SHUT_WR'); - exit; + exit if ($fork_toggled); }; alarm 5; # TODO make magic number not magic. if ( ! sysread($cl, $data, 1024) ) { - $log = "$clhost - ($cl_sni) sysread failed ... Invalid certificate/key?"; + $log = "$clhost - ($cl_sni) sysread failed"; + alarm 0; goto CLOSE; - exit; } alarm 0; @@ -373,13 +391,19 @@ while () { eval { $url = parse_url($data); }; + + # TODO: make user adjustable + $log = "$clhost - ($cl_sni) $data"; + + if (! $url) { + speak($cl, 'bad_request'); + goto CLOSE; + } $path = $url->{path}; ### $data ### $url # ## $path - # TODO: make user adjustable - $log = "$clhost - ($cl_sni) $data"; my $vhost = $url->{host}; my $doc; @@ -471,7 +495,8 @@ while () { CLOSE: $cl->close('SHUT_WR'); print $out "$log [". localtime(). "]\n"; - exit; + + exit if ($fork_toggled); } $srv->close(); -- cgit v1.2.3