[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: IP TUNNEL / was Re: doesn't anybody use tunnelling / vpn?



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 to: