├── rscreen ├── autossh.host ├── sourcecraft.yaml ├── autossh.spec ├── Makefile.in ├── daemon.h ├── configure.ac ├── fakepoll.h ├── config.h.in ├── CHANGES ├── INSTALL ├── README ├── autossh.1 └── autossh.c /rscreen: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # sample script to use autossh to open up a remote screen 4 | # session, or reconnect to an existing one. 5 | # 6 | # $Id: rscreen,v 1.4 2002/05/07 17:54:13 harding Exp $ 7 | # 8 | if [ "X$1" = "X" ]; then 9 | echo "usage: `basename $0` " 10 | exit 1 11 | fi 12 | 13 | if [ "X$SSH_AUTH_SOCK" = "X" ]; then 14 | eval `ssh-agent -s` 15 | ssh-add $HOME/.ssh/id_rsa 16 | fi 17 | 18 | #AUTOSSH_POLL=600 19 | #AUTOSSH_PORT=20000 20 | #AUTOSSH_GATETIME=30 21 | #AUTOSSH_LOGFILE=$HOST.log 22 | #AUTOSSH_DEBUG=yes 23 | #AUTOSSH_PATH=/usr/local/bin/ssh 24 | export AUTOSSH_POLL AUTOSSH_LOGFILE AUTOSSH_DEBUG AUTOSSH_PATH AUTOSSH_GATETIME AUTOSSH_PORT 25 | 26 | autossh -M 20004 -t $1 "screen -e^Zz -D -R" 27 | -------------------------------------------------------------------------------- /autossh.host: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Example script to start up tunnel with autossh. 4 | # 5 | # This script will tunnel 2200 from the remote host 6 | # to 22 on the local host. On remote host do: 7 | # ssh -p 2200 localhost 8 | # 9 | # $Id: autossh.host,v 1.6 2004/01/24 05:53:09 harding Exp $ 10 | # 11 | 12 | ID=username 13 | HOST=hostname.your.net 14 | 15 | if [ "X$SSH_AUTH_SOCK" = "X" ]; then 16 | eval `ssh-agent -s` 17 | ssh-add $HOME/.ssh/id_rsa 18 | fi 19 | 20 | #AUTOSSH_POLL=600 21 | #AUTOSSH_PORT=20000 22 | #AUTOSSH_GATETIME=30 23 | #AUTOSSH_LOGFILE=$HOST.log 24 | #AUTOSSH_DEBUG=yes 25 | #AUTOSSH_PATH=/usr/local/bin/ssh 26 | export AUTOSSH_POLL AUTOSSH_LOGFILE AUTOSSH_DEBUG AUTOSSH_PATH AUTOSSH_GATETIME AUTOSSH_PORT 27 | 28 | autossh -2 -fN -M 20000 -R 2200:localhost:22 ${ID}@${HOST} 29 | -------------------------------------------------------------------------------- /sourcecraft.yaml: -------------------------------------------------------------------------------- 1 | # This file configures Sourcecraft. 2 | 3 | # (Required) 4 | # The source package name, no spaces 5 | # FIXME: add proper documentation link for sourcecraft 6 | # See https://juju.is/docs/sdk/naming#heading--naming-charms for guidance. 7 | name: dariuszd-autossh14 8 | 9 | # (Required) 10 | # The source package version 11 | version: git 12 | 13 | # (Required) 14 | # Version of the build base OS 15 | base: ubuntu@24.04 16 | 17 | # (Recommended) 18 | title: Sourcecraft Template Package 19 | 20 | # (Required) 21 | summary: A very short one-line summary of the package. 22 | 23 | # (Required) 24 | description: | 25 | A single sentence that says what the source is, concisely and memorably. 26 | 27 | A paragraph of one to three short sentences, that describe what the package does. 28 | 29 | A third paragraph that explains what need the package meets. 30 | 31 | Finally, a paragraph that describes whom the package is useful for. 32 | 33 | # (Required) 34 | # Platforms that package targets 35 | platforms: 36 | amd64: 37 | 38 | parts: 39 | dariuszd-autossh14: 40 | # See 'sourcecraft plugins' 41 | plugin: autotools 42 | autotools-configure-parameters: 43 | - --prefix=/usr 44 | source: . 45 | -------------------------------------------------------------------------------- /autossh.spec: -------------------------------------------------------------------------------- 1 | Summary: Automatically restart SSH sessions and tunnels 2 | Name: autossh 3 | Version: 1.4b 4 | Release: 1 5 | License: Distributable 6 | Group: Applications/Networking 7 | Vendor: Carson Harding 8 | URL: http://www.harding.motd.ca/autossh/ 9 | Source0: %{name}-%{version}.tgz 10 | BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot 11 | 12 | %description 13 | autossh is a program to start a copy of ssh and monitor it, restarting 14 | it as necessary should it die or stop passing traffic. 15 | 16 | %prep 17 | %setup -q 18 | 19 | %build 20 | %configure 21 | 22 | %{__make} 23 | 24 | %install 25 | rm -rf $RPM_BUILD_ROOT 26 | install -d $RPM_BUILD_ROOT{%{_bindir},%{_mandir}/man1} 27 | 28 | install autossh $RPM_BUILD_ROOT%{_bindir} 29 | install autossh.1 $RPM_BUILD_ROOT%{_mandir}/man1 30 | 31 | %clean 32 | rm -rf $RPM_BUILD_ROOT 33 | 34 | %files 35 | %defattr(644,root,root,755) 36 | %doc README CHANGES autossh.host rscreen 37 | %attr(755,root,root) %{_bindir}/* 38 | %{_mandir}/man1/* 39 | 40 | %changelog 41 | * Fri Mar 28 2008 Carson Harding 42 | - update to 1.4b 43 | 44 | * Sat May 20 2006 Carson Harding 45 | - update to 1.4 and use autoconf 46 | 47 | * Wed Feb 02 2005 Carson Harding 48 | - very minor changes to spec file 49 | 50 | * Thu Oct 21 2004 Ron Yorston 1.3-1 51 | - Original version 52 | -------------------------------------------------------------------------------- /Makefile.in: -------------------------------------------------------------------------------- 1 | # $Id: Makefile.in,v 1.9 2019/01/05 01:24:52 harding Exp $ 2 | # 3 | # @configure_input@ 4 | 5 | VER= 1.4g 6 | 7 | SSH= @path_ssh@ 8 | 9 | prefix= @prefix@ 10 | exec_prefix= @exec_prefix@ 11 | bindir= @bindir@ 12 | datadir= @datadir@ 13 | datarootdir= @datarootdir@ 14 | mandir= @mandir@ 15 | 16 | SRCDIR= @srcdir@ 17 | VPATH= @srcdir@ 18 | 19 | CC= @CC@ 20 | CFLAGS= @CFLAGS@ -DVER=\"$(VER)\" -DSSH_PATH=\"$(SSH)\" 21 | CPPFLAGS= @CPPFLAGS@ 22 | 23 | OFILES= autossh.o 24 | 25 | LD= @LD@ 26 | LDFLAGS= @LDFLAGS@ 27 | LIBS= @LIBS@ 28 | 29 | TARGET= autossh 30 | 31 | all: $(TARGET) 32 | 33 | 34 | $(TARGET): $(OFILES) 35 | $(CC) $(CPPFLAGS) $(LDFLAGS) -o $(TARGET) $(OFILES) $(LIBS) 36 | 37 | clean: 38 | - /bin/rm -f *.o *.a *.core *~ 39 | 40 | allclean: clean 41 | - /bin/rm -f $(TARGET) 42 | 43 | distclean: allclean 44 | - /bin/rm -f config.log config.cache config.status config.h 45 | - /bin/rm -rf autom4te.cache 46 | - /bin/rm -f Makefile 47 | 48 | install: $(TARGET) 49 | mkdir -p -m 755 $(DESTDIR)$(bindir) 50 | mkdir -p -m 755 $(DESTDIR)$(prefix)/share/doc/autossh 51 | mkdir -p -m 755 $(DESTDIR)$(datadir)/examples/autossh 52 | mkdir -p -m 755 $(DESTDIR)$(mandir)/man1 53 | cp $(TARGET) $(DESTDIR)$(bindir) 54 | cp CHANGES README $(DESTDIR)$(datadir)/doc/autossh 55 | cp autossh.host $(DESTDIR)$(datadir)/examples/autossh 56 | cp rscreen $(DESTDIR)$(datadir)/examples/autossh 57 | cp autossh.1 $(DESTDIR)$(mandir)/man1 58 | chmod 755 $(DESTDIR)$(bindir)/$(TARGET) 59 | chmod 644 $(DESTDIR)$(datadir)/doc/autossh/CHANGES 60 | chmod 644 $(DESTDIR)$(datadir)/doc/autossh/README 61 | chmod 644 $(DESTDIR)$(datadir)/examples/autossh/autossh.host 62 | chmod 644 $(DESTDIR)$(datadir)/examples/autossh/rscreen 63 | chmod 644 $(DESTDIR)$(mandir)/man1/autossh.1 64 | -------------------------------------------------------------------------------- /daemon.h: -------------------------------------------------------------------------------- 1 | /* 2 | * this is BSD's daemon() for things that don't have it; cut from OpenBSD 3 | * $Id: daemon.h,v 1.5 2006/05/21 03:33:01 harding Exp $ 4 | */ 5 | 6 | /*- 7 | * Copyright (c) 1990, 1993 8 | * The Regents of the University of California. All rights reserved. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions 12 | * are met: 13 | * 1. Redistributions of source code must retain the above copyright 14 | * notice, this list of conditions and the following disclaimer. 15 | * 2. Redistributions in binary form must reproduce the above copyright 16 | * notice, this list of conditions and the following disclaimer in the 17 | * documentation and/or other materials provided with the distribution. 18 | * 3. All advertising materials mentioning features or use of this software 19 | * must display the following acknowledgement: 20 | * This product includes software developed by the University of 21 | * California, Berkeley and its contributors. 22 | * 4. Neither the name of the University nor the names of its contributors 23 | * may be used to endorse or promote products derived from this software 24 | * without specific prior written permission. 25 | * 26 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 | * SUCH DAMAGE. 37 | */ 38 | 39 | #if !defined(HAVE_DAEMON) 40 | 41 | #if defined(LIBC_SCCS) && !defined(lint) 42 | static char rcsid[] = "$OpenBSD: daemon.c,v 1.2 1996/08/19 08:22:13 tholo Exp $"; 43 | #endif /* LIBC_SCCS and not lint */ 44 | 45 | int daemon(int nochdir, int noclose); 46 | 47 | int 48 | daemon(int nochdir, int noclose) 49 | { 50 | int fd; 51 | 52 | switch (fork()) { 53 | case -1: 54 | return -1; 55 | case 0: 56 | break; 57 | default: 58 | _exit(0); 59 | } 60 | 61 | if (setsid() == -1) 62 | return -1; 63 | 64 | if (!nochdir) 65 | (void)chdir("/"); 66 | 67 | if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { 68 | (void)dup2(fd, STDIN_FILENO); 69 | (void)dup2(fd, STDOUT_FILENO); 70 | (void)dup2(fd, STDERR_FILENO); 71 | if (fd > 2) 72 | (void)close (fd); 73 | } 74 | return 0; 75 | } 76 | #endif 77 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # -*- Autoconf -*- 2 | # Process this file with autoconf to produce a configure script. 3 | 4 | AC_PREREQ(2.59) 5 | AC_INIT(autossh, 1.4, [Carson Harding ]) 6 | AC_REVISION($Revision: 1.2 $) 7 | AC_CONFIG_SRCDIR([daemon.h]) 8 | AC_CONFIG_HEADER([config.h]) 9 | AC_CONFIG_FILES([Makefile]) 10 | 11 | # Checks for programs. 12 | AC_PROG_CC 13 | # Add -Wall for gcc 14 | if test "$ac_compiler_gnu" = "yes"; then 15 | CFLAGS="$CFLAGS -Wall" 16 | fi 17 | 18 | AC_ARG_WITH(ssh, 19 | AC_HELP_STRING([--with-ssh=ARG], [specify path to ssh executable]), 20 | [ac_cv_path_ssh=$withval], [] 21 | ) 22 | if test -z "$ac_cv_path_ssh"; then 23 | AC_PATH_PROG([ssh], [ssh]) 24 | fi 25 | if test -n "$ac_cv_path_ssh"; then 26 | AC_DEFINE_UNQUOTED( 27 | PATH_SSH, "$ac_cv_path_ssh", 28 | [Set this to the path to your ssh program.] 29 | ) 30 | else 31 | AC_MSG_ERROR([ssh program not found! Modify PATH, or use --with-ssh.]) 32 | fi 33 | path_ssh="$ac_cv_path_ssh" 34 | AC_SUBST(path_ssh) 35 | 36 | # Checks for libraries. 37 | 38 | # Checks for header files. 39 | AC_HEADER_STDC 40 | AC_HEADER_SYS_WAIT 41 | AC_CHECK_HEADERS([arpa/inet.h fcntl.h limits.h netdb.h]) 42 | AC_CHECK_HEADERS([netinet/in.h paths.h stdlib.h string.h sys/socket.h]) 43 | AC_CHECK_HEADERS([sys/time.h syslog.h unistd.h]) 44 | 45 | 46 | # Checks for typedefs, structures, and compiler characteristics. 47 | AC_C_CONST 48 | AC_C_INLINE 49 | AC_TYPE_SIZE_T 50 | AC_HEADER_TIME 51 | AC_STRUCT_TM 52 | AC_C_VOLATILE 53 | AC_CHECK_TYPE(socklen_t, 54 | AC_DEFINE(HAVE_SOCKLEN_T, 1, [Define to 1 if you have socklen_t.]), 55 | [], 56 | [ 57 | #ifdef HAVE_SYS_TYPES_H 58 | # include 59 | #endif 60 | #ifdef HAVE_SYS_SOCKET_H 61 | # include 62 | #endif 63 | #ifdef HAVE_ARPA_INET_H 64 | # include 65 | #endif 66 | ] 67 | ) 68 | AC_CHECK_TYPE([struct addrinfo], 69 | AC_DEFINE(HAVE_ADDRINFO, 1, [Define to 1 if you have struct addrinfo.]), 70 | [], 71 | [ 72 | #ifdef HAVE_NETDB_H 73 | # include 74 | #endif 75 | ] 76 | ) 77 | AC_CHECK_TYPE(u_int16_t, 78 | AC_DEFINE(HAVE_U_INT16_T, 1, [Define to 1 if you have u_int16_t.]), 79 | [], [ 80 | #ifdef HAVE_SYS_TYPES_H 81 | # include 82 | #endif 83 | ] 84 | ) 85 | AC_CHECK_TYPE(uint16_t, 86 | AC_DEFINE(HAVE_UINT16_T, 1, [Define to 1 if you have uint16_t.]), 87 | [], 88 | [ 89 | #ifdef HAVE_SYS_TYPES_H 90 | # include 91 | #endif 92 | ] 93 | ) 94 | AC_CHECK_DECL(LOG_PERROR, 95 | AC_DEFINE(HAVE_LOG_PERROR, 1, [Define to 1 if you have LOG_PERROR.]), 96 | [], 97 | [ 98 | #ifdef HAVE_SYSLOG_H 99 | # include 100 | #endif 101 | ] 102 | ) 103 | 104 | 105 | # Checks for library functions. 106 | AC_FUNC_FORK 107 | AC_FUNC_MALLOC 108 | AC_FUNC_REALLOC 109 | AC_FUNC_SELECT_ARGTYPES 110 | AC_FUNC_STRFTIME 111 | AC_FUNC_VPRINTF 112 | AC_CHECK_FUNCS([alarm daemon dup2 gethostbyname gettimeofday memmove]) 113 | AC_CHECK_FUNCS([memset poll select setproctitle socket strchr strerror]) 114 | AC_CHECK_FUNCS([strncasecmp strtoul uname vsyslog]) 115 | 116 | AC_CHECK_LIB(nsl, gethostbyname) 117 | AC_CHECK_LIB(socket, connect) 118 | 119 | # Other checks 120 | 121 | # Copyright (c) 1999-2004 Damien Miller 122 | # 123 | # Permission to use, copy, modify, and distribute this software for any 124 | # purpose with or without fee is hereby granted, provided that the above 125 | # copyright notice and this permission notice appear in all copies. 126 | # 127 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 128 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 129 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 130 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 131 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 132 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 133 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 134 | AC_CACHE_CHECK([if libc defines __progname], ac_cv_libc_defines___progname, [ 135 | AC_TRY_LINK([], 136 | [ extern char *__progname; printf("%s", __progname); ], 137 | [ ac_cv_libc_defines___progname="yes" ], 138 | [ ac_cv_libc_defines___progname="no" ] 139 | ) 140 | ]) 141 | if test "x$ac_cv_libc_defines___progname" = "xyes" ; then 142 | AC_DEFINE(HAVE___PROGNAME, 1, [Define if libc defines __progname]) 143 | fi 144 | 145 | AC_OUTPUT 146 | -------------------------------------------------------------------------------- /fakepoll.h: -------------------------------------------------------------------------------- 1 | /* fakepoll.h 2 | * poll using select 3 | * 4 | * Warning: a call to this poll() takes about 4K of stack space. 5 | * Greg Parker gparker-web@sealiesoftware.com December 2000 6 | * This code is in the public domain and may be copied or modified without 7 | * permission. 8 | * 9 | * Updated May 2002: 10 | * * fix crash when an fd is less than 0 11 | * * set errno=EINVAL if an fd is greater or equal to FD_SETSIZE 12 | * * don't set POLLIN or POLLOUT in revents if it wasn't requested 13 | * in events (only happens when an fd is in the poll set twice) 14 | * 15 | * Updated Dec 2002: 16 | * * change comment style (for autossh, Carson Harding) 17 | * * undef FD_SETSIZE first 18 | */ 19 | 20 | #ifndef _FAKE_POLL_H 21 | #define _FAKE_POLL_H 22 | 23 | #include 24 | #undef FD_SETSIZE 25 | #define FD_SETSIZE OPEN_MAX 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | typedef struct pollfd { 32 | int fd; /* file desc to poll */ 33 | short events; /* events of interest on fd */ 34 | short revents; /* events that occurred on fd */ 35 | } pollfd_t; 36 | 37 | 38 | /* poll flags */ 39 | #define POLLIN 0x0001 40 | #define POLLOUT 0x0004 41 | #define POLLERR 0x0008 42 | 43 | /* synonyms */ 44 | #define POLLNORM POLLIN 45 | #define POLLPRI POLLIN 46 | #define POLLRDNORM POLLIN 47 | #define POLLRDBAND POLLIN 48 | #define POLLWRNORM POLLOUT 49 | #define POLLWRBAND POLLOUT 50 | 51 | /* ignored */ 52 | #define POLLHUP 0x0010 53 | #define POLLNVAL 0x0020 54 | 55 | inline int poll(struct pollfd *pollSet, int pollCount, int pollTimeout) 56 | { 57 | struct timeval tv; 58 | struct timeval *tvp; 59 | fd_set readFDs, writeFDs, exceptFDs; 60 | fd_set *readp, *writep, *exceptp; 61 | struct pollfd *pollEnd, *p; 62 | int selected; 63 | int result; 64 | int maxFD; 65 | 66 | if (!pollSet) { 67 | pollEnd = NULL; 68 | readp = NULL; 69 | writep = NULL; 70 | exceptp = NULL; 71 | maxFD = 0; 72 | } 73 | else { 74 | pollEnd = pollSet + pollCount; 75 | readp = &readFDs; 76 | writep = &writeFDs; 77 | exceptp = &exceptFDs; 78 | 79 | FD_ZERO(readp); 80 | FD_ZERO(writep); 81 | FD_ZERO(exceptp); 82 | 83 | /* Find the biggest fd in the poll set */ 84 | maxFD = 0; 85 | for (p = pollSet; p < pollEnd; p++) { 86 | if (p->fd > maxFD) maxFD = p->fd; 87 | } 88 | 89 | if (maxFD >= FD_SETSIZE) { 90 | /* At least one fd is too big */ 91 | errno = EINVAL; 92 | return -1; 93 | } 94 | 95 | /* Transcribe flags from the poll set to the fd sets */ 96 | for (p = pollSet; p < pollEnd; p++) { 97 | if (p->fd < 0) { 98 | /* Negative fd checks nothing and always reports zero */ 99 | } else { 100 | if (p->events & POLLIN) FD_SET(p->fd, readp); 101 | if (p->events & POLLOUT) FD_SET(p->fd, writep); 102 | if (p->events != 0) FD_SET(p->fd, exceptp); 103 | /* POLLERR is never set coming in; poll() always reports errors 104 | * But don't report if we're not listening to anything at all. 105 | */ 106 | } 107 | } 108 | } 109 | 110 | /* poll timeout is in milliseconds. Convert to struct timeval. 111 | * poll timeout == -1 : wait forever : select timeout of NULL 112 | * poll timeout == 0 : return immediately : select timeout of zero 113 | */ 114 | if (pollTimeout >= 0) { 115 | tv.tv_sec = pollTimeout / 1000; 116 | tv.tv_usec = (pollTimeout % 1000) * 1000; 117 | tvp = &tv; 118 | } else { 119 | tvp = NULL; 120 | } 121 | 122 | 123 | selected = select(maxFD+1, readp, writep, exceptp, tvp); 124 | 125 | 126 | if (selected < 0) { 127 | /* Error during select */ 128 | result = -1; 129 | } 130 | else if (selected > 0) { 131 | /* Select found something 132 | * Transcribe result from fd sets to poll set. 133 | * Also count the number of selected fds. poll returns the 134 | * number of ready fds; select returns the number of bits set. 135 | */ 136 | int polled = 0; 137 | for (p = pollSet; p < pollEnd; p++) { 138 | p->revents = 0; 139 | if (p->fd < 0) { 140 | /* Negative fd always reports zero */ 141 | } else { 142 | if ((p->events & POLLIN) && FD_ISSET(p->fd, readp)) { 143 | p->revents |= POLLIN; 144 | } 145 | if ((p->events & POLLOUT) && FD_ISSET(p->fd, writep)) { 146 | p->revents |= POLLOUT; 147 | } 148 | if ((p->events != 0) && FD_ISSET(p->fd, exceptp)) { 149 | p->revents |= POLLERR; 150 | } 151 | 152 | if (p->revents) polled++; 153 | } 154 | } 155 | result = polled; 156 | } 157 | else { 158 | /* selected == 0, select timed out before anything happened 159 | * Clear all result bits and return zero. 160 | */ 161 | for (p = pollSet; p < pollEnd; p++) { 162 | p->revents = 0; 163 | } 164 | result = 0; 165 | } 166 | 167 | return result; 168 | } 169 | 170 | 171 | #endif 172 | -------------------------------------------------------------------------------- /config.h.in: -------------------------------------------------------------------------------- 1 | /* config.h.in. Generated from configure.ac by autoheader. */ 2 | 3 | /* Define to 1 if you have struct addrinfo. */ 4 | #undef HAVE_ADDRINFO 5 | 6 | /* Define to 1 if you have the `alarm' function. */ 7 | #undef HAVE_ALARM 8 | 9 | /* Define to 1 if you have the header file. */ 10 | #undef HAVE_ARPA_INET_H 11 | 12 | /* Define to 1 if you have the `daemon' function. */ 13 | #undef HAVE_DAEMON 14 | 15 | /* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ 16 | #undef HAVE_DOPRNT 17 | 18 | /* Define to 1 if you have the `dup2' function. */ 19 | #undef HAVE_DUP2 20 | 21 | /* Define to 1 if you have the header file. */ 22 | #undef HAVE_FCNTL_H 23 | 24 | /* Define to 1 if you have the `fork' function. */ 25 | #undef HAVE_FORK 26 | 27 | /* Define to 1 if you have the `gethostbyname' function. */ 28 | #undef HAVE_GETHOSTBYNAME 29 | 30 | /* Define to 1 if you have the `gettimeofday' function. */ 31 | #undef HAVE_GETTIMEOFDAY 32 | 33 | /* Define to 1 if you have the header file. */ 34 | #undef HAVE_INTTYPES_H 35 | 36 | /* Define to 1 if you have the `nsl' library (-lnsl). */ 37 | #undef HAVE_LIBNSL 38 | 39 | /* Define to 1 if you have the `socket' library (-lsocket). */ 40 | #undef HAVE_LIBSOCKET 41 | 42 | /* Define to 1 if you have the header file. */ 43 | #undef HAVE_LIMITS_H 44 | 45 | /* Define to 1 if you have LOG_PERROR. */ 46 | #undef HAVE_LOG_PERROR 47 | 48 | /* Define to 1 if your system has a GNU libc compatible `malloc' function, and 49 | to 0 otherwise. */ 50 | #undef HAVE_MALLOC 51 | 52 | /* Define to 1 if you have the `memmove' function. */ 53 | #undef HAVE_MEMMOVE 54 | 55 | /* Define to 1 if you have the header file. */ 56 | #undef HAVE_MEMORY_H 57 | 58 | /* Define to 1 if you have the `memset' function. */ 59 | #undef HAVE_MEMSET 60 | 61 | /* Define to 1 if you have the header file. */ 62 | #undef HAVE_NETDB_H 63 | 64 | /* Define to 1 if you have the header file. */ 65 | #undef HAVE_NETINET_IN_H 66 | 67 | /* Define to 1 if you have the header file. */ 68 | #undef HAVE_PATHS_H 69 | 70 | /* Define to 1 if you have the `poll' function. */ 71 | #undef HAVE_POLL 72 | 73 | /* Define to 1 if your system has a GNU libc compatible `realloc' function, 74 | and to 0 otherwise. */ 75 | #undef HAVE_REALLOC 76 | 77 | /* Define to 1 if you have the `select' function. */ 78 | #undef HAVE_SELECT 79 | 80 | /* Define to 1 if you have the `setproctitle' function. */ 81 | #undef HAVE_SETPROCTITLE 82 | 83 | /* Define to 1 if you have the `socket' function. */ 84 | #undef HAVE_SOCKET 85 | 86 | /* Define to 1 if you have socklen_t. */ 87 | #undef HAVE_SOCKLEN_T 88 | 89 | /* Define to 1 if you have the header file. */ 90 | #undef HAVE_STDINT_H 91 | 92 | /* Define to 1 if you have the header file. */ 93 | #undef HAVE_STDLIB_H 94 | 95 | /* Define to 1 if you have the `strchr' function. */ 96 | #undef HAVE_STRCHR 97 | 98 | /* Define to 1 if you have the `strerror' function. */ 99 | #undef HAVE_STRERROR 100 | 101 | /* Define to 1 if you have the `strftime' function. */ 102 | #undef HAVE_STRFTIME 103 | 104 | /* Define to 1 if you have the header file. */ 105 | #undef HAVE_STRINGS_H 106 | 107 | /* Define to 1 if you have the header file. */ 108 | #undef HAVE_STRING_H 109 | 110 | /* Define to 1 if you have the `strncasecmp' function. */ 111 | #undef HAVE_STRNCASECMP 112 | 113 | /* Define to 1 if you have the `strtoul' function. */ 114 | #undef HAVE_STRTOUL 115 | 116 | /* Define to 1 if you have the header file. */ 117 | #undef HAVE_SYSLOG_H 118 | 119 | /* Define to 1 if you have the header file. */ 120 | #undef HAVE_SYS_SELECT_H 121 | 122 | /* Define to 1 if you have the header file. */ 123 | #undef HAVE_SYS_SOCKET_H 124 | 125 | /* Define to 1 if you have the header file. */ 126 | #undef HAVE_SYS_STAT_H 127 | 128 | /* Define to 1 if you have the header file. */ 129 | #undef HAVE_SYS_TIME_H 130 | 131 | /* Define to 1 if you have the header file. */ 132 | #undef HAVE_SYS_TYPES_H 133 | 134 | /* Define to 1 if you have that is POSIX.1 compatible. */ 135 | #undef HAVE_SYS_WAIT_H 136 | 137 | /* Define to 1 if you have uint16_t. */ 138 | #undef HAVE_UINT16_T 139 | 140 | /* Define to 1 if you have the `uname' function. */ 141 | #undef HAVE_UNAME 142 | 143 | /* Define to 1 if you have the header file. */ 144 | #undef HAVE_UNISTD_H 145 | 146 | /* Define to 1 if you have u_int16_t. */ 147 | #undef HAVE_U_INT16_T 148 | 149 | /* Define to 1 if you have the `vfork' function. */ 150 | #undef HAVE_VFORK 151 | 152 | /* Define to 1 if you have the header file. */ 153 | #undef HAVE_VFORK_H 154 | 155 | /* Define to 1 if you have the `vprintf' function. */ 156 | #undef HAVE_VPRINTF 157 | 158 | /* Define to 1 if you have the `vsyslog' function. */ 159 | #undef HAVE_VSYSLOG 160 | 161 | /* Define to 1 if `fork' works. */ 162 | #undef HAVE_WORKING_FORK 163 | 164 | /* Define to 1 if `vfork' works. */ 165 | #undef HAVE_WORKING_VFORK 166 | 167 | /* Define to 1 if you __progname is available. */ 168 | #undef HAVE___PROGNAME 169 | 170 | /* Define to the address where bug reports for this package should be sent. */ 171 | #undef PACKAGE_BUGREPORT 172 | 173 | /* Define to the full name of this package. */ 174 | #undef PACKAGE_NAME 175 | 176 | /* Define to the full name and version of this package. */ 177 | #undef PACKAGE_STRING 178 | 179 | /* Define to the one symbol short name of this package. */ 180 | #undef PACKAGE_TARNAME 181 | 182 | /* Define to the version of this package. */ 183 | #undef PACKAGE_VERSION 184 | 185 | /* Set this to the path to your ssh program. */ 186 | #undef PATH_SSH 187 | 188 | /* Define to the type of arg 1 for `select'. */ 189 | #undef SELECT_TYPE_ARG1 190 | 191 | /* Define to the type of args 2, 3 and 4 for `select'. */ 192 | #undef SELECT_TYPE_ARG234 193 | 194 | /* Define to the type of arg 5 for `select'. */ 195 | #undef SELECT_TYPE_ARG5 196 | 197 | /* Define to 1 if you have the ANSI C header files. */ 198 | #undef STDC_HEADERS 199 | 200 | /* Define to 1 if you can safely include both and . */ 201 | #undef TIME_WITH_SYS_TIME 202 | 203 | /* Define to 1 if your declares `struct tm'. */ 204 | #undef TM_IN_SYS_TIME 205 | 206 | /* Define to empty if `const' does not conform to ANSI C. */ 207 | #undef const 208 | 209 | /* Define to `__inline__' or `__inline' if that's what the C compiler 210 | calls it, or to nothing if 'inline' is not supported under any name. */ 211 | #ifndef __cplusplus 212 | #undef inline 213 | #endif 214 | 215 | /* Define to rpl_malloc if the replacement function should be used. */ 216 | #undef malloc 217 | 218 | /* Define to `int' if does not define. */ 219 | #undef pid_t 220 | 221 | /* Define to rpl_realloc if the replacement function should be used. */ 222 | #undef realloc 223 | 224 | /* Define to `unsigned' if does not define. */ 225 | #undef size_t 226 | 227 | /* Define as `fork' if `vfork' does not work. */ 228 | #undef vfork 229 | 230 | /* Define to empty if the keyword `volatile' does not work. Warning: valid 231 | code using `volatile' can become incorrect without. Disable with care. */ 232 | #undef volatile 233 | -------------------------------------------------------------------------------- /CHANGES: -------------------------------------------------------------------------------- 1 | 2 | Version 1.4g 3 | - Make sure to clear alarm handler when interrupted by signal 4 | (diagnosed by and patch from Jeff Forys). In retrospect this 5 | issue was reported by a number of people. 6 | - Note -M as optional in README, to match usage output and man page. 7 | (Vladimir Panteleev) 8 | - Add -J to SSH option string (Matt Stancliff) 9 | - Typo "then"->"than" and add datarootdir to Makefile.in 10 | (Stig-??rjan Smelror) 11 | - More correct checking that we have a monitor port and remote 12 | host. (Vladimir D. Seleznev) 13 | 14 | Version 1.4f 15 | - Change behaviour when ssh child exits on signal. Previously 16 | if SIGHUP, SIGTERM, or SIGKILL were used, autossh assumed that 17 | it also was meant to exit. But it is possible that ssh was 18 | killed because it had hung up or was unresponsive for some 19 | reason. Restarting it is probably the better course. 20 | - Fix order of arguments to kill(). Bug reported by Dapeng Gao. 21 | - Ignore SIGPIPE. Issue noted and debugged by Rick van der Zwet. 22 | - Note use of ExitOnForwardFailure and ClientAliveInterval in 23 | README and man page (Till Maas). 24 | - Should accept the default -1 with AUTOSSH_MAXSTART. Reported by 25 | Daniel Hahler. 26 | - Restart ssh when ssh exits with 2, which it can do if 27 | setting up tunnel fails due to race with remote end 28 | tearing down. (Daniel Sutcliffe). 29 | - Daniel Hahler and Jindrich Makovich both reported that signals 30 | will have no effect if before ssh started (sleeping in gatetime, 31 | etc.) Signal handling is now set just just before monitoring the 32 | child, and unset just after. 33 | - Makefile should use LDFLAGS (Waldemar Brodkorb). 34 | - memset() sigaction structure before use. 35 | 36 | Version 1.4e 37 | - By default, changing the poll time should change the first poll 38 | time to match. Only have different times if AUTOSSH_FIRST_POLL 39 | is explicitly set. Jerry Xie forwarded on change request from 40 | Ubuntu bug forums. 41 | 42 | Version 1.4d 43 | 44 | - call daemon() before opening any sockets. Problem discovered and 45 | diagnosed by Frank van der Aa when trying to start autossh at 46 | system init. 47 | - don't use malloc(n * size) idiom; use calloc() 48 | 49 | Version 1.4c 50 | 51 | - updated option string up to OpenSSH 5.6 52 | - when using -f, set gate_time to 0; the assumption is that 53 | it is being used for infrastructure (i.e. in a system startup), 54 | has been tested, and bombing out just because the remote end is 55 | not up is not the desired behaviour. 56 | - add patch from Thorsten Glaser for configure, fixes misplaced 57 | parenthesis and check for __progname. 58 | 59 | Version 1.4b 60 | 61 | - add AUTOSSH_MAXLIFETIME (patch from Steven Clark) 62 | - include configure.ac in package 63 | - fix poll flags so not checking for writable when write done (patch 64 | from John Grahor) 65 | - compile time TOUCH_PIDFILE option to touch pid file on connection test. 66 | 67 | Version 1.4a 68 | 69 | - fix up pid file generation (Xander Hudson) 70 | - fix up Makefile.in (Andrew Schulman) 71 | 72 | Version 1.4 73 | 74 | - initialise ep in main() to avoid warning (Marcelo Goes) 75 | - fix where cast to int happens when calculating next time to poll 76 | connection (Omer Erdem Demir) 77 | - fix '--' use so can pass -M to autossh for session multiplexing 78 | - fix use of strcpy for overlapping copy in strip_arg (Filippo Giunchedi). 79 | - add basic GNU autoconf support and drop per-platform Makefiles (Andre Lucas) 80 | - pid file support (Ben Vitale) 81 | - arbitrary messages in echo string (Ron Yorston) 82 | 83 | Version 1.3 84 | 85 | - fix AUTOSSH_DEBUG for Solaris and AIX 86 | - fix attempt to free() static storage (affected platforms without 87 | getaddrinfo() -- mostly cygwin) (Andrew Schulman) 88 | - change test and placement of typedef for socklen_t under OS X; new 89 | OS X defines it 90 | - add ability to signal autossh to kill and restart ssh child, using 91 | SIGUSR1 92 | - add hostname to monitor message (Ron Yorston) 93 | - check on looping on poll() where connection has been lost (spinning 94 | and high CPU) 95 | - fix bug where length argument to accept() was not initialised 96 | - fix arg parsing bug where stripping -f from arguments would strip 97 | from a parameter to the argument: e.g -L8808:foo:80 would become 98 | -L8808:oo:80 (pointed out by Eric Larson) 99 | - pull out r/w loops in conn_test() into separate functions, makes 100 | logic more apparent 101 | - add echo port support: have the remote server use the inetd 102 | echo service to echo our test string back to us. Or use some other 103 | echo service. Idea and patch from Ron Yorston. This makes it 1.3. 104 | - remove bad strcpy() (left over from some testing?) thanks to Ron 105 | Yorston, change to memset read buffer to all zeros 106 | - fix ssh args when AUTOSSH_PORT=0 is used to turn monitor loop off 107 | (Karl Berry) 108 | - add more descriptive usage output, by popular request 109 | 110 | Version 1.2g 111 | 112 | - add AUTOSSH_NTSERVICE (Andrew Schulman) 113 | - fix bad calculation for seconds left in poll time (again from 114 | Andrew Schulman) 115 | - from Andrew Schulman: add support for older networking and cygwin 116 | - add AUTOSSH_MAXSTART (from Hugo Haas) 117 | - loop around waitpid() in ssh_kill() in case interrupted (thanks to 118 | Jens Krabbenhoeft) 119 | - update ssh argument string 120 | - move openlog above port error checking 121 | - handle environment variables and -M arg being set to the 122 | empty string (reported by Dan Christensen via Filippo Giunche) 123 | - add some rudimetary auto-adjust to the network timeouts for 124 | low poll times. So by default 15secs on each of accept() and 125 | poll()to deal with high-latency connections, but as poll time 126 | falls below 30secs, then adjust timeouts down as well. 127 | - adjust division in grace_time() to allow for low poll time 128 | - don't call shutdown() and close() on invalid socket () 129 | (found by Dmitry V. Levin) 130 | 131 | Version 1.2f 132 | 133 | - by popular request, support the -f flag by doing the fork/background 134 | ourselves, and not passing the flag to ssh (thanks to Dan Christensen 135 | for prodding me into it) 136 | - change timeout to from 5000 to 15000 ms to deal with reported issues 137 | with high-latency links; unused var removal; and man page typo (thanks 138 | to Michael Shields) 139 | 140 | Version 1.2e 141 | 142 | - check for attempt to use -f flag; exit as error 143 | - if AUTOSSH_GATETIME is 0, then disable any of the startup 144 | failure bailouts, and just retry 145 | - set SO_REUSEADDR on listening socket (Jedi One's suggestion) 146 | - show port number in some error messages 147 | - note in man page and README about -M 0 turning port monitoring off 148 | - remove duplicate include of sys/socket.h 149 | 150 | Version 1.2d 151 | 152 | - AIX support (thanks to Stefan Rodenstein) 153 | - fix argument rewrite bug when using AUTOSSH_PORT (thanks 154 | to Peter Williams) 155 | - log pid of ssh child just after fork 156 | 157 | Version 1.2c 158 | 159 | - use Marcus Friedl's suggestion to simply connect to "127.0.0.1" 160 | rather than "localhost", as not really using IPv6 anyway. And this 161 | gets rid of annoying ipv6 localhost message on Solaris at least. 162 | - support for MacOS X using Greg Parker's fakepoll. 163 | 164 | Version 1.2b 165 | 166 | (Thanks to Simon Easter for bug reports and trials) 167 | 168 | - fix file descriptor leak 169 | - setsockopt()'s don't work for Solaris either. Give up on them. 170 | - set close-on-exec for read socket so will be closed when 171 | ssh executed 172 | - do shutdown() before close() (paranoia) 173 | - close read socket before exit 174 | - pull read socket open and close up out of ssh_run() 175 | - cosmetic changes to some loops, get rid of newlines in some 176 | errlog strings. 177 | 178 | Version 1.2a 179 | 180 | - setsockopt() will not set timeouts on socket read/write ops 181 | under Linux 2.2 kernels (and earlier, I presume). So unless 182 | someone tells me we really need them, I've #ifdef'd the 183 | setsockopt()s out for Linux. 184 | - check value of fd returned by accept(). 185 | - Oh, there's a man page now. Unfortunately, it doesn't render 186 | for Solaris. Sorry, Solaris users are still stuck with the 187 | README. 188 | 189 | Version 1.2 190 | 191 | - Major restructuring of code, mostly to support the change to 192 | a loop of forwarded ports to test the network connection. 193 | - Incremental back off on rate of connection attempts when 194 | there are rapid failures to establish/maintain a connection. 195 | 196 | Version 1.1b 197 | 198 | - change handling of ssh exit status 199 | - introduce "starting gate" time: ssh process that dies too 200 | early is deemed not to have made it out of the starting 201 | gate, and autossh exits. 202 | 203 | Version 1.1a 204 | 205 | - fix race after failure to exec ssh where parent will 206 | loop attempting to restart 207 | - add -V version flag 208 | - use strtoul() for environment option parsing 209 | - drop useless intermediate function ssh_setwatch() 210 | 211 | Version 1.1 212 | 213 | Initial release 214 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software 2 | Foundation, Inc. 3 | 4 | This file is free documentation; the Free Software Foundation gives 5 | unlimited permission to copy, distribute and modify it. 6 | 7 | Basic Installation 8 | ================== 9 | 10 | These are generic installation instructions. 11 | 12 | The `configure' shell script attempts to guess correct values for 13 | various system-dependent variables used during compilation. It uses 14 | those values to create a `Makefile' in each directory of the package. 15 | It may also create one or more `.h' files containing system-dependent 16 | definitions. Finally, it creates a shell script `config.status' that 17 | you can run in the future to recreate the current configuration, and a 18 | file `config.log' containing compiler output (useful mainly for 19 | debugging `configure'). 20 | 21 | It can also use an optional file (typically called `config.cache' 22 | and enabled with `--cache-file=config.cache' or simply `-C') that saves 23 | the results of its tests to speed up reconfiguring. (Caching is 24 | disabled by default to prevent problems with accidental use of stale 25 | cache files.) 26 | 27 | If you need to do unusual things to compile the package, please try 28 | to figure out how `configure' could check whether to do them, and mail 29 | diffs or instructions to the address given in the `README' so they can 30 | be considered for the next release. If you are using the cache, and at 31 | some point `config.cache' contains results you don't want to keep, you 32 | may remove or edit it. 33 | 34 | The file `configure.ac' (or `configure.in') is used to create 35 | `configure' by a program called `autoconf'. You only need 36 | `configure.ac' if you want to change it or regenerate `configure' using 37 | a newer version of `autoconf'. 38 | 39 | The simplest way to compile this package is: 40 | 41 | 1. `cd' to the directory containing the package's source code and type 42 | `./configure' to configure the package for your system. If you're 43 | using `csh' on an old version of System V, you might need to type 44 | `sh ./configure' instead to prevent `csh' from trying to execute 45 | `configure' itself. 46 | 47 | Running `configure' takes awhile. While running, it prints some 48 | messages telling which features it is checking for. 49 | 50 | 2. Type `make' to compile the package. 51 | 52 | 3. Optionally, type `make check' to run any self-tests that come with 53 | the package. 54 | 55 | 4. Type `make install' to install the programs and any data files and 56 | documentation. 57 | 58 | 5. You can remove the program binaries and object files from the 59 | source code directory by typing `make clean'. To also remove the 60 | files that `configure' created (so you can compile the package for 61 | a different kind of computer), type `make distclean'. There is 62 | also a `make maintainer-clean' target, but that is intended mainly 63 | for the package's developers. If you use it, you may have to get 64 | all sorts of other programs in order to regenerate files that came 65 | with the distribution. 66 | 67 | Compilers and Options 68 | ===================== 69 | 70 | Some systems require unusual options for compilation or linking that 71 | the `configure' script does not know about. Run `./configure --help' 72 | for details on some of the pertinent environment variables. 73 | 74 | You can give `configure' initial values for configuration parameters 75 | by setting variables in the command line or in the environment. Here 76 | is an example: 77 | 78 | ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix 79 | 80 | *Note Defining Variables::, for more details. 81 | 82 | Compiling For Multiple Architectures 83 | ==================================== 84 | 85 | You can compile the package for more than one kind of computer at the 86 | same time, by placing the object files for each architecture in their 87 | own directory. To do this, you must use a version of `make' that 88 | supports the `VPATH' variable, such as GNU `make'. `cd' to the 89 | directory where you want the object files and executables to go and run 90 | the `configure' script. `configure' automatically checks for the 91 | source code in the directory that `configure' is in and in `..'. 92 | 93 | If you have to use a `make' that does not support the `VPATH' 94 | variable, you have to compile the package for one architecture at a 95 | time in the source code directory. After you have installed the 96 | package for one architecture, use `make distclean' before reconfiguring 97 | for another architecture. 98 | 99 | Installation Names 100 | ================== 101 | 102 | By default, `make install' will install the package's files in 103 | `/usr/local/bin', `/usr/local/man', etc. You can specify an 104 | installation prefix other than `/usr/local' by giving `configure' the 105 | option `--prefix=PATH'. 106 | 107 | You can specify separate installation prefixes for 108 | architecture-specific files and architecture-independent files. If you 109 | give `configure' the option `--exec-prefix=PATH', the package will use 110 | PATH as the prefix for installing programs and libraries. 111 | Documentation and other data files will still use the regular prefix. 112 | 113 | In addition, if you use an unusual directory layout you can give 114 | options like `--bindir=PATH' to specify different values for particular 115 | kinds of files. Run `configure --help' for a list of the directories 116 | you can set and what kinds of files go in them. 117 | 118 | If the package supports it, you can cause programs to be installed 119 | with an extra prefix or suffix on their names by giving `configure' the 120 | option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. 121 | 122 | Optional Features 123 | ================= 124 | 125 | Some packages pay attention to `--enable-FEATURE' options to 126 | `configure', where FEATURE indicates an optional part of the package. 127 | They may also pay attention to `--with-PACKAGE' options, where PACKAGE 128 | is something like `gnu-as' or `x' (for the X Window System). The 129 | `README' should mention any `--enable-' and `--with-' options that the 130 | package recognizes. 131 | 132 | For packages that use the X Window System, `configure' can usually 133 | find the X include and library files automatically, but if it doesn't, 134 | you can use the `configure' options `--x-includes=DIR' and 135 | `--x-libraries=DIR' to specify their locations. 136 | 137 | Specifying the System Type 138 | ========================== 139 | 140 | There may be some features `configure' cannot figure out 141 | automatically, but needs to determine by the type of machine the package 142 | will run on. Usually, assuming the package is built to be run on the 143 | _same_ architectures, `configure' can figure that out, but if it prints 144 | a message saying it cannot guess the machine type, give it the 145 | `--build=TYPE' option. TYPE can either be a short name for the system 146 | type, such as `sun4', or a canonical name which has the form: 147 | 148 | CPU-COMPANY-SYSTEM 149 | 150 | where SYSTEM can have one of these forms: 151 | 152 | OS KERNEL-OS 153 | 154 | See the file `config.sub' for the possible values of each field. If 155 | `config.sub' isn't included in this package, then this package doesn't 156 | need to know the machine type. 157 | 158 | If you are _building_ compiler tools for cross-compiling, you should 159 | use the `--target=TYPE' option to select the type of system they will 160 | produce code for. 161 | 162 | If you want to _use_ a cross compiler, that generates code for a 163 | platform different from the build platform, you should specify the 164 | "host" platform (i.e., that on which the generated programs will 165 | eventually be run) with `--host=TYPE'. 166 | 167 | Sharing Defaults 168 | ================ 169 | 170 | If you want to set default values for `configure' scripts to share, 171 | you can create a site shell script called `config.site' that gives 172 | default values for variables like `CC', `cache_file', and `prefix'. 173 | `configure' looks for `PREFIX/share/config.site' if it exists, then 174 | `PREFIX/etc/config.site' if it exists. Or, you can set the 175 | `CONFIG_SITE' environment variable to the location of the site script. 176 | A warning: not all `configure' scripts look for a site script. 177 | 178 | Defining Variables 179 | ================== 180 | 181 | Variables not defined in a site shell script can be set in the 182 | environment passed to `configure'. However, some packages may run 183 | configure again during the build, and the customized values of these 184 | variables may be lost. In order to avoid this problem, you should set 185 | them in the `configure' command line, using `VAR=value'. For example: 186 | 187 | ./configure CC=/usr/local2/bin/gcc 188 | 189 | will cause the specified gcc to be used as the C compiler (unless it is 190 | overridden in the site shell script). 191 | 192 | `configure' Invocation 193 | ====================== 194 | 195 | `configure' recognizes the following options to control how it 196 | operates. 197 | 198 | `--help' 199 | `-h' 200 | Print a summary of the options to `configure', and exit. 201 | 202 | `--version' 203 | `-V' 204 | Print the version of Autoconf used to generate the `configure' 205 | script, and exit. 206 | 207 | `--cache-file=FILE' 208 | Enable the cache: use and save the results of the tests in FILE, 209 | traditionally `config.cache'. FILE defaults to `/dev/null' to 210 | disable caching. 211 | 212 | `--config-cache' 213 | `-C' 214 | Alias for `--cache-file=config.cache'. 215 | 216 | `--quiet' 217 | `--silent' 218 | `-q' 219 | Do not print messages saying which checks are being made. To 220 | suppress all normal output, redirect it to `/dev/null' (any error 221 | messages will still be shown). 222 | 223 | `--srcdir=DIR' 224 | Look for the package's source code in directory DIR. Usually 225 | `configure' can determine that directory automatically. 226 | 227 | `configure' also accepts some other, not widely useful, options. Run 228 | `configure --help' for more details. 229 | 230 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | 2 | autossh Version 1.4 3 | ------------------- 4 | 5 | Building and Installing Autossh 6 | -------------------------------- 7 | 8 | With version 1.4, autossh now uses autoconf. So the build procedure 9 | is now the well-known: 10 | 11 | ./configure 12 | make 13 | make install 14 | 15 | Look at autossh.host for an example wrapper script. 16 | 17 | 18 | Usage 19 | ----- 20 | autossh [-M [:echo_port]] [-f] [SSH OPTIONS] 21 | 22 | Description 23 | ----------- 24 | 25 | autossh is a program to start a copy of ssh and monitor it, restarting 26 | it as necessary should it die or stop passing traffic. 27 | 28 | The original idea and the mechanism were from rstunnel (Reliable SSH 29 | Tunnel). With version 1.2 the method changed: autossh now uses ssh to 30 | construct a loop of ssh forwardings (one from local to remote, one 31 | from remote to local), and then sends test data that it expects to get 32 | back. (The idea is thanks to Terrence Martin.) 33 | 34 | With version 1.3, a new method is added (thanks to Ron Yorston): a 35 | port may be specified for a remote echo service that will echo back 36 | the test data. This avoids the congestion and the aggravation of 37 | making sure all the port numbers on the remote machine do not 38 | collide. The loop-of -forwardings method remains available for 39 | situations where using an echo service may not be possible. 40 | 41 | autossh has only three arguments of its own: 42 | 43 | -M [:echo_port], to specify the base monitoring port to use, or 44 | alternatively, to specify the monitoring port and echo service 45 | port to use. 46 | 47 | When no echo service port is specified, this port and the port 48 | immediately above it (port# + 1) should be something nothing 49 | else is using. autossh will send test data on the base monitoring 50 | port, and receive it back on the port above. For example, if you 51 | specify "-M 20000", autossh will set up forwards so that it can 52 | send data on port 20000 and receive it back on 20001. 53 | 54 | Alternatively a port for a remote echo service may be 55 | specified. This should be port 7 if you wish to use the 56 | standard inetd echo service. When an echo port is specified, 57 | only the specified monitor port is used, and it carries the 58 | monitor message in both directions. 59 | 60 | Many people disable the echo service, or even disable inetd, 61 | so check that this service is available on the remote 62 | machine. Some operating systems allow one to specify that the 63 | service only listen on the localhost (loopback interface), 64 | which would suffice for this use. 65 | 66 | The echo service may also be something more complicated: 67 | perhaps a daemon that monitors a group of ssh tunnels. 68 | 69 | -M 0 will turn the monitoring off, and autossh will only 70 | restart ssh on ssh exit. 71 | 72 | For example, if you are using a recent version of OpenSSH, you 73 | may wish to explore using the ServerAliveInterval and 74 | ServerAliveCountMax options to have the SSH client exit if it 75 | finds itself no longer connected to the server. In many ways 76 | this may be a better solution than the monitoring port. 77 | 78 | -f Causes autossh to drop to the background before running ssh. The 79 | -f flag is stripped from arguments passed to ssh. Note that there 80 | is a crucial difference between the -f with autossh, and -f 81 | with ssh: when used with autossh, ssh will be *unable* to ask for 82 | passwords or passphrases. When -f is used, the "starting gate" 83 | time (see AUTOSSH_GATETIME) will be set to 0. 84 | 85 | -V to have autossh display its version and exit. 86 | 87 | All other arguments are passed to ssh. There are a number of 88 | other settings, but these are all controlled through environment 89 | variables. ssh seems to be appropriating more and more letters for 90 | options, and this seems the easiest way to avoid collisions. 91 | 92 | autossh tries to distinguish the manner of death of the ssh process it 93 | is monitoring and act appropriately. The rules are: 94 | 95 | - If the ssh process exited normally (for example, someone typed 96 | "exit" in an interactive session), autossh exits rather than 97 | restarting; 98 | - If autossh itself receives a SIGTERM, SIGINT, or a SIGKILL 99 | signal, it assumes that it was deliberately signalled, and exits 100 | after killing the child ssh process; 101 | - If autossh itself receives a SIGUSR1 signal, it will kill the child 102 | ssh process and start a new one; 103 | - Periodically (by default every 10 minutes), autossh attempts to pass 104 | traffic on the monitor forwarded port. If this fails, autossh will 105 | kill the child ssh process (if it is still running) and start a new 106 | one; 107 | - If the child ssh process dies for any other reason, autossh will 108 | attempt to start a new one. 109 | 110 | Startup behaviour: 111 | 112 | - If the ssh session fails with an exit status of 1 on the very first 113 | try, autossh will assume that there is some problem with syntax or 114 | the connection setup, and will exit rather than retrying; 115 | - There is now a "starting gate" time. If the first ssh process fails 116 | within the first few seconds of being started, autossh assumes that 117 | it never made it "out of the starting gate", and exits. This is to handle 118 | initial failed authentication, connection, etc. This time is 30 seconds 119 | by default, and can be adjusted (see the AUTOSSH_GATETIME environment 120 | variable below). 121 | - NOTE: If AUTOSSH_GATETIME is set to 0, then BOTH of the above 122 | behaviours are disabled. This is useful for, for example, 123 | having autossh start on boot. The "starting gate" time is 124 | also set to 0 with the -f flag to autossh is used. 125 | 126 | Continued failures: 127 | 128 | - If the ssh connection fails and attempts to restart it fail in 129 | quick succession, autossh will start delaying its attempts to 130 | restart, gradually backing farther and farther off up to a 131 | maximum interval of the autossh poll time (usually 10 minutes). 132 | autossh can be "prodded" to retry by signalling it, perhaps with 133 | SIGHUP ("kill -HUP"). 134 | 135 | Connection Setup 136 | ---------------- 137 | 138 | As connections must be established unattended, the use of autossh 139 | requires that some form of automatic authentication be set up. The use 140 | of RSAAuthentication with ssh-agent is the recommended method. The 141 | example wrapper script attempts to check if there is an agent running 142 | for the current environment, and to start one if there isn't. 143 | 144 | It cannot be stressed enough that you must make sure ssh works on its 145 | own, that you can set up the session you want before you try to 146 | run it under autossh. 147 | 148 | If you are tunnelling and using an older version of ssh that does not 149 | support the -N flag, you should upgrade (your version has security 150 | flaws). If you can't upgrade, you may wish to do as rstunnel does, and 151 | give ssh a command to run, such as "sleep 99999999999". 152 | 153 | Disabling connection monitoring 154 | ------------------------------- 155 | 156 | A monitor port value of "0" ("autossh -M 0") will disable use of 157 | the monitor ports; autossh will then only react to signals and the 158 | death of the ssh process. 159 | 160 | Environment Variables 161 | --------------------- 162 | 163 | The following environment variables can be set: 164 | 165 | AUTOSSH_DEBUG - sets logging level to LOG_DEBUG, and if 166 | the operating system supports it, sets 167 | syslog to duplicate log entries to stderr. 168 | AUTOSSH_FIRST_POLL - time to initial poll (default is as 169 | AUTOSSH_POLL below). 170 | AUTOSSH_GATETIME - how long ssh must be up before we consider 171 | it a successful connection. Default is 30 172 | seconds. If set to 0, then this behaviour 173 | is disabled, and as well, autossh will retry 174 | even on failure of first attempt to run ssh. 175 | AUTOSSH_LOGFILE - sets autossh to use the named log file, 176 | rather than syslog. 177 | AUTOSSH_LOGLEVEL - log level, they correspond to the levels 178 | used by syslog; so 0-7 with 7 being the 179 | chattiest. 180 | AUTOSSH_MAXLIFETIME - Sets the maximum number of seconds the process 181 | should live for before killing off the ssh child 182 | and exiting. 183 | AUTOSSH_MAXSTART - specifies how many times ssh should be started. 184 | A negative number means no limit on the number 185 | of times ssh is started. The default value is -1. 186 | AUTOSSH_MESSAGE - append a custom message to the echo string (max 64 187 | bytes). 188 | AUTOSSH_NTSERVICE - when set to "yes" , setup autossh to run as an 189 | NT service under cygrunsrv. This adds the -N flag 190 | for ssh if not already set, sets the log output 191 | to stdout, and changes the behaviour on ssh exit 192 | so that it will restart even on a normal exit. 193 | AUTOSSH_PATH - path to the ssh executable, in case 194 | it is different than that compiled in. 195 | AUTOSSH_PIDFILE - write autossh pid to specified file. 196 | AUTOSSH_POLL - poll time in seconds; default is 600. 197 | Changing this will also change the first 198 | poll time, unless AUTOSSH_FIRST_POLL is 199 | used to set it to something different. 200 | If the poll time is less than twice the 201 | network timeouts (default 15 seconds) the 202 | network timeouts will be adjusted downward 203 | to 1/2 the poll time. 204 | AUTOSSH_PORT - set monitor port. Mostly in case ssh 205 | appropriates -M at some time. But because 206 | of this possible use, AUTOSSH_PORT overrides 207 | the -M flag. 208 | 209 | SSH Options 210 | ------------------ 211 | 212 | There are two particular OpenSSH options that are useful when using 213 | autossh: 214 | 215 | 1) ExitOnForwardFailure=yes on the client side to make sure forwardings 216 | have succeeded when autossh assumes the connection is setup properly. 217 | 218 | 2) ClientAliveInterval on the server side to make sure the listening 219 | socket is closed on the server side if the connection closes on the 220 | client side. 221 | 222 | Logging and Syslog 223 | ------------------ 224 | 225 | autossh logs to syslog using the LOG_USER facility. Your syslog may 226 | have to be configured to accept messages for this facility. This is 227 | usually done in /etc/syslog.conf. 228 | 229 | -- 230 | Kudos and raspberries to harding [at] motd.ca 231 | -------------------------------------------------------------------------------- /autossh.1: -------------------------------------------------------------------------------- 1 | .\" -*- nroff -*- 2 | .\" 3 | .\" Author: Carson Harding 4 | .\" Copyright (c) 2002-2018 Carson Harding. All rights reserved. 5 | .\" 6 | .\" Redistribution and use in source and binary forms, with or without 7 | .\" modification, are permitted. 8 | .\" 9 | .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 10 | .\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 11 | .\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 12 | .\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 13 | .\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 14 | .\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 15 | .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 16 | .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 17 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 18 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 19 | .\" 20 | .\" $Id: autossh.1,v 1.24 2018/03/18 19:28:38 harding Exp $ 21 | .\" 22 | .Dd Mar 18, 2018 23 | .Dt AUTOSSH 1 24 | .Os 25 | .Sh NAME 26 | .Nm autossh 27 | .Nd monitor and restart ssh sessions 28 | .Sh SYNOPSIS 29 | .Nm autossh 30 | .Op Fl V 31 | .Op Fl M Ar port[:echo_port] 32 | .Op Fl f 33 | .Ar [SSH_OPTIONS] 34 | .Sh DESCRIPTION 35 | .Nm 36 | is a program to start a copy of ssh and monitor it, restarting it as 37 | necessary should it die or stop passing traffic. 38 | .Pp 39 | The original idea and the mechanism were from rstunnel (Reliable SSH 40 | Tunnel). With version 1.2 of 41 | .Nm 42 | the method changed: 43 | .Nm 44 | uses ssh to construct a loop of ssh forwardings (one from local to 45 | remote, one from remote to local), and then sends test data that it 46 | expects to get back. (The idea is thanks to Terrence Martin.) 47 | .Pp 48 | With version 1.3, a new method is added (thanks to Ron Yorston): a 49 | port may be specified for a remote echo service that will echo back 50 | the test data. This avoids the congestion and the aggravation of 51 | making sure all the port numbers on the remote machine do not 52 | collide. The loop-of-forwardings method remains available for 53 | situations where using an echo service may not be possible. 54 | .Pp 55 | .Sh CONTROLLING SSH 56 | .Pp 57 | .Ss SSH exits 58 | .Pp 59 | .Bl -tag -width Ds 60 | .Nm 61 | tries to distinguish the manner of death of the ssh process it 62 | is monitoring and act appropriately. The rules are: 63 | .Bl -tag -width Ds 64 | .It 1. 65 | If the ssh process exited normally (for example, someone typed 66 | "exit" in an interactive session), 67 | .Nm 68 | exits rather than restarting; 69 | .It 2. 70 | If 71 | .Nm 72 | itself receives a SIGTERM, SIGINT, or a SIGKILL signal, it assumes 73 | that it was deliberately signalled, and exits after killing the child 74 | ssh process; 75 | .It 3. 76 | If 77 | .Nm 78 | itself receives a SIGUSR1 signal, it kills the child ssh process and starts 79 | a new one; 80 | .It 4. 81 | Periodically (by default every 10 minutes), 82 | .Nm 83 | attempts to pass traffic on the monitor forwarded port. If this fails, 84 | .Nm 85 | will kill the child ssh process (if it is still running) and start a new one; 86 | .It 5. 87 | If the child ssh process dies for any other reason, 88 | .Nm 89 | will attempt to start a new one. 90 | .El 91 | .Pp 92 | .Ss Startup behaviour 93 | .Pp 94 | If the ssh session fails with an exit status of 1 on the very first 95 | try, 96 | .Nm 97 | .Bl -tag -width Ds 98 | .It 1. 99 | will assume that there is some problem with syntax or the connection 100 | setup, and will exit rather than retrying; 101 | .It 2. 102 | There is a "starting gate" time. If the first ssh process fails within 103 | the first few seconds of being started, 104 | .Nm 105 | assumes that 106 | it never made it "out of the starting gate", and exits. This is to handle 107 | initial failed authentication, connection, etc. This time is 30 seconds 108 | by default, and can be adjusted (see the AUTOSSH_GATETIME environment 109 | variable below). If AUTOSSH_GATETIME is set to 0, then both behaviours 110 | are disabled: there is no "starting gate", and autossh will restart even 111 | if ssh fails on the first run with an exit status of 1. The "starting gate" 112 | time is also set to 0 when the 113 | .Fl f 114 | flag to autossh is used. 115 | .El 116 | .Pp 117 | .Ss Continued failures 118 | .Pp 119 | If the ssh connection fails and attempts to restart it fail in 120 | quick succession, 121 | .Nm 122 | will start delaying its attempts to 123 | restart, gradually backing farther and farther off up to a 124 | maximum interval of the 125 | .Nm 126 | poll time (usually 10 minutes). 127 | .Nm 128 | can be "prodded" to retry by signalling it, perhaps with 129 | SIGHUP ("kill -HUP"). 130 | .Pp 131 | .Ss Connection setup 132 | .Pp 133 | As connections must be established unattended, the use of 134 | .Nm 135 | requires that some form of automatic authentication be set up. The use 136 | of RSAAuthentication with ssh-agent is the recommended method. The 137 | example wrapper script attempts to check if there is an agent running 138 | for the current environment, and to start one if there isn't. 139 | .Pp 140 | It cannot be stressed enough that you must make sure ssh works on its 141 | own, that you can set up the session you want before you try to 142 | run it under 143 | .Nm 144 | . 145 | .Pp 146 | If you are tunnelling and using an older version of ssh that does not 147 | support the 148 | .Fl N 149 | flag, you should upgrade (your version has security 150 | flaws). If you can't upgrade, you may wish to do as rstunnel does, and 151 | give ssh a command to run, such as "sleep 99999999999". 152 | .Sh OPTIONS 153 | .Bl -tag -width Ds 154 | .It Fl M Ar port[:echo_port] 155 | specifies the base monitoring port to use. Without the echo port, 156 | this port and the port 157 | immediately above it ( 158 | .Ar port 159 | + 1) should be something nothing else is 160 | using. 161 | .Nm 162 | will send test data on the base monitoring port, and 163 | receive it back on the port above. For example, if you specify "-M 164 | 20000", 165 | .Nm 166 | will set up forwards so that it can send data on port 167 | 20000 and receive it back on 20001. 168 | .Pp 169 | Alternatively, a port for a remote echo service may be specified. This 170 | should be port 7 if you wish to use the standard inetd echo service. 171 | When an echo port is specified, only the specified monitor port is 172 | used, and it carries the monitor message in both directions. 173 | .Pp 174 | Many people disable the echo service, or even disable inetd, so check 175 | that this service is available on the remote machine. Some operating 176 | systems allow one to specify that the service only listen on the 177 | localhost (loopback interface), which would suffice for this use. 178 | .Pp 179 | The echo service may also be something more complicated: perhaps 180 | a daemon that monitors a group of ssh tunnels. 181 | .Pp 182 | Setting the monitor port to 0 turns the monitoring function off, and 183 | autossh will only restart ssh upon ssh's exit. For example, if you are 184 | using a recent version of OpenSSH, you may wish to explore using the 185 | .Cm ServerAliveInterval 186 | and 187 | .Cm ServerAliveCountMax 188 | options to have the SSH client exit if it finds itself no longer 189 | connected to the server. In many ways this may be a better solution than 190 | the monitoring port. 191 | .It Fl f 192 | causes autossh to drop to the background before running ssh. The 193 | .Fl f 194 | flag is stripped from arguments passed to ssh. Note that there is a crucial 195 | difference between 196 | .Fl f 197 | with autossh, and 198 | .Fl f 199 | with ssh: when used with 200 | .Nm 201 | ssh will be unable to ask for passwords or passphrases. When 202 | .Fl f 203 | is used, the "starting gate" time (see AUTOSSH_GATETIME) 204 | is set to 0. 205 | .It Fl V 206 | causes 207 | .Nm 208 | to display its version number and exit. 209 | .El 210 | .Sh ENVIRONMENT 211 | Other than the flag to set the connection monitoring port, 212 | .Nm 213 | uses environment variables to control features. ssh seems to be 214 | still collecting letters for options, and this seems the easiest 215 | way to avoid collisions. 216 | .Bl -tag -width Ds 217 | .It Ev AUTOSSH_DEBUG 218 | If this variable is set, the logging level is set to to LOG_DEBUG, and 219 | if the operating system supports it, syslog is set to duplicate log 220 | entries to stderr. 221 | .It Ev AUTOSSH_FIRST_POLL 222 | Specifies the time to wait before the first connection test. Thereafter 223 | the general poll time is used (see AUTOSSH_POLL below). 224 | .It Ev AUTOSSH_GATETIME 225 | Specifies how long ssh must be up before we consider it a successful 226 | connection. The default is 30 seconds. Note that if AUTOSSH_GATETIME 227 | is set to 0, then not only is the gatetime behaviour turned off, but 228 | autossh also ignores the first run failure of ssh. This may be useful 229 | when running autossh at boot. 230 | .It Ev AUTOSSH_LOGLEVEL 231 | Specifies the log level, corresponding to the levels used by syslog; 232 | so 0-7 with 7 being the chattiest. 233 | .It Ev AUTOSSH_LOGFILE 234 | Specifies that 235 | .Nm 236 | should use the named log file, rather than syslog. 237 | .It Ev AUTOSSH_MAXLIFETIME 238 | Sets the maximum number of seconds that the program should run. Once 239 | the number of seconds has been passed, the ssh child will be killed 240 | and the program will exit. 241 | .It Ev AUTOSSH_MAXSTART 242 | Specifies how many times ssh should be started. A negative number 243 | means no limit on the number of times ssh is started. The default 244 | value is -1. 245 | .It Ev AUTOSSH_MESSAGE 246 | Append message to echo message sent when testing connections. 247 | .It Ev AUTOSSH_NTSERVICE 248 | (Cygwin only.) When set to "yes" , autossh sets up to run as an NT 249 | service under cygrunsrv. This adds the -N flag for ssh if not already 250 | set, sets the log output to stdout, and changes the behaviour on ssh 251 | exit so that it will restart even on a normal exit. 252 | .It Ev AUTOSSH_PATH 253 | Specifies the path to the ssh executable, in case it is 254 | different than the path compiled in. 255 | .It Ev AUTOSSH_PIDFILE 256 | Write autossh pid to specified file. 257 | .It Ev AUTOSSH_POLL 258 | Specifies the connection poll time in seconds; default is 600 seconds. 259 | Unless AUTOSSH_FIRST_POLL is used, the first poll time will 260 | set to match the poll time. If the poll time is less than twice the 261 | network timeouts (default 15 seconds) the network timeouts will be 262 | adjusted downward to 1/2 the poll time. 263 | .It Ev AUTOSSH_PORT 264 | Sets the connection monitoring port. Mostly in case ssh appropriates 265 | -M at some time. But because of this possible use, AUTOSSH_PORT 266 | overrides the -M flag. A value of 0 turns the monitoring function off. 267 | .El 268 | .Sh ENVIRONMENT 269 | There are two particular OpenSSH options that are useful when using 270 | .Nm 271 | : 272 | .Fp 273 | .Cm ExitOnForwardFailure=yes 274 | on the client side to make sure forwardings 275 | have succeeded when autossh assumes the connection is setup properly. 276 | .Fp 277 | .Cm ClientAliveInterval 278 | on the server side to make sure the listening 279 | socket is closed on the server side if the connection closes on the 280 | client side. 281 | .El 282 | .Sh AUTHOR 283 | .Nm 284 | was written by Carson Harding. 285 | .Sh SEE ALSO 286 | .Xr ssh 1 , 287 | .Xr ssh_config 5, 288 | .Xr sshd_config 5, 289 | .Xr ssh-add 1 , 290 | .Xr ssh-agent 1 , 291 | .Xr ssh-keygen 1 , 292 | .Xr cygrunsrv 1 . 293 | -------------------------------------------------------------------------------- /autossh.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Start an ssh session (or tunnel) and monitor it. 3 | * If it fails or blocks, restart it. 4 | * 5 | * From the example of rstunnel. 6 | * 7 | * Copyright (c) Carson Harding, 2002-2018. 8 | * All rights reserved. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are freely permitted. 12 | * 13 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 14 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 15 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 16 | * THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 17 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 18 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 19 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 20 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 21 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 22 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | * 24 | * $Id: autossh.c,v 1.91 2019/01/05 01:23:39 harding Exp $ 25 | * 26 | */ 27 | 28 | #include "config.h" 29 | 30 | #include 31 | #include 32 | 33 | #ifndef HAVE_SOCKLEN_T 34 | typedef int32_t socklen_t; 35 | #endif 36 | 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | 56 | #ifndef HAVE_POLL 57 | # ifdef HAVE_SELECT 58 | # include "fakepoll.h" 59 | # else 60 | # error "System lacks both select() and poll()!" 61 | # endif 62 | #else 63 | # include 64 | #endif 65 | 66 | #ifndef __attribute__ 67 | # if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__ 68 | # define __attribute__(x) 69 | # endif 70 | #endif 71 | 72 | #ifndef _PATH_DEVNULL 73 | # define _PATH_DEVNULL "/dev/null" 74 | #endif 75 | 76 | #ifndef HAVE_DAEMON 77 | # include "daemon.h" 78 | #endif 79 | 80 | #ifdef HAVE___PROGNAME 81 | extern char *__progname; 82 | #else 83 | char *__progname; 84 | #endif 85 | 86 | const char *rcsid = "$Id: autossh.c,v 1.91 2019/01/05 01:23:39 harding Exp $"; 87 | 88 | #ifndef SSH_PATH 89 | # define SSH_PATH "/usr/bin/ssh" 90 | #endif 91 | 92 | #define POLL_TIME 600 /* 10 minutes default */ 93 | #define GATE_TIME 30 /* 30 seconds default */ 94 | #define MAX_LIFETIME 0 /* default max lifetime of forever */ 95 | #define TIMEO_NET 15000 /* poll on accept() and io (msecs) */ 96 | #define MAX_CONN_TRIES 3 /* how many attempts */ 97 | #define MAX_START (-1) /* max # of runs; <0 == forever */ 98 | #define MAX_MESSAGE 64 /* max length of message we can add */ 99 | 100 | #define P_CONTINUE 0 /* continue monitoring */ 101 | #define P_RESTART 1 /* restart ssh process */ 102 | #define P_EXITOK 2 /* exit ok */ 103 | #define P_EXITERR 3 /* exit with error */ 104 | 105 | #define L_FILELOG 0x01 /* log to file */ 106 | #define L_SYSLOG 0x02 /* log to syslog */ 107 | 108 | #define NO_RD_SOCK -2 /* magic flag for echo: no read socket */ 109 | 110 | #define N_FAST_TRIES 5 /* try this many times fast before slowing */ 111 | 112 | #define OPTION_STRING "M:V1246ab:c:e:fgi:kl:m:no:p:qstvw:xyACD:E:F:GI:MJKL:NO:PQ:R:S:TW:XY" 113 | 114 | int logtype = L_SYSLOG; /* default log to syslog */ 115 | int loglevel = LOG_INFO; /* default loglevel */ 116 | int syslog_perror; /* use PERROR option? */ 117 | FILE *flog; /* log file */ 118 | 119 | char *writep; /* write port as string */ 120 | char readp[16]; /* read port as string */ 121 | char *echop; /* echo port as string */ 122 | char *mhost = "127.0.0.1"; /* host in port forwards */ 123 | char *env_port; /* port spec'd in environment */ 124 | char *echo_message = ""; /* message to append to echo string */ 125 | char *pid_file_name; /* path to pid file */ 126 | int pid_file_created; /* we have created pid file */ 127 | time_t pid_start_time; /* time autossh process started */ 128 | int poll_time = POLL_TIME; /* default connection poll time */ 129 | int first_poll_time = POLL_TIME; /* initial connection poll time */ 130 | double gate_time = GATE_TIME; /* time to "make it out of the gate" */ 131 | int max_start = MAX_START; /* how many times to run (default no limit) */ 132 | double max_lifetime = MAX_LIFETIME; /* how long can the process/daemon live */ 133 | int net_timeout = TIMEO_NET; /* timeout on network data */ 134 | char *ssh_path = SSH_PATH; /* default path to ssh */ 135 | int start_count; /* # of times exec()d ssh */ 136 | time_t start_time; /* time we exec()d ssh */ 137 | 138 | #if defined(__CYGWIN__) 139 | int ntservice; /* set some stuff for running as nt service */ 140 | #endif 141 | 142 | int newac; /* argc, argv for ssh */ 143 | char **newav; 144 | #define START_AV_SZ 16 145 | 146 | int cchild; /* current child */ 147 | 148 | volatile sig_atomic_t exit_signalled; /* signalled outside of monitor loop */ 149 | volatile sig_atomic_t restart_ssh; /* signalled to restart ssh child */ 150 | volatile sig_atomic_t dolongjmp; 151 | sigjmp_buf jumpbuf; 152 | 153 | void usage(int code) __attribute__ ((__noreturn__)); 154 | void get_env_args(void); 155 | void add_arg(char *s); 156 | void strip_arg(char *arg, char ch, char *opts); 157 | int ssh_run(int sock, char **argv); 158 | int ssh_watch(int sock); 159 | int ssh_wait(int options); 160 | void ssh_kill(void); 161 | int conn_test(int sock, char *host, char *write_port); 162 | int conn_poll_for_accept(int sock, struct pollfd *pfd); 163 | int conn_send_and_receive(char *rp, char *wp, size_t len, 164 | struct pollfd *pfd, int ntopoll); 165 | #ifndef HAVE_ADDRINFO 166 | void conn_addr(char *host, char *port, struct sockaddr_in *resp); 167 | #else 168 | void conn_addr(char *host, char *port, struct addrinfo **resp); 169 | #endif 170 | int conn_listen(char *host, char *port); 171 | int conn_remote(char *host, char *port); 172 | void grace_time(time_t last_start); 173 | void unlink_pid_file(void); 174 | void errlog(int level, char *fmt, ...) 175 | __attribute__ ((__format__ (__printf__, 2, 3))); 176 | void xerrlog(int level, char *fmt, ...) 177 | __attribute__ ((__format__ (__printf__, 2, 3))); 178 | void doerrlog(int level, char *fmt, va_list ap); 179 | char *timestr(void); 180 | void set_exit_sig_handler(void); 181 | void set_sig_handlers(void); 182 | void unset_sig_handlers(void); 183 | void sig_catch(int sig); 184 | int exceeded_lifetime(void); 185 | unsigned int clear_alarm_timer(void); 186 | 187 | void 188 | usage(int code) 189 | { 190 | fprintf(code ? stderr : stdout, 191 | "usage: %s [-V] [-M monitor_port[:echo_port]] [-f] [SSH_OPTIONS]\n", 192 | __progname); 193 | if (code) { 194 | fprintf(stderr, "\n"); 195 | fprintf(stderr, 196 | " -M specifies monitor port. May be overridden by" 197 | " environment\n" 198 | " variable AUTOSSH_PORT. 0 turns monitoring" 199 | " loop off.\n" 200 | " Alternatively, a port for an echo service on" 201 | " the remote\n" 202 | " machine may be specified. (Normally port 7.)\n"); 203 | fprintf(stderr, 204 | " -f run in background (autossh handles this, and" 205 | " does not\n" 206 | " pass it to ssh.)\n"); 207 | fprintf(stderr, 208 | " -V print autossh version and exit.\n"); 209 | fprintf(stderr, "\n"); 210 | fprintf(stderr, "Environment variables are:\n"); 211 | fprintf(stderr, 212 | " AUTOSSH_GATETIME " 213 | "- how long must an ssh session be established\n" 214 | " " 215 | " before we decide it really was established\n" 216 | " " 217 | " (in seconds). Default is %d seconds; use of -f\n" 218 | " " 219 | " flag sets this to 0.\n", GATE_TIME); 220 | fprintf(stderr, 221 | " AUTOSSH_LOGFILE " 222 | "- file to log to (default is to use the syslog\n" 223 | " " 224 | " facility)\n"); 225 | fprintf(stderr, 226 | " AUTOSSH_LOGLEVEL " 227 | "- level of log verbosity\n"); 228 | fprintf(stderr, 229 | " AUTOSSH_MAXLIFETIME " 230 | "- set the maximum time to live (seconds)\n"); 231 | fprintf(stderr, 232 | " AUTOSSH_MAXSTART " 233 | "- max times to restart (default is no limit)\n"); 234 | fprintf(stderr, 235 | " AUTOSSH_MESSAGE " 236 | "- message to append to echo string (max 64 bytes)\n"); 237 | #if defined(__CYGWIN__) 238 | fprintf(stderr, 239 | " AUTOSSH_NTSERVICE " 240 | "- tweak some things for running under cygrunsrv\n"); 241 | #endif 242 | fprintf(stderr, 243 | " AUTOSSH_PATH " 244 | "- path to ssh if not default\n"); 245 | fprintf(stderr, 246 | " AUTOSSH_PIDFILE " 247 | "- write pid to this file\n"); 248 | fprintf(stderr, 249 | " AUTOSSH_POLL " 250 | "- how often to check the connection (seconds)\n"); 251 | fprintf(stderr, 252 | " AUTOSSH_FIRST_POLL " 253 | "- time before first connection check (seconds)\n"); 254 | fprintf(stderr, 255 | " AUTOSSH_PORT " 256 | "- port to use for monitor connection\n"); 257 | fprintf(stderr, 258 | " AUTOSSH_DEBUG " 259 | "- turn logging to maximum verbosity and log to\n" 260 | " " 261 | " stderr\n"); 262 | fprintf(stderr, "\n"); 263 | } 264 | exit(code); 265 | } 266 | 267 | int 268 | main(int argc, char **argv) 269 | { 270 | int i; 271 | int n; 272 | int ch; 273 | char *s; 274 | int wp, rp, ep = 0; 275 | char wmbuf[256], rmbuf[256]; 276 | FILE *pid_file; 277 | 278 | int retval = 0; 279 | int sock = -1; 280 | int done_fwds = 0; 281 | int runasdaemon = 0; 282 | int sawargstop = 0; 283 | #if defined(__CYGWIN__) 284 | int sawoptionn = 0; 285 | #endif 286 | 287 | #ifndef HAVE___PROGNAME 288 | __progname = "autossh"; 289 | #endif 290 | 291 | /* 292 | * set up options from environment 293 | */ 294 | get_env_args(); 295 | 296 | /* 297 | * We accept all ssh args, and quietly pass them on 298 | * to ssh when we call it. 299 | */ 300 | while ((ch = getopt(argc, argv, OPTION_STRING)) != -1) { 301 | switch(ch) { 302 | case 'M': 303 | if (!env_port) 304 | writep = optarg; 305 | break; 306 | case 'V': 307 | fprintf(stdout, "%s %s\n", __progname, VER); 308 | exit(0); 309 | break; 310 | case 'f': 311 | runasdaemon = 1; 312 | break; 313 | #if defined(__CYGWIN__) 314 | case 'N': 315 | sawoptionn = 1; 316 | break; 317 | #endif 318 | case '?': 319 | usage(1); 320 | break; 321 | default: 322 | /* other options get passed to ssh */ 323 | break; 324 | } 325 | } 326 | 327 | /* if we got it from the environment */ 328 | if (env_port) 329 | writep = env_port; 330 | 331 | /* 332 | * We must at least have a monitor port and a remote host. 333 | */ 334 | if (!writep || argc == optind) 335 | usage(1); 336 | 337 | if (logtype & L_SYSLOG) 338 | openlog(__progname, LOG_PID|syslog_perror, LOG_USER); 339 | 340 | /* 341 | * Check for echo port 342 | */ 343 | if ((s = strchr(writep, ':')) != NULL) { 344 | *s = '\0'; 345 | echop = s + 1; 346 | ep = strtoul(echop, &s, 0); 347 | if (*echop == '\0' || *s != '\0' || ep == 0) 348 | xerrlog(LOG_ERR, "invalid echo port \"%s\"", echop); 349 | } 350 | 351 | /* 352 | * Check, and get the read port (write port + 1); 353 | * then construct port-forwarding arguments for ssh. 354 | */ 355 | wp = strtoul(writep, &s, 0); 356 | if (*writep == '\0' || *s != '\0') 357 | xerrlog(LOG_ERR, "invalid port \"%s\"", writep); 358 | if (wp == 0) { 359 | errlog(LOG_INFO, "port set to 0, monitoring disabled"); 360 | writep = NULL; 361 | } 362 | else if (wp > 65534 || wp < 0) 363 | xerrlog(LOG_ERR, "monitor port (%d) out of range", wp); 364 | else { 365 | rp = wp+1; 366 | /* all this for solaris; we could use asprintf() */ 367 | (void)snprintf(readp, sizeof(readp), "%d", rp); 368 | 369 | /* port-forward arg strings */ 370 | n = snprintf(wmbuf, sizeof(wmbuf), "%d:%s:%d", wp, mhost, 371 | echop ? ep : wp); 372 | if (n > sizeof(wmbuf)) 373 | xerrlog(LOG_ERR, 374 | "overflow building forwarding string"); 375 | if (!echop) { 376 | n = snprintf(rmbuf, sizeof(rmbuf), "%d:%s:%d", 377 | wp, mhost, rp); 378 | if (n > sizeof(rmbuf)) 379 | xerrlog(LOG_ERR, 380 | "overflow building forwarding string"); 381 | } 382 | } 383 | 384 | /* 385 | * Adjust timeouts if necessary: net_timeout is first 386 | * the timeout for accept and then for io, so if the 387 | * poll_time is set less than 2 timeouts, the timeouts need 388 | * to be adjusted to be at least 1/2. Perhaps there should be 389 | * be some padding here as well.... 390 | */ 391 | if ((poll_time * 1000) / 2 < net_timeout) { 392 | net_timeout = (poll_time * 1000) / 2; 393 | errlog(LOG_INFO, 394 | "short poll time: adjusting net timeouts to %d", 395 | net_timeout); 396 | } 397 | 398 | /* 399 | * Build a new arg list, skipping -f, -M and inserting 400 | * port forwards. 401 | */ 402 | add_arg(ssh_path); 403 | 404 | #if defined(__CYGWIN__) 405 | if (ntservice && !sawoptionn) 406 | add_arg("-N"); 407 | #endif 408 | 409 | for (i = 1; i < argc; i++) { 410 | /* 411 | * We step past the first '--', taking it as ours 412 | * (autossh's). Any further ones we pass to ssh. 413 | */ 414 | if (argv[i][0] == '-' && argv[i][1] == '-') { 415 | if (!sawargstop) { 416 | sawargstop = 1; 417 | continue; 418 | } 419 | } 420 | if (wp && env_port && !done_fwds) { 421 | add_arg("-L"); 422 | add_arg(wmbuf); 423 | if (!echop) { 424 | add_arg("-R"); 425 | add_arg(rmbuf); 426 | } 427 | done_fwds = 1; 428 | } else if (!sawargstop && argv[i][0] == '-' && argv[i][1] == 'M') { 429 | if (argv[i][2] == '\0') 430 | i++; 431 | if (wp && !done_fwds) { 432 | add_arg("-L"); 433 | add_arg(wmbuf); 434 | if (!echop) { 435 | add_arg("-R"); 436 | add_arg(rmbuf); 437 | } 438 | done_fwds = 1; 439 | } 440 | continue; 441 | } 442 | /* look for -f in option args and strip out */ 443 | strip_arg(argv[i], 'f', OPTION_STRING); 444 | add_arg(argv[i]); 445 | } 446 | 447 | if (runasdaemon) { 448 | if (daemon(0, 0) == -1) { 449 | xerrlog(LOG_ERR, "run as daemon failed: %s", 450 | strerror(errno)); 451 | } 452 | /* 453 | * If running as daemon, the user likely wants it 454 | * to just run and not fail early (perhaps machines 455 | * are coming up, etc.) 456 | */ 457 | gate_time = 0; 458 | } 459 | 460 | /* 461 | * Only if we're doing the network monitor thing. 462 | * Socket once opened stays open for listening for 463 | * the duration of the program. 464 | */ 465 | if (writep) { 466 | if (!echop) { 467 | sock = conn_listen(mhost, readp); 468 | /* set close-on-exec */ 469 | (void)fcntl(sock, F_SETFD, FD_CLOEXEC); 470 | } else 471 | sock = NO_RD_SOCK; 472 | } 473 | 474 | if (pid_file_name) { 475 | pid_file = fopen(pid_file_name, "w"); 476 | if (!pid_file) { 477 | xerrlog(LOG_ERR, "cannot open pid file \"%s\": %s", 478 | pid_file_name, strerror(errno)); 479 | } 480 | pid_file_created = 1; 481 | atexit(unlink_pid_file); 482 | if (fprintf(pid_file, "%d\n", (int)getpid()) == 0) 483 | xerrlog(LOG_ERR, "write failed to pid file \"%s\": %s", 484 | pid_file_name, strerror(errno)); 485 | fflush(pid_file); 486 | fclose(pid_file); 487 | } 488 | 489 | retval = ssh_run(sock, newav); 490 | 491 | if (sock >= 0) { 492 | shutdown(sock, SHUT_RDWR); 493 | close(sock); 494 | } 495 | 496 | if (logtype & L_SYSLOG) 497 | closelog(); 498 | 499 | if (retval == P_EXITERR) 500 | exit(1); 501 | exit(0); 502 | } 503 | 504 | /* 505 | * Add an argument to the argument array. 506 | */ 507 | void 508 | add_arg(char *s) 509 | { 510 | char *p; 511 | size_t len; 512 | static size_t newamax = START_AV_SZ; 513 | 514 | len = strlen(s); 515 | if (len == 0) 516 | return; 517 | 518 | if (!newav) { 519 | newav = calloc(START_AV_SZ, sizeof(char *)); 520 | if (!newav) 521 | xerrlog(LOG_ERR, "malloc: %s", strerror(errno)); 522 | } else if (newac >= newamax-1) { 523 | newamax *= 2; 524 | newav = realloc(newav, newamax * sizeof(char *)); 525 | if (!newav) 526 | xerrlog(LOG_ERR, "realloc: %s", strerror(errno)); 527 | } 528 | p = malloc(len+1); 529 | if (!p) xerrlog(LOG_ERR, "malloc: %s", strerror(errno)); 530 | memmove(p, s, len); 531 | p[len] = '\0'; 532 | newav[newac++] = p; 533 | newav[newac] = NULL; 534 | 535 | return; 536 | } 537 | 538 | /* 539 | * strip an argument option from an option string; strings that 540 | * end up with just a '-' become zero length (add_arg() will 541 | * skip them). An option that enters as '-' is untouched. 542 | * 543 | */ 544 | void 545 | strip_arg(char *arg, char ch, char *opts) 546 | { 547 | char *f, *o; 548 | size_t len; 549 | 550 | 551 | if (arg[0] == '-' && arg[1] != '\0') { 552 | for (len = strlen(arg), f = arg; *f != '\0'; f++, len--) { 553 | /* 554 | * If f in option string and next char is ':' then 555 | * what follows is a parameter to the flag, and 556 | * what we're stripping may be valid in it. We do 557 | * not validate f in opts: that is really someone 558 | * else's job, and the options may change. In that 559 | * case, this provides a best effort. This is 560 | * terribly inefficient. 561 | */ 562 | if ((o = strchr(opts, *f)) != NULL) { 563 | if (*(o+1) == ':') 564 | return; 565 | } 566 | if (*f == ch) 567 | (void)memmove(f, f+1, len); 568 | } 569 | /* left with "-" alone? then truncate */ 570 | if (arg[1] == '\0') 571 | arg[0] = '\0'; 572 | } 573 | 574 | return; 575 | } 576 | 577 | /* 578 | * Ugly, but as we've used so many command args... 579 | */ 580 | void 581 | get_env_args(void) 582 | { 583 | char *s; 584 | char *t; 585 | 586 | if ((s = getenv("AUTOSSH_PATH")) != NULL) 587 | ssh_path = s; 588 | 589 | if ((s = getenv("AUTOSSH_DEBUG")) != NULL) { 590 | #ifdef HAVE_LOG_PERROR 591 | syslog_perror = LOG_PERROR; 592 | #else 593 | syslog_perror = 0; 594 | logtype |= L_FILELOG; 595 | flog = stderr; 596 | #endif 597 | loglevel = LOG_DEBUG; 598 | } else if ((s = getenv("AUTOSSH_LOGLEVEL")) != NULL) { 599 | loglevel = strtoul(s, &t, 0); 600 | if (*s == '\0' || *t != '\0' || 601 | loglevel < LOG_EMERG || loglevel > LOG_DEBUG) 602 | xerrlog(LOG_ERR, "invalid log level \"%s\"", s); 603 | } 604 | 605 | if ((s = getenv("AUTOSSH_POLL")) != NULL) { 606 | poll_time = strtoul(s, &t, 0); 607 | if (*s == '\0' || poll_time == 0 || *t != '\0' ) 608 | xerrlog(LOG_ERR, 609 | "invalid poll time \"%s\"", s); 610 | if (poll_time <= 0) 611 | poll_time = POLL_TIME; 612 | } 613 | 614 | if ((s = getenv("AUTOSSH_FIRST_POLL")) != NULL) { 615 | first_poll_time = strtoul(s, &t, 0); 616 | if (*s == '\0' || first_poll_time == 0 || *t != '\0' ) 617 | xerrlog(LOG_ERR, 618 | "invalid first poll time \"%s\"", s); 619 | if (first_poll_time <= 0) 620 | first_poll_time = POLL_TIME; 621 | } else { 622 | /* 623 | * If first poll time not explicitly set, first 624 | * poll time should equal poll time. 625 | */ 626 | first_poll_time = poll_time; 627 | } 628 | 629 | if ((s = getenv("AUTOSSH_GATETIME")) != NULL) { 630 | gate_time = (double)strtol(s, &t, 0); 631 | if (*s == '\0' || gate_time < 0 || *t != '\0' ) 632 | xerrlog(LOG_ERR, "invalid gate time \"%s\"", s); 633 | } 634 | 635 | if ((s = getenv("AUTOSSH_MAXSTART")) != NULL) { 636 | max_start = (int)strtol(s, &t, 0); 637 | if (*s == '\0' || max_start < -1 || *t != '\0') 638 | xerrlog(LOG_ERR, "invalid max start number \"%s\"", s); 639 | } 640 | 641 | if ((s = getenv("AUTOSSH_MESSAGE")) != NULL) { 642 | if (*s != '\0') 643 | echo_message = s; 644 | if (strlen(echo_message) > MAX_MESSAGE) 645 | xerrlog(LOG_ERR, "echo message may only be %d bytes long", 646 | MAX_MESSAGE); 647 | } 648 | 649 | if ((s = getenv("AUTOSSH_PORT")) != NULL) 650 | if (*s != '\0') 651 | env_port = s; 652 | 653 | if ((s = getenv("AUTOSSH_MAXLIFETIME")) != NULL) { 654 | max_lifetime = (double)strtoul(s, &t, 0); 655 | if (*s == '\0' || *t != '\0' ) 656 | xerrlog(LOG_ERR, 657 | "invalid max lifetime \"%s\"", s); 658 | /* can't really be < 0, as converted as unsigned long */ 659 | if (max_lifetime <= 0 ) 660 | max_lifetime = MAX_LIFETIME; 661 | else { 662 | if (poll_time > max_lifetime) { 663 | errlog( LOG_INFO, 664 | "poll time is greater than lifetime," 665 | " dropping poll time to %.0f", max_lifetime ); 666 | poll_time = max_lifetime; 667 | } 668 | 669 | if (first_poll_time > max_lifetime) { 670 | errlog( LOG_INFO, 671 | "first poll time is greater than lifetime," 672 | " dropping first poll time to %.0f", max_lifetime ); 673 | first_poll_time = max_lifetime; 674 | } 675 | 676 | time(&pid_start_time); 677 | } 678 | } 679 | 680 | if ((s = getenv("AUTOSSH_PIDFILE")) != NULL) 681 | if (*s != '\0') 682 | pid_file_name = s; 683 | 684 | #if defined(__CYGWIN__) 685 | if ((s = getenv("AUTOSSH_NTSERVICE")) != NULL) { 686 | if (*s != '\0' && strncasecmp("yes", s, strlen(s)) == 0) { 687 | ntservice = 1; 688 | logtype = L_FILELOG; 689 | flog = stdout; 690 | } 691 | } 692 | #endif 693 | 694 | /* 695 | * Look for this after nt service; in case we may wish to log 696 | * elsewhere than stdout when running under cygrunsrv. 697 | */ 698 | if ((s = getenv("AUTOSSH_LOGFILE")) != NULL) { 699 | flog = fopen(s, "a"); 700 | if (!flog) 701 | xerrlog(LOG_ERR, "%s: %s", s, strerror(errno)); 702 | logtype = L_FILELOG; 703 | } 704 | 705 | return; 706 | } 707 | 708 | /* 709 | * Run ssh 710 | */ 711 | int 712 | ssh_run(int sock, char **av) 713 | { 714 | int retval; 715 | struct timeval tv; 716 | 717 | /* 718 | * There are much better things. and we all wait 719 | * for solaris to get /dev/random. 720 | */ 721 | gettimeofday(&tv, NULL); 722 | srandom(getpid() ^ tv.tv_usec ^ tv.tv_sec); 723 | 724 | set_exit_sig_handler(); 725 | 726 | while (max_start < 0 || start_count < max_start) { 727 | if (exceeded_lifetime()) 728 | return P_EXITOK; 729 | restart_ssh = 0; 730 | start_count++; 731 | grace_time(start_time); 732 | if (exit_signalled) { 733 | errlog(LOG_ERR, "signalled to exit"); 734 | return P_EXITERR; 735 | } 736 | time(&start_time); 737 | if (max_start < 0) 738 | errlog(LOG_INFO, "starting ssh (count %d)", 739 | start_count); 740 | else 741 | errlog(LOG_INFO, "starting ssh (count %d of %d)", 742 | start_count, max_start); 743 | cchild = fork(); 744 | switch (cchild) { 745 | case 0: 746 | errlog(LOG_DEBUG, "child of %d execing %s", 747 | getppid(), av[0]); 748 | execvp(av[0], av); 749 | errlog(LOG_ERR, "%s: %s", av[0], strerror(errno)); 750 | /* else can loop restarting! */ 751 | kill(getppid(), SIGTERM); 752 | _exit(1); 753 | break; 754 | case -1: 755 | cchild = 0; 756 | xerrlog(LOG_ERR, "fork: %s", strerror(errno)); 757 | break; 758 | default: 759 | errlog(LOG_INFO, "ssh child pid is %d", (int)cchild); 760 | set_sig_handlers(); 761 | retval = ssh_watch(sock); 762 | dolongjmp = 0; 763 | clear_alarm_timer(); 764 | unset_sig_handlers(); 765 | if (retval == P_EXITOK || retval == P_EXITERR) 766 | return retval; 767 | break; 768 | } 769 | } 770 | 771 | errlog(LOG_INFO, "max start count reached; exiting"); 772 | 773 | return P_EXITOK; 774 | } 775 | 776 | /* 777 | * Periodically test network connection. On signals, determine what 778 | * happened or what to do with child. Return as necessary for exit 779 | * or restart of child. 780 | */ 781 | int 782 | ssh_watch(int sock) 783 | { 784 | int r; 785 | int val; 786 | static int secs_left; 787 | int my_poll_time = first_poll_time; 788 | time_t now; 789 | double secs_to_shutdown; 790 | 791 | #if defined(HAVE_SETPROCTITLE) 792 | setproctitle("parent of %d (%d)", 793 | (int)cchild, start_count); 794 | #endif 795 | 796 | for (;;) { 797 | if (restart_ssh) { 798 | errlog(LOG_INFO, "signalled to kill and restart ssh"); 799 | ssh_kill(); 800 | return P_RESTART; 801 | } 802 | if ((val = sigsetjmp(jumpbuf, 1)) == 0) { 803 | 804 | errlog(LOG_DEBUG, "check on child %d", cchild); 805 | 806 | /* poll for expired child */ 807 | r = ssh_wait(WNOHANG); 808 | if (r != P_CONTINUE) { 809 | errlog(LOG_DEBUG, 810 | "expired child, returning %d", r); 811 | return r; 812 | } 813 | 814 | secs_left = clear_alarm_timer(); 815 | if (secs_left == 0) 816 | secs_left = my_poll_time; 817 | 818 | my_poll_time = poll_time; 819 | 820 | if (max_lifetime != 0) { 821 | time(&now); 822 | secs_to_shutdown = max_lifetime - difftime(now,pid_start_time); 823 | if (secs_to_shutdown < poll_time) 824 | secs_left = secs_to_shutdown; 825 | } 826 | 827 | errlog(LOG_DEBUG, 828 | "set alarm for %d secs", secs_left); 829 | 830 | dolongjmp = 1; 831 | alarm(secs_left); 832 | 833 | /* In case we were signalled while setting 834 | all this up */ 835 | if (exit_signalled) { 836 | errlog(LOG_INFO, "signalled to exit"); 837 | ssh_kill(); 838 | return P_EXITERR; 839 | } 840 | 841 | pause(); 842 | 843 | } else { 844 | 845 | switch(val) { 846 | case SIGINT: 847 | case SIGTERM: 848 | case SIGQUIT: 849 | case SIGABRT: 850 | errlog(LOG_INFO, 851 | "received signal to exit (%d)", val); 852 | ssh_kill(); 853 | return P_EXITERR; 854 | break; 855 | case SIGALRM: 856 | r = exceeded_lifetime(); 857 | errlog(LOG_DEBUG, 858 | "received SIGALRM (end-of-life %d)", r); 859 | 860 | /* exit if user-configured lifetime exceeded */ 861 | if (r) { 862 | ssh_kill(); 863 | return P_EXITOK; 864 | } 865 | 866 | if (writep && sock != -1 && 867 | !conn_test(sock, mhost, writep)) { 868 | errlog(LOG_INFO, 869 | "port down, restarting ssh"); 870 | ssh_kill(); 871 | return P_RESTART; 872 | } 873 | #ifdef TOUCH_PIDFILE 874 | /* 875 | * utimes() with a NULL time argument sets 876 | * file access and modification times to 877 | * the current time 878 | */ 879 | if (pid_file_name && 880 | utimes(pid_file_name, NULL) != 0) { 881 | errlog(LOG_ERR, 882 | "could not touch pid file: %s", 883 | strerror(errno)); 884 | } 885 | #endif 886 | break; 887 | default: 888 | break; 889 | } 890 | } 891 | } 892 | } 893 | 894 | /* 895 | * Clear any pending signal timer alarm and return the number of seconds 896 | * before it would have gone off. Return 0 if there was no alarm pending. 897 | */ 898 | unsigned int 899 | clear_alarm_timer(void) 900 | { 901 | unsigned int secs_left = alarm(0); 902 | errlog(LOG_DEBUG, 903 | "clear alarm timer (%d secs left)", secs_left); 904 | return secs_left; 905 | } 906 | 907 | /* 908 | * Checks to see if we have exceeded our time to live 909 | * Returns 1 if we have, 0 if we haven't 910 | */ 911 | int 912 | exceeded_lifetime(void) 913 | { 914 | time_t now; 915 | 916 | if (max_lifetime > 0 ) { 917 | time(&now); 918 | if (difftime(now, pid_start_time) >= max_lifetime ) { 919 | errlog(LOG_INFO, 920 | "exceeded maximum time to live, shutting down"); 921 | return 1; 922 | } 923 | } 924 | 925 | return 0; 926 | } 927 | 928 | /* 929 | * Wait on child: with options == WNOHANG, poll for 930 | * dead child, else if options == 0, then wait for 931 | * known dead child. 932 | * 933 | * If child was deliberately killed (TERM, INT, KILL), 934 | * the pass message back to restart. If child called exit(0) 935 | * or _exit(0), then pass message on return to give up (P_EXITOK). 936 | * Otherwise death was unnatural (or unintended), and pass 937 | * message back to restart (P_RESTART). 938 | * 939 | * However, if child died with exit(1) on first try, then 940 | * there is some startup error (anything from network 941 | * connection to authentication failure), so we exit. 942 | * If on a restart, however, we keep trying as it must 943 | * have worked once. This doesn't necessarily work if 944 | * the user did an interactive authentication, and then 945 | * isn't there on the restart to enter his password.... 946 | * But we can only know very little about what's going 947 | * on inside ssh. 948 | * 949 | * This is further complicated by the behaviour of 950 | * OpenSSH when sent SIGTERM (15). It is possible to 951 | * kill it before it installs the handler for that 952 | * signal, in which case it autossh behaves as above 953 | * and exits. But, in at least interactive use, it 954 | * appears that once the session is established ssh 955 | * installs a handler, and then when signalled (killed) 956 | * it exits with status 255. autossh does not know 957 | * it (ssh) was signalled, so restarts it. 958 | * 959 | */ 960 | int 961 | ssh_wait(int options) { 962 | 963 | int status; 964 | int evalue; 965 | time_t now; 966 | 967 | if (waitpid(cchild, &status, options) > 0) { 968 | if (WIFSIGNALED(status)) { 969 | switch(WTERMSIG(status)) { 970 | #if 0 971 | /* If someone kills the child, we assume 972 | it was hung up or something and they 973 | wished to restart it. Not entirely sure 974 | want to keep this behaviour or what 975 | signals it should apply to, therefore 976 | the #if 0. 977 | */ 978 | case SIGINT: 979 | case SIGTERM: 980 | case SIGKILL: 981 | /* someone meant it */ 982 | errlog(LOG_INFO, 983 | "ssh exited on signal %d; parent exiting", 984 | WTERMSIG(status)); 985 | return P_EXITERR; 986 | break; 987 | #endif 988 | default: 989 | /* continue on and restart */ 990 | errlog(LOG_INFO, 991 | "ssh exited on signal %d, restarting ssh", 992 | WTERMSIG(status)); 993 | return P_RESTART; 994 | break; 995 | } 996 | } else if (WIFEXITED(status)) { 997 | evalue = WEXITSTATUS(status); 998 | if (start_count == 1 && gate_time != 0) { 999 | /* 1000 | * If ssh exits too quickly, give up. 1001 | */ 1002 | time(&now); 1003 | if (difftime(now, start_time) <= gate_time) { 1004 | errlog(LOG_ERR, 1005 | "ssh exited prematurely " 1006 | "with status %d; %s exiting", 1007 | evalue, __progname); 1008 | return P_EXITERR; 1009 | } 1010 | } 1011 | switch(evalue) { 1012 | case 255: 1013 | /* 1014 | * we can get this on an initial 1015 | * connection if the connection itself 1016 | * is ok, but authentication fails. 1017 | * But there's no way to do this nicely: 1018 | * we don't have enough info from the 1019 | * ssh session and we get the same exit 1020 | * status from a dropped connection. 1021 | * Hence the gate_time above. 1022 | */ 1023 | errlog(LOG_INFO, 1024 | "ssh exited with error " 1025 | "status %d; restarting ssh", 1026 | evalue); 1027 | return P_RESTART; 1028 | break; 1029 | case 0: /* exited on success */ 1030 | #if defined(__CYGWIN__) 1031 | if (ntservice) 1032 | return P_RESTART; 1033 | #endif 1034 | errlog(LOG_INFO, 1035 | "ssh exited with status %d; %s exiting", 1036 | evalue, __progname); 1037 | return P_EXITOK; 1038 | case 2: 1039 | /* can exit with 2 with temporary issues 1040 | setting up tunnels */ 1041 | /* FALLTHROUGH */ 1042 | case 1: 1043 | /* 1044 | * the first time, it could be any of 1045 | * a number of errors; so we exit and let 1046 | * the user fix. But if been running ok 1047 | * already, then network may be down and 1048 | * then ssh fails exit(1) on the attempt 1049 | * to reconnect....so we try to restart. 1050 | */ 1051 | if (start_count > 1 || gate_time == 0) { 1052 | errlog(LOG_INFO, 1053 | "ssh exited with error " 1054 | "status %d; restarting ssh", 1055 | evalue); 1056 | return P_RESTART; 1057 | } 1058 | /* FALLTHROUGH */ 1059 | default: /* remote command error status */ 1060 | errlog(LOG_INFO, 1061 | "ssh exited with status %d; %s exiting", 1062 | evalue, __progname); 1063 | return P_EXITERR; 1064 | break; 1065 | } 1066 | } 1067 | } 1068 | 1069 | /* do nothing */ 1070 | return P_CONTINUE; 1071 | } 1072 | 1073 | /* 1074 | * Kill ssh child. This can be overly aggressive, and 1075 | * result in kill KILL before TERM has time to take.... 1076 | * Perhaps just use TERM? 1077 | */ 1078 | void 1079 | ssh_kill(void) 1080 | { 1081 | int w; 1082 | int status; 1083 | 1084 | if (cchild) { 1085 | /* overkill */ 1086 | kill(cchild, SIGTERM); 1087 | /* if (kill(cchild, 0) != -1) 1088 | + kill(cchild, SIGKILL); 1089 | */ 1090 | do { 1091 | errno = 0; 1092 | w = waitpid(cchild, &status, 0); 1093 | } while (w < 0 && errno == EINTR ); 1094 | 1095 | if (w <= 0) { 1096 | errlog(LOG_ERR, 1097 | "waitpid() not successful: %s", 1098 | strerror(errno)); 1099 | } 1100 | } 1101 | return; 1102 | } 1103 | 1104 | /* 1105 | * Try to prevent rapid-fire restarts on such things 1106 | * as connection refused. Back off and try more slowly. 1107 | * Calculate a grace period to wait based time between 1108 | * now and the last restart and the number of tries 1109 | * in a row that have had less than the poll_time 1110 | * between them. 1111 | * 1112 | * Questions: 1113 | * - should it back off faster? slower? 1114 | */ 1115 | void 1116 | grace_time(time_t last_start) 1117 | { 1118 | int n; 1119 | double t; 1120 | int interval; 1121 | time_t now; 1122 | static int tries; 1123 | 1124 | double min_time; 1125 | 1126 | /* 1127 | * Minimum time we have to stay up to avoid backoff 1128 | * behaviour. With default poll_time this is 60 secs. 1129 | * This may be too complicated. 1130 | */ 1131 | min_time = (double)(poll_time / 10); 1132 | if (min_time < 10) min_time = 10; 1133 | 1134 | time(&now); 1135 | if (difftime(now, last_start) >= min_time) 1136 | tries = 0; 1137 | else 1138 | tries++; 1139 | 1140 | errlog(LOG_DEBUG, 1141 | "checking for grace period, tries = %d", tries); 1142 | 1143 | if (tries > N_FAST_TRIES) { 1144 | t = (double)(tries - N_FAST_TRIES); 1145 | n = (int)((poll_time / 100.0) * (t * (t/3))); 1146 | interval = (n > poll_time) ? poll_time : n; 1147 | if (interval) { 1148 | errlog(LOG_DEBUG, 1149 | "sleeping for grace time %d secs", interval); 1150 | sleep(interval); 1151 | } 1152 | } 1153 | return; 1154 | } 1155 | 1156 | void 1157 | set_exit_sig_handler() 1158 | { 1159 | struct sigaction act; 1160 | 1161 | memset(&act, 0, sizeof(act)); 1162 | act.sa_handler = sig_catch; 1163 | sigemptyset(&act.sa_mask); 1164 | act.sa_flags = 0; 1165 | 1166 | sigaction(SIGTERM, &act, NULL); 1167 | sigaction(SIGINT, &act, NULL); 1168 | } 1169 | 1170 | void 1171 | set_sig_handlers(void) 1172 | { 1173 | struct sigaction act; 1174 | sigset_t blockmask; 1175 | 1176 | memset(&act, 0, sizeof(act)); 1177 | act.sa_handler = sig_catch; 1178 | act.sa_flags = 0; 1179 | 1180 | /* create mask to ensure sig_catch() processes one signal at-a-time */ 1181 | sigemptyset(&blockmask); 1182 | sigaddset(&blockmask, SIGTERM); 1183 | sigaddset(&blockmask, SIGINT); 1184 | sigaddset(&blockmask, SIGHUP); 1185 | sigaddset(&blockmask, SIGUSR1); 1186 | sigaddset(&blockmask, SIGUSR2); 1187 | sigaddset(&blockmask, SIGCHLD); 1188 | sigaddset(&blockmask, SIGALRM); 1189 | sigaddset(&blockmask, SIGPIPE); 1190 | act.sa_mask = blockmask; 1191 | 1192 | sigaction(SIGTERM, &act, NULL); 1193 | sigaction(SIGINT, &act, NULL); 1194 | sigaction(SIGHUP, &act, NULL); 1195 | sigaction(SIGUSR1, &act, NULL); 1196 | sigaction(SIGUSR2, &act, NULL); 1197 | sigaction(SIGCHLD, &act, NULL); 1198 | 1199 | act.sa_flags |= SA_RESTART; 1200 | sigaction(SIGALRM, &act, NULL); 1201 | 1202 | act.sa_handler = SIG_IGN; 1203 | act.sa_flags = 0; 1204 | sigaction(SIGPIPE, &act, NULL); 1205 | } 1206 | 1207 | void 1208 | unset_sig_handlers(void) 1209 | { 1210 | struct sigaction act; 1211 | 1212 | memset(&act, 0, sizeof(act)); 1213 | act.sa_handler = SIG_DFL; 1214 | sigemptyset(&act.sa_mask); 1215 | act.sa_flags = 0; 1216 | 1217 | /* We don't reset SIGTERM, as we want the 1218 | handler to persist in the run_ssh() loop */ 1219 | /* This seems a little hidden down in here... */ 1220 | /* sigaction(SIGTERM, &act, NULL); */ 1221 | /* sigaction(SIGINT, &act, NULL); */ 1222 | sigaction(SIGHUP, &act, NULL); 1223 | sigaction(SIGUSR1, &act, NULL); 1224 | sigaction(SIGUSR2, &act, NULL); 1225 | sigaction(SIGCHLD, &act, NULL); 1226 | sigaction(SIGALRM, &act, NULL); 1227 | sigaction(SIGPIPE, &act, NULL); 1228 | } 1229 | 1230 | /* 1231 | * If we're primed, longjump back. 1232 | */ 1233 | void 1234 | sig_catch(int sig) 1235 | { 1236 | if (sig == SIGUSR1) 1237 | restart_ssh = 1; 1238 | else if (sig == SIGTERM || sig == SIGINT) 1239 | exit_signalled = 1; 1240 | if (dolongjmp) { 1241 | dolongjmp = 0; 1242 | siglongjmp(jumpbuf, sig); 1243 | } 1244 | return; 1245 | } 1246 | 1247 | /* 1248 | * Test the connection monitor loop can pass traffic, and that 1249 | * we get back what we send. This needs the most testing. 1250 | */ 1251 | int 1252 | conn_test(int sock, char *host, char *write_port) 1253 | { 1254 | int rval; /* default return value (failure) */ 1255 | int tries; /* message attempts */ 1256 | int send_error; /* did it go/come ok? */ 1257 | struct pollfd pfd[2]; /* poll fds */ 1258 | int ntopoll; /* # fds to poll */ 1259 | int rd, wd; /* read and write descriptors */ 1260 | long id; /* for a random number */ 1261 | 1262 | struct utsname uts; 1263 | char wbuf[64+sizeof(uts.nodename)+MAX_MESSAGE]; 1264 | char rbuf[sizeof(wbuf)]; 1265 | 1266 | wd = -1; /* default desc. values */ 1267 | rd = -1; 1268 | rval = 0; /* default return value : no success */ 1269 | tries = 0; /* number of attempts */ 1270 | 1271 | uts.nodename[0] = '\0'; 1272 | (void)uname(&uts); 1273 | id = random(); 1274 | 1275 | if (dolongjmp != 0) 1276 | errlog(LOG_ERR, "conn_test(): error: dolongjmp != 0"); 1277 | 1278 | /* set up write connection */ 1279 | if ((wd = conn_remote(host, write_port)) == -1) 1280 | return 0; 1281 | 1282 | pfd[1].fd = wd; 1283 | pfd[1].events = POLLOUT; 1284 | 1285 | while (tries++ < MAX_CONN_TRIES) { 1286 | 1287 | if (tries >= MAX_CONN_TRIES) { 1288 | errlog(LOG_DEBUG, 1289 | "tried connection %d times and failed", 1290 | tries); 1291 | break; /* give up */ 1292 | } 1293 | 1294 | /* close read socket if we're coming around again */ 1295 | if (sock != NO_RD_SOCK && rd != -1) { 1296 | shutdown(rd, SHUT_RDWR); 1297 | close(rd); 1298 | rd = -1; 1299 | } 1300 | 1301 | /* 1302 | * Some data to send: something that is identifiable 1303 | * as coming from ourselves. Any user can still trash 1304 | * our listening port. We'd really like to be able to 1305 | * connect and accept connections from certain pids 1306 | * (ourself, our children). 1307 | */ 1308 | if (snprintf(wbuf, sizeof(wbuf), 1309 | "%s %s %d %ld %s\r\n", uts.nodename, __progname, 1310 | (int)getpid(), id, echo_message) >= sizeof(wbuf)) 1311 | xerrlog(LOG_ERR, "conn_test: buffer overflow"); 1312 | memset(rbuf, '\0', sizeof(rbuf)); 1313 | 1314 | if (sock != NO_RD_SOCK) { 1315 | /* 1316 | * If doing loop of connections, then accept() the read 1317 | * connection and use both read and write fds for 1318 | * poll(). Replace poll fd with accepted connection fd. 1319 | */ 1320 | rd = conn_poll_for_accept(sock, pfd); 1321 | if (rd < 0) 1322 | break; /* give up */ 1323 | pfd[0].fd = rd; 1324 | pfd[0].events = POLLIN; 1325 | ntopoll = 2; 1326 | } else { 1327 | /* 1328 | * For talking to echo service, shift over and 1329 | * just use the one descriptor for both read and 1330 | * write. 1331 | */ 1332 | pfd[0].fd = wd; 1333 | pfd[0].events = POLLIN|POLLOUT; 1334 | ntopoll = 1; 1335 | } 1336 | 1337 | send_error = conn_send_and_receive(rbuf, wbuf, 1338 | strlen(wbuf), pfd, ntopoll); 1339 | if (send_error == 0) { 1340 | /* we try again if received does not match sent */ 1341 | if (strcmp(rbuf, wbuf) == 0) { 1342 | errlog(LOG_DEBUG, "connection ok"); 1343 | rval = 1; /* success */ 1344 | break; /* out of here */ 1345 | } else { 1346 | errlog(LOG_DEBUG, 1347 | "not what I sent: \"%s\" : \"%s\"", 1348 | wbuf, rbuf); 1349 | /* loop again */ 1350 | } 1351 | } else if (send_error == 1) { 1352 | errlog(LOG_DEBUG, 1353 | "timeout on io poll, looping to accept again"); 1354 | } else { 1355 | errlog(LOG_DEBUG, "error on poll: %s", 1356 | strerror(errno)); 1357 | break; /* hard error, we're out of here */ 1358 | } 1359 | } 1360 | 1361 | shutdown(wd, SHUT_RDWR); 1362 | close(wd); 1363 | if (sock != NO_RD_SOCK) { 1364 | shutdown(rd, SHUT_RDWR); 1365 | close(rd); 1366 | } 1367 | 1368 | return rval; 1369 | } 1370 | 1371 | /* 1372 | * poll for accept(), return file descriptor for accepted connection, 1373 | * or -1 for error. 1374 | */ 1375 | int 1376 | conn_poll_for_accept(int sock, struct pollfd *pfd) 1377 | { 1378 | int rd; /* new descriptor on accept */ 1379 | int timeo_polla; /* for accept() */ 1380 | struct sockaddr cliaddr; 1381 | socklen_t len; /* listen socket info */ 1382 | 1383 | rd = 0; 1384 | timeo_polla = net_timeout; /* timeout value for accept() */ 1385 | len = sizeof(struct sockaddr); 1386 | 1387 | /* 1388 | * first we're going to poll for accept() 1389 | */ 1390 | pfd[0].fd = sock; 1391 | pfd[0].events = POLLIN; 1392 | 1393 | for (;;) { 1394 | switch(poll(pfd, 1, timeo_polla)) { 1395 | case 0: 1396 | errlog(LOG_INFO, 1397 | "timeout polling to accept read connection"); 1398 | return -1; 1399 | case -1: 1400 | errlog(LOG_ERR, 1401 | "error polling to accept read connection: %s", 1402 | strerror(errno)); 1403 | return -1; 1404 | default: 1405 | break; 1406 | } 1407 | 1408 | if (pfd[0].revents & POLLIN) { 1409 | rd = accept(sock, &cliaddr, &len); 1410 | if (rd == -1) { 1411 | errlog(LOG_ERR, 1412 | "error accepting read connection: %s", 1413 | strerror(errno)); 1414 | return -1; 1415 | } 1416 | break; 1417 | } 1418 | break; 1419 | } 1420 | 1421 | return rd; 1422 | } 1423 | 1424 | /* 1425 | * Send from wp and receive into rp. 1426 | * 1 = try again 1427 | * 0 = ok 1428 | * -1 = error 1429 | */ 1430 | int 1431 | conn_send_and_receive(char *rp, char *wp, size_t len, 1432 | struct pollfd *pfd, int ntopoll) 1433 | { 1434 | ssize_t nwrite, nread; 1435 | size_t rleft, wleft; 1436 | int timeo_pollio; 1437 | int ird, iwr; 1438 | int loops = 0; 1439 | 1440 | timeo_pollio = net_timeout; /* timeout value for net io */ 1441 | rleft = wleft = len; 1442 | 1443 | /* 1444 | * If two fds, one is to read, one is to write, 1445 | * else read and write on the same fd. 1446 | */ 1447 | if (ntopoll == 2) { 1448 | ird = 0; 1449 | iwr = 1; 1450 | } else { 1451 | iwr = ird = 0; 1452 | } 1453 | 1454 | 1455 | /* 1456 | * Now, send and receive. When we're doing the loop thing, we stop 1457 | * polling for write() once we've sent the whole message. 1458 | */ 1459 | while (rleft > 0) { 1460 | 1461 | switch(poll(pfd, ntopoll, timeo_pollio)) { 1462 | case 0: 1463 | return 1; 1464 | break; 1465 | case -1: 1466 | return -1; 1467 | break; 1468 | default: 1469 | break; 1470 | } 1471 | 1472 | if (wleft && pfd[iwr].revents & POLLOUT) { 1473 | while (wleft > 0) { 1474 | nwrite = write(pfd[iwr].fd, wp, wleft); 1475 | if (nwrite == 0) { 1476 | wleft = 0; /* EOF */ 1477 | break; 1478 | } else if (nwrite == -1) { 1479 | if (errno == EINTR || errno == EAGAIN) 1480 | break; 1481 | else 1482 | return -1; 1483 | } 1484 | wleft -= nwrite; 1485 | wp += nwrite; 1486 | } 1487 | /* if complete, turn off polling for write */ 1488 | if (wleft == 0) { 1489 | ntopoll = 1; 1490 | /* 1491 | * if we are reading and writing to the 1492 | * same fd then we must clear the write bit 1493 | * so that poll doesn't loop tight. 1494 | */ 1495 | if (iwr == ird) 1496 | pfd[ird].events = POLLIN; 1497 | } 1498 | } 1499 | 1500 | if (pfd[ird].revents & POLLIN || pfd[ird].revents & POLLHUP) { 1501 | while (rleft > 0) { 1502 | nread = read(pfd[ird].fd, rp, rleft); 1503 | if (nread == 0) { 1504 | rleft = 0; /* EOF */ 1505 | break; 1506 | } else if (nread == -1) { 1507 | if (errno == EINTR || errno == EAGAIN) 1508 | break; 1509 | else 1510 | return -1; 1511 | } 1512 | rleft -= nread; 1513 | rp += nread; 1514 | } 1515 | } 1516 | 1517 | /* 1518 | * we can run into situations where the data gets black-holed 1519 | * and poll() can't tell. And then we loop fast and 1520 | * things go nuts. So if we do that, give up after a while. 1521 | */ 1522 | if (loops++ > 5) { 1523 | sleep(1); 1524 | if (loops > 10) { 1525 | errlog(LOG_INFO, 1526 | "too many loops without data"); 1527 | return -1; 1528 | } 1529 | } 1530 | } 1531 | 1532 | return 0; 1533 | } 1534 | 1535 | #ifndef HAVE_ADDRINFO 1536 | 1537 | /* 1538 | * Convert names to addresses, setup for connection. 1539 | */ 1540 | void 1541 | conn_addr(char *host, char *port, struct sockaddr_in *resp) 1542 | { 1543 | struct hostent *h; 1544 | 1545 | if ((h = gethostbyname(host)) == NULL) 1546 | xerrlog(LOG_ERR, "%s: %s", host, hstrerror(h_errno)); 1547 | 1548 | resp->sin_family = h->h_addrtype; 1549 | resp->sin_port = htons(atoi(port)); 1550 | resp->sin_addr = *((struct in_addr *) h->h_addr_list[0]); 1551 | 1552 | return; 1553 | } 1554 | 1555 | /* 1556 | * Open connection we're writing to. 1557 | */ 1558 | int 1559 | conn_remote(char *host, char *port) 1560 | { 1561 | int sock; 1562 | static struct sockaddr_in res = {AF_UNSPEC}; 1563 | 1564 | /* Cache the address info */ 1565 | if (res.sin_family == AF_UNSPEC) 1566 | conn_addr(host, port, &res); 1567 | 1568 | if ((sock = socket(res.sin_family, SOCK_STREAM, 0)) == -1) 1569 | xerrlog(LOG_ERR, "socket: %s", strerror(errno)); 1570 | 1571 | if (connect(sock, (struct sockaddr *) &res, sizeof(res)) == -1) { 1572 | errlog(LOG_INFO, "%s:%s: %s", host, port, strerror(errno)); 1573 | close(sock); 1574 | return -1; 1575 | } 1576 | 1577 | return sock; 1578 | } 1579 | 1580 | /* 1581 | * Returns a socket listening on a local port, bound to specified source 1582 | * address. Errors in binding to the local listening port are fatal. 1583 | */ 1584 | int 1585 | conn_listen(char *host, char *port) 1586 | { 1587 | int sock; 1588 | struct sockaddr_in res; 1589 | int on = 1; 1590 | 1591 | /* 1592 | * Unlike conn_remote, we don't need to cache the 1593 | * info; we're only calling once at start. All errors 1594 | * here are fatal. 1595 | */ 1596 | conn_addr(host, port, &res); 1597 | 1598 | if ((sock = socket(res.sin_family, SOCK_STREAM, 0)) == -1) 1599 | xerrlog(LOG_ERR, "socket: %s", strerror(errno)); 1600 | 1601 | if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, 1602 | (char *) &on, sizeof on) != 0) { 1603 | xerrlog(LOG_ERR, "setsockopt: %s", strerror(errno)); 1604 | } 1605 | 1606 | if (bind(sock, (struct sockaddr *)&res, sizeof(res)) == -1) 1607 | xerrlog(LOG_ERR, "bind on %s:%s: %s", 1608 | host, port, strerror(errno)); 1609 | 1610 | if (listen(sock, 1) < 0) 1611 | xerrlog(LOG_ERR, "listen: %s", strerror(errno)); 1612 | 1613 | return sock; 1614 | } 1615 | 1616 | #else /* HAVE_ADDRINFO */ 1617 | 1618 | /* 1619 | * Convert names to addresses, setup for connection. 1620 | */ 1621 | void 1622 | conn_addr(char *host, char *port, struct addrinfo **resp) 1623 | { 1624 | int family = AF_INET; 1625 | struct addrinfo hints; 1626 | int error; 1627 | 1628 | memset(&hints, 0, sizeof(struct addrinfo)); 1629 | hints.ai_family = family; 1630 | hints.ai_socktype = SOCK_STREAM; 1631 | hints.ai_protocol = IPPROTO_TCP; 1632 | 1633 | /* Allow nodename to be null */ 1634 | hints.ai_flags |= AI_PASSIVE; 1635 | 1636 | /* 1637 | * In the case of binding to a wildcard address 1638 | * default to binding to an ipv4 address. 1639 | */ 1640 | if (host == NULL && hints.ai_family == AF_UNSPEC) 1641 | hints.ai_family = AF_INET; 1642 | 1643 | if ((error = getaddrinfo(host, port, &hints, resp))) 1644 | xerrlog(LOG_ERR, "%s", gai_strerror(error)); 1645 | 1646 | return; 1647 | } 1648 | 1649 | /* 1650 | * Open connection we're writing to. 1651 | */ 1652 | int 1653 | conn_remote(char *host, char *port) 1654 | { 1655 | int sock; 1656 | static struct addrinfo *res; 1657 | 1658 | /* Cache the address info */ 1659 | if (!res) 1660 | conn_addr(host, port, &res); 1661 | 1662 | if ((sock = socket(res->ai_family, res->ai_socktype, 1663 | res->ai_protocol)) == -1) 1664 | xerrlog(LOG_ERR, "socket: %s", strerror(errno)); 1665 | 1666 | if (connect(sock, res->ai_addr, res->ai_addrlen) == -1) { 1667 | errlog(LOG_INFO, "%s:%s: %s", host, port, strerror(errno)); 1668 | close(sock); 1669 | return -1; 1670 | } 1671 | 1672 | return sock; 1673 | } 1674 | 1675 | /* 1676 | * Returns a socket listening on a local port, bound to specified source 1677 | * address. Errors in binding to the local listening port are fatal. 1678 | */ 1679 | int 1680 | conn_listen(char *host, char *port) 1681 | { 1682 | int sock; 1683 | struct addrinfo *res; 1684 | int on = 1; 1685 | 1686 | /* 1687 | * Unlike conn_remote, we don't need to cache the 1688 | * info; we're only calling once at start. All errors 1689 | * here are fatal. 1690 | */ 1691 | conn_addr(host, port, &res); 1692 | 1693 | if ((sock = socket(res->ai_family, res->ai_socktype, 1694 | res->ai_protocol)) == -1) 1695 | xerrlog(LOG_ERR, "socket: %s", strerror(errno)); 1696 | 1697 | if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, 1698 | (char *) &on, sizeof on) != 0) { 1699 | xerrlog(LOG_ERR, "setsockopt: %s", strerror(errno)); 1700 | } 1701 | 1702 | if (bind(sock, (struct sockaddr *)res->ai_addr, 1703 | res->ai_addrlen) == -1) 1704 | xerrlog(LOG_ERR, "bind on %s:%s: %s", 1705 | host, port, strerror(errno)); 1706 | 1707 | if (listen(sock, 1) < 0) 1708 | xerrlog(LOG_ERR, "listen: %s", strerror(errno)); 1709 | 1710 | freeaddrinfo(res); 1711 | 1712 | return sock; 1713 | } 1714 | #endif /* ! HAVE_ADDRINFO */ 1715 | 1716 | /* 1717 | * On OpenBSD _exit() calls atexit() registered functions. 1718 | * Solaris has a function, _exithandle(), you can call 1719 | * before _exit(). 1720 | */ 1721 | void 1722 | unlink_pid_file(void) 1723 | { 1724 | if (pid_file_created) 1725 | (void)unlink(pid_file_name); 1726 | pid_file_created = 0; 1727 | } 1728 | 1729 | /* 1730 | * Nicely formatted time string for logging 1731 | */ 1732 | char * 1733 | timestr(void) 1734 | { 1735 | static char timestr[32]; 1736 | time_t now; 1737 | struct tm *tm; 1738 | 1739 | (void)time(&now); 1740 | tm = localtime(&now); 1741 | (void)strftime(timestr, sizeof(timestr), 1742 | "%Y/%m/%d %H:%M:%S", tm); 1743 | 1744 | return timestr; 1745 | } 1746 | 1747 | /* 1748 | * Log errors. 1749 | */ 1750 | void 1751 | errlog(int level, char *fmt, ...) 1752 | { 1753 | va_list ap; 1754 | 1755 | va_start(ap, fmt); 1756 | doerrlog(level, fmt, ap); 1757 | va_end(ap); 1758 | } 1759 | 1760 | /* 1761 | * Log and then exit with error status. 1762 | */ 1763 | void 1764 | xerrlog(int level, char *fmt, ...) 1765 | { 1766 | va_list ap; 1767 | 1768 | va_start(ap, fmt); 1769 | doerrlog(level, fmt, ap); 1770 | va_end(ap); 1771 | 1772 | ssh_kill(); 1773 | unlink_pid_file(); 1774 | _exit(1); 1775 | } 1776 | 1777 | /* 1778 | * Log to file and/or syslog as directed. We want different 1779 | * behaviour before syslog has been called and set up; and 1780 | * different behaviour before we fork for ssh: errors before 1781 | * that point result in exit. 1782 | */ 1783 | void 1784 | doerrlog(int level, char *fmt, va_list ap) 1785 | { 1786 | FILE *fl; 1787 | #ifndef HAVE_VSYSLOG 1788 | char logbuf[1024]; 1789 | #endif 1790 | 1791 | fl = flog; /* only set per-call */ 1792 | 1793 | if (loglevel >= level) { 1794 | if (logtype & L_SYSLOG) { 1795 | #ifndef HAVE_VSYSLOG 1796 | (void)vsnprintf(logbuf, sizeof(logbuf), fmt, ap); 1797 | syslog(level, logbuf); 1798 | #else 1799 | vsyslog(level, fmt, ap); 1800 | #endif 1801 | } else if (!fl) { 1802 | /* 1803 | * if we're not using syslog, and we 1804 | * don't have a log file, then use 1805 | * stderr. 1806 | */ 1807 | fl = stderr; 1808 | } 1809 | if ((logtype & L_FILELOG) && fl) { 1810 | fprintf(fl, 1811 | "%s %s[%d]: ", timestr(), 1812 | __progname, (int)getpid()); 1813 | vfprintf(fl, fmt, ap); 1814 | fprintf(fl, "\n"); 1815 | fflush(fl); 1816 | } 1817 | } 1818 | return; 1819 | } 1820 | 1821 | /* END */ 1822 | --------------------------------------------------------------------------------