From 860baccb1e204a84efe32ed4267c18fc2ece8725 Mon Sep 17 00:00:00 2001 From: Mats Erik Andersson Date: Wed, 8 Feb 2012 00:15:45 +0100 Subject: [PATCH] syslogd: Allow use of non-standard ports. --- ChangeLog | 29 +++++++++++++ src/syslogd.c | 94 ++++++++++++++++++++++++++++++++++++++---- tests/ftp-localhost.sh | 5 +++ tests/syslogd.sh | 64 ++++++++++++++++------------ tests/tftp.sh | 5 +++ 5 files changed, 164 insertions(+), 33 deletions(-) diff --git a/ChangeLog b/ChangeLog index 53c4fbfe..aacd4d55 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,32 @@ +2012-02-08 Mats Erik Andersson + + * src/syslogd.c: Implement presetable inet port, defaulting to the + standard port `syslog/udp'. Fall back to `514' if `syslog' fails. + (find_inet_port): New function. + (BindPort): New variable. + [IPPORT_SYSLOG] (portstr): New variable. + (LogPortText): Initialize to NULL. + (LogForwardPort): New variable. + (argp_options, parse_opt): New option `-B/--bind-port'. + (main): New call to `find_inet_port'. + (create_inet_socket): Check that LOGPORTTEXT is non-null, + otherwise inet sockets are left disabled. + [AI_ADDRCONFIG] (fprintflog, cfline): Only AF_UNSPEC invokes + AI_ADDRCONFIG. Replace LOGPORTTEXT by LOGFORWARDPORT in calls + to getaddrinfo. + + * tests/syslogd.sh: Adapt to `syslogd' allowing non-standard ports. + (PORT): Make presetable from command line. + (locate_port): New function. + : Use a pseudo-random port. + : Take a pseudo-random step to an even higher port, only + to disable inet sockets if even that action fails. + [do_inet_socket]: Add `-B$PORT' to IU_OPTIONS and append `:$PORT' + to option `-h' in calls to logger. + + * tests/ftp-localhost.sh, tests/tftp.sh (NSSWITCH): Override + with value `/etc/services' when running OpenBSD. + 2012-02-06 Mats Erik Andersson * doc/inetutils.texi (logger invocation): Describe option `-u/--unix'. diff --git a/src/syslogd.c b/src/syslogd.c index faeebac4..a5b7e0b5 100644 --- a/src/syslogd.c +++ b/src/syslogd.c @@ -251,6 +251,7 @@ int decode (const char *, CODE *); void die (int); void doexit (int); void domark (int); +void find_inet_port (const char *); void fprintlog (struct filed *, const char *, int, const char *); void init (int); void logerror (const char *); @@ -272,6 +273,11 @@ char *LocalHostName; /* Our hostname. */ char *LocalDomain; /* Our local domain name. */ char *BindAddress = NULL; /* Binding address for INET listeners. * The default is a wildcard address. */ +char *BindPort = NULL; /* Optional non-standard port, instead + * of the usual 514/udp. */ +#ifdef IPPORT_SYSLOG +char portstr[8]; /* Fallback port number. */ +#endif char addrstr[INET6_ADDRSTRLEN]; /* Common address presentation. */ char addrname[NI_MAXHOST]; /* Common name lookup. */ int usefamily = AF_INET; /* Address family for INET services. @@ -281,7 +287,8 @@ int finet[2] = {-1, -1}; /* Internet datagram socket fd. */ #define IU_FD_IP4 0 /* Indices for the address families. */ #define IU_FD_IP6 1 int fklog = -1; /* Kernel log device fd. */ -char *LogPortText = "syslog"; /* Service/port for INET connections. */ +char *LogPortText = NULL; /* Service/port for INET connections. */ +char *LogForwardPort = NULL; /* Target port for message forwarding. */ int Initialized; /* True when we are initialized. */ int MarkInterval = 20 * 60; /* Interval between marks in seconds. */ int MarkSeq; /* Mark sequence number. */ @@ -328,6 +335,7 @@ static struct argp_option argp_options[] = { {"ipv6", '6', NULL, 0, "restrict to IPv6 transport", GRP+1}, {"ipany", OPT_IPANY, NULL, 0, "allow transport with IPv4 and IPv6", GRP+1}, {"bind", 'b', "ADDR", 0, "bind listener to this address/name", GRP+1}, + {"bind-port", 'B', "PORT", 0, "bind listener to this port", GRP+1}, {"mark", 'm', "INTVL", 0, "specify timestamp interval in logs (0 for no " "timestamps)", GRP+1}, {"no-detach", 'n', NULL, 0, "do not enter daemon mode", GRP+1}, @@ -400,6 +408,10 @@ parse_opt (int key, char *arg, struct argp_state *state) BindAddress = arg; break; + case 'B': + BindPort = arg; + break; + case 'm': v = strtol (arg, &endptr, 10); if (*endptr) @@ -464,13 +476,16 @@ main (int argc, char *argv[]) set_program_name (argv[0]); - /* Initiliaze PATH_LOG as the first element of the unix sockets array. */ + /* Initialize PATH_LOG as the first element of the unix sockets array. */ add_funix (PATH_LOG); /* Parse command line */ iu_argp_init ("syslogd", default_program_authors); argp_parse (&argp, argc, argv, 0, NULL, NULL); + /* Check desired port, if in demand at all. */ + find_inet_port (BindPort); + /* Daemonise, if not, set the buffering for line buffer. */ if (!NoDetach) { @@ -849,6 +864,12 @@ create_inet_socket (int af, int fd46[2]) /* Invalidate old descriptors. */ fd46[IU_FD_IP4] = fd46[IU_FD_IP6] = -1; + if (!LogPortText) + { + dbg_printf ("No listen port has been accepted.\n"); + return; + } + memset (&hints, 0, sizeof (hints)); hints.ai_family = af; hints.ai_socktype = SOCK_DGRAM; @@ -1300,9 +1321,11 @@ fprintlog (struct filed *f, const char *from, int flags, const char *msg) memset (&hints, 0, sizeof (hints)); hints.ai_family = usefamily; #ifdef AI_ADDRCONFIG - hints.ai_flags = AI_ADDRCONFIG; + if (usefamily == AF_UNSPEC) + hints.ai_flags |= AI_ADDRCONFIG; #endif - err = getaddrinfo (f->f_un.f_forw.f_hname, LogPortText, &hints, &rp); + err = getaddrinfo (f->f_un.f_forw.f_hname, LogForwardPort, + &hints, &rp); if (err) { dbg_printf ("Failure: %s\n", gai_strerror (err)); @@ -1360,7 +1383,7 @@ fprintlog (struct filed *f, const char *from, int flags, const char *msg) hints.ai_socktype = SOCK_DGRAM; hints.ai_flags = AI_PASSIVE; - err = getaddrinfo (NULL, LogPortText, &hints, &rp); + err = getaddrinfo (NULL, LogForwardPort, &hints, &rp); if (err) { dbg_printf ("Not forwarding due to lookup failure: %s.\n", @@ -2067,13 +2090,14 @@ cfline (const char *line, struct filed *f) hints.ai_family = usefamily; hints.ai_socktype = SOCK_DGRAM; #ifdef AI_ADDRCONFIG - hints.ai_flags = AI_ADDRCONFIG; + if (usefamily == AF_UNSPEC) + hints.ai_flags |= AI_ADDRCONFIG; #endif f->f_un.f_forw.f_addrlen = 0; /* Invalidate address. */ memset (&f->f_un.f_forw.f_addr, 0, sizeof (f->f_un.f_forw.f_addr)); - err = getaddrinfo (p, LogPortText, &hints, &rp); + err = getaddrinfo (p, LogForwardPort, &hints, &rp); if (err) { switch (err) @@ -2225,3 +2249,59 @@ trigger_restart (int signo _GL_UNUSED_PARAMETER) { restart = 1; } + +/* Override default port with a non-NULL argument. + * Otherwise identify the default syslog/udp with + * proper fallback to avoid resolve issues. */ +void +find_inet_port (const char *port) +{ + int err; + struct addrinfo hints, *ai; + + /* Fall back to numerical description. */ +#ifdef IPPORT_SYSLOG + snprintf (portstr, sizeof (portstr), "%u", IPPORT_SYSLOG); + LogForwardPort = portstr; +#else + LogForwardPort = "514"; +#endif + + memset (&hints, 0, sizeof (hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_PASSIVE; + + err = getaddrinfo (NULL, "syslog", &hints, &ai); + if (err == 0) + { + LogForwardPort = "syslog"; /* Symbolic name is usable. */ + freeaddrinfo (ai); + } + + LogPortText = (char *) port; + + if (!LogPortText) + { + LogPortText = LogForwardPort; + return; + } + + /* Is the port specified on command line really usable? */ + memset (&hints, 0, sizeof (hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_PASSIVE; + + err = getaddrinfo (NULL, LogPortText, &hints, &ai); + if (err != 0) + { + /* Not usable, disable listener. + * It is too early to report failure at this time. */ + LogPortText = NULL; + } + else + freeaddrinfo (ai); + + return; +} diff --git a/tests/ftp-localhost.sh b/tests/ftp-localhost.sh index ab4cb0bd..f4cd71b5 100755 --- a/tests/ftp-localhost.sh +++ b/tests/ftp-localhost.sh @@ -32,6 +32,8 @@ # # * Accessed by launched Inetd: # /etc/nsswitch.conf, /etc/passwd, /etc/protocols. +# +# OpenBSD uses /etc/services directly, not via /etc/nsswitch.conf. # FIXME: Better test coverage! # @@ -93,6 +95,9 @@ NSSWITCH=/etc/nsswitch.conf PASSWD=/etc/passwd PROTOCOLS=/etc/protocols +# Overrides based on systems. +test `uname -s` = OpenBSD && NSSWITCH=/etc/services + if test ! -r $NSSWITCH || test ! -r $PASSWD \ || test ! -r $PROTOCOLS; then cat <<-EOT >&2 diff --git a/tests/syslogd.sh b/tests/syslogd.sh index 89b487b9..bb4457d3 100755 --- a/tests/syslogd.sh +++ b/tests/syslogd.sh @@ -176,7 +176,19 @@ trap clean_testdir EXIT HUP INT QUIT TERM # Test at this port. # Standard is syslog at 514/udp. PROTO=udp -PORT=514 +PORT=${PORT:-514} + +# locate_port proto port +# +locate_port () { + if [ "`uname -s`" = "SunOS" ]; then + netstat -na -finet -finet6 -P$1 | + grep "\.$2[^0-9]" >/dev/null 2>&1 + else + netstat -na | + grep "^$1\(4\|6\|46\)\{0,1\}.*[^0-9]$2[^0-9]" >/dev/null 2>&1 + fi +} # Receivers for INET sockets. : ${TARGET:=127.0.0.1} @@ -253,31 +265,31 @@ TAG="syslogd-test" # Remove old files in use by daemon. rm -f "$OUT" "$PID" "$CONF" -# Full testing needs a superuser. Report this. -if [ `id -u` -ne 0 ]; then +# Full testing at the standard port needs a superuser. +# Randomise if necessary. +if test `id -u` -ne 0 && test $PORT -le 1023; then cat <<-EOT >&2 - WARNING!! Disabling INET server tests since you seem - to be underprivileged. + WARNING!! The preset port $PORT/$PROTO is not usable, + since you are underprivileged. Now attempting + a randomised higher port. + EOT + PORT=`expr $PORT + 3917 + ${RANDOM:-$$} % 2711` +fi + +# Is the INET port already in use? If so, +# randomise somewhat. +if locate_port $PROTO $PORT; then + echo "Port $PORT/$PROTO is in use. Randomising port somewhat." >&2 + PORT=`expr $PORT + 2711 + ${RANDOM:-$$} % 917` +fi + +# Test a final time. +if locate_port $PROTO $PORT; then + cat <<-EOT >&2 + The INET port $PORT/$PROTO is already in use. + Skipping test of INET socket this time. EOT do_inet_socket=false -else - # Is the INET port already in use? If so, - # skip the test in its entirety. - if [ "`uname -s`" = "SunOS" ]; then - netstat -na -finet -finet6 -P$PROTO | - grep "\.$PORT[^0-9]" >/dev/null 2>&1 - else - netstat -na | - grep "^$PROTO\(4\|6\|46\)\{0,1\}.*[^0-9]$PORT[^0-9]" \ - >/dev/null 2>&1 - fi - if [ $? -eq 0 ]; then - cat <<-EOT >&2 - The INET port $PORT/$PROTO is already in use. - No reliable test of INET socket is possible. - EOT - do_inet_socket=false - fi fi # A minimal, catch-all configuration. @@ -319,7 +331,7 @@ fi ## Enable INET service when possible. if $do_inet_socket; then - IU_OPTIONS="$IU_OPTIONS --ipany --inet --hop" + IU_OPTIONS="$IU_OPTIONS --ipany --inet -B$PORT --hop" fi ## Bring in additional options from command line. ## Disable kernel messages otherwise. @@ -381,9 +393,9 @@ fi if $do_inet_socket; then TESTCASES=`expr $TESTCASES + 2` - $LOGGER -4 -h "$TARGET" -p user.info -t "$TAG" \ + $LOGGER -4 -h "$TARGET:$PORT" -p user.info -t "$TAG" \ "Sending IPv4 message. (pid $$)" - $LOGGER -6 -h "$TARGET6" -p user.info -t "$TAG" \ + $LOGGER -6 -h "$TARGET6:$PORT" -p user.info -t "$TAG" \ "Sending IPv6 message. (pid $$)" fi diff --git a/tests/tftp.sh b/tests/tftp.sh index add33c30..d084e520 100755 --- a/tests/tftp.sh +++ b/tests/tftp.sh @@ -30,6 +30,8 @@ # # * Accessed by launched Inetd: # /etc/nsswitch.conf, /etc/passwd, /etc/protocols. +# +# OpenBSD uses /etc/services directly, not via /etc/nsswitch.conf. # Need job control when spawning Inetd. set -m @@ -82,6 +84,9 @@ NSSWITCH=/etc/nsswitch.conf PASSWD=/etc/passwd PROTOCOLS=/etc/protocols +# Overrides based on systems. +test `uname -s` = OpenBSD && NSSWITCH=/etc/services + if test ! -r $NSSWITCH || test ! -r $PASSWD \ || test ! -r $PROTOCOLS; then cat <<-EOT >&2