On Wed, 27 Sep 2000, will trillich wrote:

> hi. i have no clue about all this fancy stuff. sounds
> delightfully cool. if you get it straightened out,
> PLEASE post a 'SOLVED' message so that the rest of us
> dunces (speaking for what i hope is a large group and
> not just me) can learn from your experience...
> 
> by the way -- HOW did you set up those tunnels?
> 
> what package, what command, what script?
> 

OK I'm a  bit hesitant about posting my solution since I
figure  there's probably  a  simpler  and better  way,  but here  goes.
Please note that I'm only doing this because it's the only way
I know for e.g. reading news on my school's news server, given that my
ISP is LargeFacelessCorporation.com and not my school's modem pool. 
I'm not doing it just because it's a neat trick or whatever. Peace.

First, I put the following two lines in the "iface eth0" section of my
/etc/network/interfaces.  (I talk  to  the world  through an  ethernet
card, if this  is not the way  you do things you'll have  to find some
other way, like your /etc/ppp/ip-up script or whatever):

     up /etc/init.d/tcp-pipes start 
     down /etc/init.d/tcp-pipes stop

The "tcp-pipes" script is attached. The way I do it, this 
script runs a command  on the remote machine. The command does
nothing: it just  hangs. I've jimmied things on the  other end so that
only one  instance of  this command (there's  actually three  of them,
they're called "imapl, newsl, and  maill" if I remember right) can run
at a time. Otherwise, I'd eventually have a million of these things running on
the remote  machine and  the sysadmins at  school would hate  me. I've
done this with a C program (attached) which reads a PID from a file, nukes the
process, writes its PID to the same file, and hangs forever. You can maybe
do the same thing with a shell script. 

Uh, I think that's all. Then I just tell my mail and news clients to 
talk to,  say, port 6143 on the  localhost instead of port  143 on the
remote host. Hope this helps. -chris

#! /bin/sh
#
# Port forwarding to servers which would otherwise refuse connections from us
#

echo $*
NAME=`basename $0`
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
SSH=/usr/bin/ssh2 # careful! there might be an ssh in the current dir
SSHBASENAME=`basename ${SSH}`
SSHFLAGS="-f -x"
HOST=cascade.cs.ubc.ca
USER=majewski
PRG=loop

start()
{
    LOCALPORT=$1
    DEST=$2
    REMOTEPORT=$3
    PIPE=$4
    SSHARGS="${SSHFLAGS} -l ${USER} -L ${LOCALPORT}:${DEST}:${REMOTEPORT} 
${HOST} ${PIPE}l"
    PIDFILE=/var/run/${PIPE}-pipe.pid
#    echo -n "Starting ${PIPE}: "
        if [ -e ${PIDFILE} ]; then
                rm ${PIDFILE}
        fi
    start-stop-daemon --start --verbose  --background --make-pidfile --pidfile 
${PIDFILE} --exec ${SSH} -- ${SSHARGS}
    if [ $? -eq 0 ]; then
        fixpid ${PIPE} ${PIDFILE}
    fi
#    echo "${PIPE}."
}

# Wait for the PIDFILE to get the initial PID of the ssh process
# Wait for the ssh process to exec() to a different PID
# Put the new PID in the PIDFILE
fixpid()
{
    PIPE=$1
    PIDFILE=$2
    PID=
    NEWPID=
    COUNT=1
    MAXCOUNT=10
    GOTCHA=false
    while [ "${PID}" = "" ]; do
        if [ ${COUNT} -gt ${MAXCOUNT} ]; then
            logger "${NAME}: initial PID not found for ${PIPE}"
            logger "${NAME}: continuing anyway..."
            break
        fi
        if [ -e ${PIDFILE} ]; then
                PID=`cat ${PIDFILE}`
        fi
        COUNT=`expr ${COUNT} + 1`
        sleep 1
    done
    # sleep until the process with the old PID goes away
    # can't use 'wait' because the ssh process is not our child
    COUNT=1
    while ps h -o pid -p ${PID} >> /dev/null; do
        if [ ${COUNT} -gt ${MAXCOUNT} ]; then
            logger "${NAME}: new PID not found for ${PIPE}"
            logger "${NAME}: continuing anyway..."
            break
        fi
        COUNT=`expr ${COUNT} + 1`
        GOTCHA=true
        sleep 1
    done
    NEWPID=`ps h -C ${SSHBASENAME} | grep ${PIPE} | awk '{print $1}'`
    if [ "${NEWPID}" = "" ]; then
        logger "${NAME}: Empty PID, you may have to stop ${PIPE} manually later 
on"
    else
        echo ${NEWPID} > ${PIDFILE}
    fi
}

stop()
{
    PIPE=$1
    PID=
#    echo -n "Stopping ${PIPE}: "
    PIDFILE=/var/run/${PIPE}-pipe.pid
    start-stop-daemon --stop --verbose --pidfile ${PIDFILE}
    if [ $? -ne 0 ]; then
        PID=`ps h -C ${SSHBASENAME} | grep ${PIPE} | awk '{print $1}'`
        if [ "${PID}" != "" ]; then
            echo "Killing ${PIPE} pipe by brute force"
            logger "${NAME}: Killing ${PIPE} pipe by brute force"
            # ask process to die honorably
            kill -TERM ${PID}
            # coup de grace if necessary
            PID=`ps h -C ${SSHBASENAME} | grep ${PIPE} | awk '{print $1}'`
            if [ "${PID}" != "" ]; then
                kill -KILL ${PID}
            fi
        else
            logger "${NAME}: Couldn't find PID for ${PIPE}, not killing"
        fi
    fi
    rm -f ${PIDFILE}
#    echo "${PIPE}."
}

startImap()
{
        start 6143 imap.cs.ubc.ca 143 imap
}

startNews()
{
        start 6119 news.cs.ubc.ca 119 news 
}

startMail()
{
        start 6025 mailhost.cs.ubc.ca 25 mail 
}

startAll()
{
            echo "Starting ${NAME}: "
            start 6143 imap.cs.ubc.ca 143 imap
            start 6119 news.cs.ubc.ca 119 news
            start 6025 mailhost.cs.ubc.ca 25 mail
            echo "${NAME}."
}


stopAll()
{
            echo "Stopping ${NAME}: "
            stop imap
            stop news
            stop mail
            echo "${NAME}."
}

case "$1" in
        imap)
        startImap
        ;;
        news)
        startNews
        ;;
        mail)
        startMail
        ;;      
  start)
    startAll
    ;;
  stop)
    stopAll
    ;;
  restart)
    stopAll
    startAll
    ;;
  #reload)
        #
        #       If the daemon can reload its config files on the fly
        #       for example by sending it SIGHUP, do it here.
        #
        #       If the daemon responds to changes in its config file
        #       directly anyway, make this a do-nothing entry.
        #
        # echo "Reloading $DESC configuration files."
        # start-stop-daemon --stop --signal 1 --quiet --pidfile \
        #       /var/run/$NAME.pid --exec $DAEMON
  #;;
