Skip to content

Instantly share code, notes, and snippets.

@marktheunissen
Created July 16, 2020 05:20
Show Gist options
  • Save marktheunissen/197747dfeb44cf583a85fdf546364f8b to your computer and use it in GitHub Desktop.
Save marktheunissen/197747dfeb44cf583a85fdf546364f8b to your computer and use it in GitHub Desktop.
commit 13a26e81a7d5dba116a7f4729ce977569cade34d
Author: Michal Trojnara <[email protected]>
Date: Thu Oct 2 13:09:51 2014 +0200
systemd socket activation
diff --git a/CREDITS b/CREDITS
index 8ece5a7..e649af8 100644
--- a/CREDITS
+++ b/CREDITS
@@ -1,9 +1,35 @@
-Special thx to:
+stunnel code contributions
+
+systemd socket activation in version 5.05:
+Copyright (c) 2014 Mark Theunissen
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+Several bugfixes and improvements:
+* Brian Hatch <[email protected]>
+
+Initial PTY support in version 3.05:
+* Dirk O. Siebnich <[email protected]>
+
+Initial SSL support in versions 1.x:
* Adam Hernik <[email protected]>
* Pawel Krawczyk <[email protected]>
-* Brian Hatch <[email protected]>
-* Dirk O. Siebnich <[email protected]> for PTY support
and many others...
-
diff --git a/ChangeLog b/ChangeLog
index 3c8b991..13b14f7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -4,6 +4,7 @@ Version 5.04, unreleased, urgency: MEDIUM:
* New features
- Asynchronous communication with the GUI thread for faster
logging on Win32.
+ - systemd socket activation (thx to Mark Theunissen).
* Bugfixes
- Fixed POLLIN|POLLHUP condition handling error resulting
in prematurely closed (truncated) connection.
diff --git a/configure b/configure
index 65c7759..2aa1fee 100755
--- a/configure
+++ b/configure
@@ -12266,6 +12266,18 @@ fi
done
+for ac_header in systemd/sd-daemon.h
+do :
+ ac_fn_c_check_header_mongrel "$LINENO" "systemd/sd-daemon.h" "ac_cv_header_systemd_sd_daemon_h" "$ac_includes_default"
+if test "x$ac_cv_header_systemd_sd_daemon_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_SYSTEMD_SD_DAEMON_H 1
+_ACEOF
+
+fi
+
+done
+
ac_fn_c_check_member "$LINENO" "struct msghdr" "msg_control" "ac_cv_member_struct_msghdr_msg_control" "
$ac_includes_default
#include <sys/socket.h>
@@ -12697,6 +12709,63 @@ if test "$ac_res" != no; then :
fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing sd_listen_fds" >&5
+$as_echo_n "checking for library containing sd_listen_fds... " >&6; }
+if ${ac_cv_search_sd_listen_fds+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char sd_listen_fds ();
+int
+main ()
+{
+return sd_listen_fds ();
+ ;
+ return 0;
+}
+_ACEOF
+for ac_lib in '' systemd-daemon; do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_search_sd_listen_fds=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext
+ if ${ac_cv_search_sd_listen_fds+:} false; then :
+ break
+fi
+done
+if ${ac_cv_search_sd_listen_fds+:} false; then :
+
+else
+ ac_cv_search_sd_listen_fds=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_sd_listen_fds" >&5
+$as_echo "$ac_cv_search_sd_listen_fds" >&6; }
+ac_res=$ac_cv_search_sd_listen_fds
+if test "$ac_res" != no; then :
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+fi
+
+
# Add BeOS libraries
if test "$host_os" = "beos"; then
diff --git a/configure.ac b/configure.ac
index 6c4a1cb..4b6a741 100644
--- a/configure.ac
+++ b/configure.ac
@@ -168,6 +168,7 @@ AC_MSG_NOTICE([**************************************** header files])
# AC_HEADER_SYS_WAIT
AC_CHECK_HEADERS([malloc.h ucontext.h pthread.h poll.h tcpd.h stropts.h grp.h unistd.h util.h libutil.h pty.h])
AC_CHECK_HEADERS([sys/types.h sys/select.h sys/poll.h sys/socket.h sys/un.h sys/ioctl.h sys/filio.h sys/resource.h sys/uio.h sys/syscall.h])
+AC_CHECK_HEADERS([systemd/sd-daemon.h])
AC_CHECK_MEMBERS([struct msghdr.msg_control],
[AC_DEFINE([HAVE_MSGHDR_MSG_CONTROL], [1],
[Define to 1 if you have 'msghdr.msg_control' structure.])], [], [
@@ -192,6 +193,8 @@ AC_SEARCH_LIBS([openpty], [util])
AC_SEARCH_LIBS([dlopen], [dl])
AC_SEARCH_LIBS([shl_load], [dld])
AC_SEARCH_LIBS([inflateEnd], [z])
+AC_SEARCH_LIBS([sd_listen_fds], [systemd-daemon])
+
# Add BeOS libraries
if test "$host_os" = "beos"; then
diff --git a/src/common.h b/src/common.h
index 6b15b81..3f3394f 100644
--- a/src/common.h
+++ b/src/common.h
@@ -171,6 +171,11 @@ typedef int socklen_t;
#define USE_LIBWRAP 1
#endif
+/* systemd */
+#ifdef HAVE_SYSTEMD_SD_DAEMON_H
+#include <systemd/sd-daemon.h>
+#endif
+
/* must be included before sys/stat.h for Ultrix */
/* must be included before sys/socket.h for OpenBSD */
#include <sys/types.h> /* u_short, u_long */
diff --git a/src/config.h.in b/src/config.h.in
index ace0015..14f14eb 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -138,6 +138,9 @@
/* Define to 1 if you have the `sysconf' function. */
#undef HAVE_SYSCONF
+/* Define to 1 if you have the <systemd/sd-daemon.h> header file. */
+#undef HAVE_SYSTEMD_SD_DAEMON_H
+
/* Define to 1 if you have the <sys/filio.h> header file. */
#undef HAVE_SYS_FILIO_H
diff --git a/src/stunnel.c b/src/stunnel.c
index 6d283a5..ccbdbb3 100644
--- a/src/stunnel.c
+++ b/src/stunnel.c
@@ -84,10 +84,21 @@ int max_clients=0;
volatile int num_clients=-1;
#endif
s_poll_set *fds; /* file descriptors of listening sockets */
+int systemd_fds; /* number of file descriptors passed by systemd */
+int listen_fds_start; /* base for systemd-provided file descriptors */
/**************************************** startup */
void main_init() { /* one-time initialization */
+#ifdef HAVE_SYSTEMD_SD_DAEMON_H
+ systemd_fds=sd_listen_fds(1);
+ if(systemd_fds<0)
+ fatal("systemd initialization failed");
+ listen_fds_start=SD_LISTEN_FDS_START;
+#else
+ systemd_fds=0; /* no descriptors received */
+ listen_fds_start=3; /* the value is not really important */
+#endif
/* basic initialization contains essential functions required for logging
* subsystem to function properly, thus all errors here are fatal */
if(ssl_init()) /* initialize SSL library */
@@ -338,7 +349,9 @@ void unbind_ports(void) {
for(opt=service_options.next; opt; opt=opt->next) {
s_log(LOG_DEBUG, "Closing service [%s]", opt->servname);
if(opt->option.accept && opt->fd>=0) {
- closesocket(opt->fd);
+ if(opt->fd<listen_fds_start ||
+ opt->fd>=listen_fds_start+systemd_fds)
+ closesocket(opt->fd);
s_log(LOG_DEBUG, "Service [%s] closed (FD=%d)",
opt->servname, opt->fd);
opt->fd=-1;
@@ -376,6 +389,7 @@ void unbind_ports(void) {
int bind_ports(void) {
SERVICE_OPTIONS *opt;
char *local_address;
+ int listening_section;
#ifdef USE_LIBWRAP
/* execute after options_cmdline() to know service_options.next,
@@ -394,12 +408,22 @@ int bind_ports(void) {
if(opt->option.accept)
opt->fd=-1;
+ listening_section=0;
for(opt=service_options.next; opt; opt=opt->next) {
if(opt->option.accept) {
- opt->fd=s_socket(opt->local_addr.sa.sa_family,
- SOCK_STREAM, 0, 1, "accept socket");
- if(opt->fd<0)
- return 1;
+ if(listening_section<systemd_fds) {
+ opt->fd=listen_fds_start+listening_section;
+ s_log(LOG_DEBUG,
+ "Listening file descriptor received from systemd (FD=%d)",
+ opt->fd);
+ } else {
+ opt->fd=s_socket(opt->local_addr.sa.sa_family,
+ SOCK_STREAM, 0, 1, "accept socket");
+ if(opt->fd<0)
+ return 1;
+ s_log(LOG_DEBUG, "Listening file descriptor created (FD=%d)",
+ opt->fd);
+ }
if(set_socket_options(opt->fd, 0)<0) {
closesocket(opt->fd);
opt->fd=-1;
@@ -407,26 +431,30 @@ int bind_ports(void) {
}
/* local socket can't be unnamed */
local_address=s_ntop(&opt->local_addr, addr_len(&opt->local_addr));
- if(bind(opt->fd, &opt->local_addr.sa, addr_len(&opt->local_addr))) {
- s_log(LOG_ERR, "Error binding service [%s] to %s",
- opt->servname, local_address);
- sockerror("bind");
- closesocket(opt->fd);
- opt->fd=-1;
- str_free(local_address);
- return 1;
- }
- if(listen(opt->fd, SOMAXCONN)) {
- sockerror("listen");
- closesocket(opt->fd);
- opt->fd=-1;
- str_free(local_address);
- return 1;
+ /* we don't bind or listen on a socket inherited from systemd */
+ if(listening_section>=systemd_fds) {
+ if(bind(opt->fd, &opt->local_addr.sa, addr_len(&opt->local_addr))) {
+ s_log(LOG_ERR, "Error binding service [%s] to %s",
+ opt->servname, local_address);
+ sockerror("bind");
+ closesocket(opt->fd);
+ opt->fd=-1;
+ str_free(local_address);
+ return 1;
+ }
+ if(listen(opt->fd, SOMAXCONN)) {
+ sockerror("listen");
+ closesocket(opt->fd);
+ opt->fd=-1;
+ str_free(local_address);
+ return 1;
+ }
}
s_poll_add(fds, opt->fd, 1, 0);
s_log(LOG_DEBUG, "Service [%s] (FD=%d) bound to %s",
opt->servname, opt->fd, local_address);
str_free(local_address);
+ ++listening_section;
} else if(opt->option.program && opt->option.remote) {
/* create exec+connect services */
/* FIXME: needs to be delayed on reload with opt->option.retry set */
@@ -434,6 +462,12 @@ int bind_ports(void) {
alloc_client_session(opt, -1, -1), client_thread);
}
}
+ if(listening_section<systemd_fds) {
+ s_log(LOG_ERR,
+ "Too many listening file descriptors received from systemd, got %d",
+ systemd_fds);
+ return 1;
+ }
return 0; /* OK */
}
@@ -591,6 +625,9 @@ void stunnel_info(int level) {
"SELECT"
#endif /* defined(USE_POLL) */
",IPv%c"
+#ifdef HAVE_SYSTEMD_SD_DAEMON_H
+ ",SYSTEMD"
+#endif /* HAVE_SYSTEMD_SD_DAEMON_H */
#if defined HAVE_OSSL_ENGINE_H || defined HAVE_OSSL_OCSP_H || defined USE_FIPS
" SSL:"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment