Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

close std-filehandles when daemonize #468

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions doc/INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,10 @@ After each run of ./configure, those changes are gone and the Makefile is recrea
There are a couple of configuration options at the beginning of the Makefile:

* `# override undefine HAVE_LANDLOCK` if you uncomment this line, sslh will be compiled
without landlock. As an alternative ./configure creates a config.h file,
which gives also the possibility, to comment that out.
without landlock. This works with gcc versions < 12. Otherwise, if your system has
linux/landlock.h in the include path, the configure script creates a _**config.h**_ file,
which defines HAVE_LANDLOCK. It is not enough, to set this to 0, you must delete it,
when you don't wish to have landlock in your binary.

* `USELIBWRAP` compiles support for host access control (see `hosts_access(3)`),
you will need `libwrap` headers and library to compile (`libwrap0-dev` in Debian).
Expand All @@ -82,6 +84,11 @@ There are a couple of configuration options at the beginning of the Makefile:

* `USELIBBSD` compiles support for updating the process name (as shown by `ps`).

* `USELIBCAP` compiles support for libcap, which allows to inherit capabilities to
daughter-processes, which run as restricted users. You need this, when you wish to
make sure, that the --user= parameter can be used, without setting capabilities etc.
to your binaries, to make this work.

Now you can do either a plain `make` to create the binaries, or you can do an
`make install` to create the binaries and install them.

Expand Down
3 changes: 3 additions & 0 deletions landlock.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ static int add_path_ro(int ruleset_fd, ll_obj_type otype, const char* path)
return -1;
}

// close helper handle
close(fd);

return 0;
}

Expand Down
186 changes: 186 additions & 0 deletions scripts/etc-init.d-sslh-debian-modified.sslh
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
#! /bin/sh
### BEGIN INIT INFO
# Provides: sslh
# Required-Start: $remote_fs $syslog $network
# Required-Stop: $remote_fs $syslog $network
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: ssl/ssh multiplexer
# Description: sslh lets one accept both HTTPS and SSH connections on the
# same port. It makes it possible to connect to an SSH server
# on port 443 (e.g. from inside a corporate firewall) while
# still serving HTTPS on that port.
### END INIT INFO

# Original Author: Guillaume Delacour <gui@iroqwa.org>
# modified and optimized for current sslh-fork

# Do NOT "set -e"

# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="ssl/ssh multiplexer"
NAME=sslh
DAEMON=/usr/sbin/$NAME
DAEMON_OPTS=""
PIDFILE=/var/run/sslh/$NAME.pid
SCRIPTNAME=/etc/init.d/$NAME
RUN=yes


# If you want to use a configuration file, put -F/path/to/sslh.cfg
# into /etc/default/sslh DAEMON_OPTS
# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] && . /etc/default/$NAME



# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh

# Define LSB log_* functions.
# Depend on lsb-base (>= 3.2-14) to ensure that this file is present
# and status_of_proc is working.
. /lib/lsb/init-functions

# Exit if the package is not installed
if [ -x "$DAEMON" ]
then
echo "Can not start \"$DAEMON\", path not available"
log_failure_msg "Can not start \"$DAEMON\", path not available"
fi


#
# Function that starts the daemon/service
#
do_start()
{
# Return
# 0 if daemon has been started
# 1 if daemon was already running
# 2 if daemon could not be started

# Use this if you want the user to explicitly set 'RUN' in
# /etc/default/
if [ "$RUN" != "yes" ]
then
echo "$NAME disabled, please adjust the configuration to your needs "
log_failure_msg "and then set RUN to 'yes' in /etc/default/$NAME to enable it."
return 2
fi

# sslh write the pid as sslh user
if [ ! -d /var/run/sslh/ ]
then
mkdir -p /var/run/sslh
chown sslh:sslh /var/run/sslh
fi

start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \
|| return 1
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \
$DAEMON_OPTS \
|| return 2
# Add code here, if necessary, that waits for the process to be ready
# to handle requests from services started subsequently which depend
# on this one. As a last resort, sleep for some time.
}

#
# Function that stops the daemon/service
#
do_stop()
{
# Return
# 0 if daemon has been stopped
# 1 if daemon was already stopped
# 2 if daemon could not be stopped
# other if a failure occurred
start-stop-daemon --stop --quiet --retry=TERM/45/KILL/5 --pidfile $PIDFILE --name $NAME
RETVAL="$?"
[ "$RETVAL" = 2 ] && return 2
# As long, as the started sslh is sslh-fork, don't kill the still existing
# connections. You may need the following construct for sslh-ev and sslh-select,
# as sslh has currently no function reloading its configuration.

# Wait for children to finish too if this is a daemon that forks
# and if the daemon is only ever run from this initscript.
# If the above conditions are not satisfied then add some other code
# that waits for the process to drop all resources that could be
# needed by services started subsequently. A last resort is to
# sleep for some time.
#start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
#[ "$?" = 2 ] && return 2
# Many daemons don't delete their pidfiles when they exit.
rm -f $PIDFILE
return "$RETVAL"
}

#
# Function that sends a SIGHUP to the daemon/service
# don't activate this, as this kills only the leading process
# of sslh-fork, and the spawned worker stays connected listening.
# After that, the Owner of the PID from PIDFILE is gone, the
# listening connection is still blocked
# sslh can't reload its configuration as of Aug 2024
#do_reload() {
#
# If the daemon can reload its configuration without
# restarting (for example, when it is sent a SIGHUP),
# then implement that here.
#
# start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME
# return 0
#}

case "$1" in
start)
# check if sslh is launched via inetd
if [ -f /etc/inetd.conf ] && [ $(egrep -q "^https.*/usr/sbin/sslh" /etc/inetd.conf|wc -l) -ne 0 ]
then
echo "sslh is started from inetd."
exit 1
fi

log_daemon_msg "Starting $DESC" "$NAME"
do_start
case "$?" in
0|1) log_end_msg 0 ;;
2) log_end_msg 1 ;;
esac
;;
stop)
log_daemon_msg "Stopping $DESC" "$NAME"
do_stop
case "$?" in
0|1) log_end_msg 0 ;;
2) log_end_msg 1 ;;
esac
;;
status)
status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
;;
restart|force-reload)
log_daemon_msg "Restarting $DESC" "$NAME"
do_stop
case "$?" in
0|1)
do_start
case "$?" in
0) log_end_msg 0 ;;
1) log_end_msg 1 ;; # Old process is still running
*) log_end_msg 1 ;; # Failed to start
esac
;;
*)
# Failed to stop
log_end_msg 1
;;
esac
;;
*)
echo "Usage: $SCRIPTNAME {start|stop|status|restart}" >&2
exit 3
;;
esac
2 changes: 1 addition & 1 deletion sslh-fork.c
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ void main_loop(struct listen_endpoint listen_sockets[], int num_addr_listen)
wait(NULL);
}

/* The actual main is in common.c: it's the same for both version of
/* The actual main() is in sslh_main.c: it's the same for all versions of
* the server
*/

14 changes: 14 additions & 0 deletions sslh-main.c
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,20 @@ int main(int argc, char *argv[], char* envp[])

if (!cfg.foreground) {
if (fork() > 0) exit(0); /* Detach */
// close stdin, stderr, stdout
int newfd;
// duplicating a handle connected to /dev/null to stdin, stdout and stderr
// so we don't run in any problems, when a control-job or whats-o-ever will
// grab the those handles.
if ((newfd = open("/dev/null", O_RDWR))) {
dup2 (newfd, STDIN_FILENO);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am curious of why you're doing this. Intuitively I would have simply

close(fileno(stdin));
close(fileno(stdout));
close(fileno(stderr));

(which is how we do it to close stderr when using inetd)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I remembered this construct from Stevens Network Programming, but I have to reread to give more arguments.
Just copied from some older simple programs, I wrote decades ago

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But I bet, the other way is also working.

dup2 (newfd, STDOUT_FILENO);
dup2 (newfd, STDERR_FILENO);
// close the helper handle, as this is now unnecessary
close(newfd);
} else {
print_message(msg_system_error, "Error closing standard filehandles for background daemon\n");
}

/* New session -- become group leader */
if (getuid() == 0) {
Expand Down
2 changes: 1 addition & 1 deletion sslh-select.c
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ void start_shoveler(int listen_socket) {
}


/* The actual main is in common.c: it's the same for both version of
/* The actual main is in sslh-main.c: it's the same for all versions of
* the server
*/

Expand Down
19 changes: 11 additions & 8 deletions sslh.pod
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ B<sslh> accepts connections on specified ports, and forwards
them further based on tests performed on the first data
packet sent by the remote client.

Probes for HTTP, SSL, SSH, OpenVPN, tinc, XMPP are
Probes for HTTP, TLS, SSH, OpenVPN, tinc, XMPP are
implemented, and any other protocol that can be tested using
a regular expression, can be recognised. A typical use case
is to allow serving several services on port 443 (e.g. to
Expand Down Expand Up @@ -102,8 +102,10 @@ clients wait for the server to send its banner.

Makes B<sslh> behave as a transparent proxy, i.e. the
receiving service sees the original client's IP address.
This works on Linux only and involves B<iptables> settings.
Refer to the README for more information.
This works on Linux only and involves B<iproute2> settings.
In some cases also B<iptables/nftables> settings are needed.
Refer to the README or L<https://github.com/ftasnetamot/sslh/blob/2014-08-16--close-filehandles-with-detach/doc/simple_transparent_proxy.md>
for more information.

=item B<-p> I<listening address>, B<--listen> I<listening address>

Expand All @@ -123,10 +125,11 @@ Note that you can set B<sslh> to listen on I<ext_ip:443> and
B<httpd> to listen on I<localhost:443>: this allows clients
inside your network to just connect directly to B<httpd>.

Also, B<sslh> probes for SSLv3 (or TLSv1) handshake and will
Also, B<sslh> probes for TLS handshakes and will
reject connections from clients requesting SSLv2. This is
compliant with RFC6176 which prohibits the usage of SSLv2. If
you wish to accept SSLv2, use B<--anyprot> instead.
compliant with RFC6176 which prohibits the usage of SSLv2.
If you wish to accept SSLv2, use B<--anyprot> instead.


=item B<--ssh> I<target address>

Expand Down Expand Up @@ -234,8 +237,8 @@ detailed explanation of the variables used by B<sslh>.
=head1 SEE ALSO

The latest version is available from
L<http://www.rutschle.net/tech/sslh>, and can be tracked
from L<http://freecode.com/projects/sslh>.
L<https://github.com/yrutschle/sslh>. There you can find a more
detailed and recent documentation.

=head1 AUTHOR

Expand Down
Loading