#    restart|force-reload)
#       #
#       #       If the "reload" option is implemented, move the "force-reload"
#       #       option to the "reload" entry above. If not, "force-reload" is
#       #       just the same as "restart".
#       #
#       echo -n "Restarting $DESC: "
#       start-stop-daemon --stop --quiet --pidfile \
#               /var/run/$NAME.pid --exec $DAEMON
#       sleep 1
#       start-stop-daemon --start --quiet --pidfile \
#               /var/run/$NAME.pid --exec $DAEMON
#       echo "$NAME."
#       ;;
  *)
        N=/etc/init.d/${NAME}
        # echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2
        # echo "Usage: $N {start|stop|restart|force-reload}" >&2
        echo "Usage: $N {start|stop}" >&2
        exit 1
        ;;
esac

exit 0
#include <stdio.h>
#include <unistd.h>
#include <strings.h>
#include <sys/types.h>
#include <signal.h>
#include <stdlib.h>
#include <malloc.h>
#include <libgen.h>

int
main(int arc, const char** argv)
{
  const char* home = getenv("HOME");
  char* fullName = (char *)malloc(1000*sizeof(char));
  char* name = NULL;
  pid_t pid = getpid();
  pid_t previousPid = 0;
  char* fileName = (char*)malloc(1000*sizeof(char));
  FILE* file = NULL;
  int _signal = 9;

  strcpy(fullName, argv[0]);
  name = basename(fullName);
  fileName[0] = (char)0;
  strcat(fileName, home);
  strcat(fileName, "/var/run/");
  strcat(fileName, name);
  strcat(fileName, ".pid");
  file = fopen(fileName, "r");
  if (file == NULL) {
    fprintf(stderr, "Failed to open file '%s' for reading\n", fileName);
    exit(1);
  }
  fscanf(file, "%d", &previousPid);
  if (previousPid != pid) {
    if (previousPid > 0) {
      /* There is a race condition here. If we kill the old instance
	 before overwriting its PID, a third instance could try to kill 
	 a nonexistent process. If on the other hand we overwrite
	 the PID first, a third instance could kill us before we have 
	 a chance to kill the old instance. 
      */
      int result = kill(previousPid, _signal);
      if (result != 0) {
	fprintf(stderr, 
		"Failed to kill PID '%d' with signal '%d'\n"
		"Continuing anyway...\n",
		previousPid, 
		_signal);
      }
    }
  } else {
    fprintf(stderr,
	    "Suicide attempt thwarted\n");
    exit(1);
  }
  {
    int result;
    fclose(file);
    file = fopen(fileName, "w");
    if (file == NULL) {
      fprintf(stderr, "Failed to open file '%s' for writing\n", fileName);
      exit(1);
    }
    fprintf(file, "%d", pid);
    fflush(file);
    fclose(file);
    result = pause();
    fprintf(stderr, "pause() returned value '%d'\n", result);
    return 0;
  }
}

Reply via email to