Skip site navigation (1)Skip section navigation (2)
Date:      13 Feb 96 11:27:10 GMT
From:      peter@jhome.DIALix.COM (Peter Wemm)
To:        freebsd-hackers@freebsd.org
Subject:   Re: Kerberos @ freebsd.org?
Message-ID:  <peter.824210830@jhome.DIALix.COM>
References:  <199602111306.OAA05893@keltia.freenix.fr>, <4456.824046250@time.cdrom.com>

next in thread | previous in thread | raw e-mail | index | archive | help
jkh@time.cdrom.com (Jordan K. Hubbard) writes:

>> It seems that Warner Losh said:
>> > However, ssh won't encrypt things like NFS traffic, mud traffic, etc.
>> 
>> You can use FTP thru an encrypted channel  or simply uses "scp" to tranfert
>> files... 

>Who was it here who successfully used ssh and the tun driver to implement an
>encrypted encapsulation channel?  Maybe we should package that functionality
>a little bit.. :-)

Me.. :-)  I did a REALLY crude hack in about 10 minutes.  It uses a simple
2-byte length to encode the length of the datagram following.

The basic problem with doing it this way is that you can't do routing
over it to get all sessions to the remote host going over the tunnel, because
the tunnel's packets themselves would go over the tunnel.  The only way
around it would be to use IP aliases to get the tunnel endpoints or some
other hack.

I used it for a few test cases like this:
iptun -l 1.1.1.1 -r 2.2.2.2 -c "ssh otherhost iptun -l 2.2.2.2 -r 1.1.1.1"

It works with rsh and any other *guaranteed* reliable, 8-bit clean protocol.
It has no way of recovering from an error.

>						Jordan

If anybody wants to have a play with this, be my guest... :-)

/*
 * Copyright (c) 1996 Peter Wemm <peter@freebsd.org>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, is permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice immediately at the beginning of the file, without modification,
 *    this list of conditions, and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Absolutely no warranty of function or purpose is made by the author
 *    Peter Wemm.
 * 4. Modifications may be freely made to this file providing the above
 *    conditions are met.
 */

#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/filio.h>
#include <sys/socket.h>
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <signal.h>

void
Usage(char *s)
{
  fprintf(stderr, "Usage: %s -l locaddr -r remaddr [ -c command ]\n", s);
  exit(1);
}

#define MYMTU 1500

int
main(int ac, char **av)
{
  char buf[PATH_MAX];
  int i;
  int n;
  int c;
  int tunfd = -1;
  int tununit = -1;
  char *locaddr = NULL;
  char *remaddr = NULL;
  char *netmask = NULL;
  int readfd;			/* read fd to remote */
  int writefd;			/* write fd to remote */
  int pipe1[2], pipe2[2];
  u_char txbuf[MYMTU + 10];	/* transmit staging buffer (tun to remote) */
  u_char rxbuf[MYMTU + 10];	/* receive staging buffer (remote to tun) */
  int rxwant, rxgot;		/* how much do we want vs got */
  fd_set fdsr, fdse;

  char *progname = *av++;
  
  locaddr = *av++;
  if (!locaddr) {
    fprintf(stderr, "You must supply a local address!\n");
    Usage(progname);
  }

  remaddr = *av++;
  if (!remaddr) {
    fprintf(stderr, "You must supply a remote address!\n");
    Usage(progname);
  }

  netmask = *av++;
  if (!netmask) {
    fprintf(stderr, "You must supply a netmask!\n");
    Usage(progname);
  }

  for (i = 0; i < 256; i++) {
    sprintf(buf, "/dev/tun%d", i);
    tunfd = open(buf, O_RDWR, 0);
    if (tunfd != -1) {
      tununit = i;
      break;
    }
    if (errno == ENOENT || i == 255) {
      fprintf(stderr, "Not enough IP tunnel devices (/dev/tunXX) configured!\n");
      exit(1);
    }
  }	
  assert(tunfd != -1);
  assert(tununit != -1);

  sprintf(buf, "/sbin/ifconfig tun%d %s %s netmask %s",
	  tununit, locaddr, remaddr, netmask);
  system(buf);

  fflush(stdout);
  fflush(stdin);
  
  if (av[0]) {
    /* start remote server command */
    pipe(pipe1);		/* parent -> child */
    pipe(pipe2);		/* child -> parent */
    if (fork() == 0) {
      /* child */
      dup2(pipe1[0], 0);
      dup2(pipe2[1], 1);
      close(tunfd);
      close(pipe1[1]);
      close(pipe2[0]);
      execv(av[0], av);
      perror("execv");
      _exit(1);
    } else {
      /* parent */
      writefd = pipe1[1];
      readfd = pipe2[0];
      close(pipe1[0]);
      close(pipe2[1]);
    }
    signal(SIGPIPE, SIG_IGN);
    /* master - read/write to pipe */
  } else {
    /* slave - read/write to stdin/out */
    readfd = 0;
    writefd = 1;
  }

  i = 1;
  ioctl(tunfd, FIONBIO, &i);	/* lets get on with it.. :-) */
#if 1
  ioctl(readfd, FIONBIO, &i);
  ioctl(writefd, FIONBIO, &i);
#endif
  rxwant = rxgot = 0;

  while(1) {

    FD_ZERO(&fdsr);
    FD_ZERO(&fdse);

    FD_SET(tunfd, &fdsr);
    FD_SET(readfd, &fdsr);

    FD_SET(readfd, &fdse);
    FD_SET(writefd, &fdse);

    n = tunfd > readfd ? tunfd : readfd;
    
    n = select(n + 1, &fdsr, NULL, &fdse, NULL);
    if (n < 0) {
      if (errno == EINTR)
	continue;
      perror("select");
      exit(1);
    }

    /* net drop? */
    if (FD_ISSET(readfd, &fdse)) {
      fprintf(stderr, "exception on remote read file descriptor..");
      exit(1);
    }
    if (FD_ISSET(writefd, &fdse)) {
      fprintf(stderr, "exception on remote write file descriptor..");
      exit(1);
    }

    if (FD_ISSET(readfd, &fdsr)) {
      int try;
      /*
       * rxwant - how much data is in the IP packet
       * rxgot - how much data is in rxbuf
       * Note rxgot includes the length, rxwant does not
       */

      if (!rxwant)
	try = 2;
      else
	try = rxwant - rxgot + 2;

      /* slurp in any more data */
      if (try > 0) {
	n = read(readfd, rxbuf + rxgot, try);
	if (n > 0) {
	  rxgot += n;
	}
	if (n == 0) {
	  _exit(1);
	}
	if (n < 0) {
	  if (errno != EAGAIN && errno != EINTR) {
	    perror("read");
	    exit(0);
	  }
	}
      }

      if (!rxwant) {		/* new packet starting */
	if (rxgot >= 2) {	/* ok. got count */
	  rxwant = rxbuf[0] * 256 + rxbuf[1];
	}
      }

      if (rxwant > MYMTU) {
	fprintf(stderr, "rxwant: %d\n", rxwant);
	_exit(1);		/* "cant happen"... :-) */
      }

      /* are we counting for a packet */
      if (rxwant) {
	if ((rxgot - 2) >= rxwant) { /* all here... */

	  write(tunfd, rxbuf + 2, rxwant); /* ignore error */

	  rxgot = 0;
	  rxwant = 0;
	}
      }
    }

    if (FD_ISSET(tunfd, &fdsr)) {
      n = read(tunfd, txbuf + 2, MYMTU);
      if (n > 0) {
	txbuf[0] = n / 256;	/* high count */
	txbuf[1] = n % 256;	/* low count */
	write(writefd, txbuf, n + 2); /* ignore error */
      }
    }

  }
}

Cheers,
-Peter



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?peter.824210830>