chiark / gitweb /
Support SLIP encapsulation as a tunnelling mechanism.
authormdw <mdw>
Sat, 3 Sep 2005 23:52:20 +0000 (23:52 +0000)
committermdw <mdw>
Sat, 3 Sep 2005 23:52:20 +0000 (23:52 +0000)
Makefile.am
configure.in
doc/tripe-admin.5
doc/tripe.8
peer.c
tripe-init.in
tripe.c
tripe.h
tun-linux.c
tun-slip.c [new file with mode: 0644]

index cb7455a1e4501b7d57cef2e5d707f6662b15323d..bbf743ea63ec8b69186d63ea67e8b6d4a7defb04 100644 (file)
@@ -43,7 +43,7 @@ tripe_SOURCES = \
        keymgmt.c keyexch.c keyset.c \
        servutil.c util.c util.h
 EXTRA_tripe_SOURCES = \
        keymgmt.c keyexch.c keyset.c \
        servutil.c util.c util.h
 EXTRA_tripe_SOURCES = \
-       tun-unet.c tun-bsd.c tun-linux.c
+       tun-unet.c tun-bsd.c tun-linux.c tun-slip.c
 tripe_LDADD = $(CATACOMB_LIBS)
 tripectl_SOURCES = \
        client.c util.c util.h
 tripe_LDADD = $(CATACOMB_LIBS)
 tripectl_SOURCES = \
        client.c util.c util.h
index 6163a8d87fed39f15e96709ade8f83f57dbf5ff5..db4ddf9aad4cebab46c5dfb0d6f808c366d0925f 100644 (file)
@@ -84,32 +84,44 @@ AC_ARG_WITH([ethereal],
 esac],
 [ethereal=true requireethereal=false])
 
 esac],
 [ethereal=true requireethereal=false])
 
-case $host_os in
-  linux*)
-    case `uname -r` in
+tun=guess
+AC_ARG_WITH([tunnel],
+[  --with-tunnel=KIND      kind of tunnel device to use
+                            (linux, unet, bsd, slip)],
+[tun=$withval])
+
+if test "$tun" = guess; then
+  AC_CACHE_CHECK([tunnel device to use], [mdw_cv_tunnel], [
+    case $host_os in
+      linux*)
+       case `uname -r` in
 changequote(,)dnl
 changequote(,)dnl
-      2.[4-9].* | 2.[1-9][0-9]*.* | [3-9].* | [1-9][0-9]*.*)
+         2.[4-9].* | 2.[1-9][0-9]*.* | [3-9].* | [1-9][0-9]*.*)
 changequote([,])dnl
 changequote([,])dnl
-       tun=linux
-       AC_DEFINE([TUN_TYPE], [TUN_LINUX], 
-        [Set to the tunnel driver for your OS.  See TUN_* in tripe.h.])
+           mdw_cv_tunnel=linux
+           ;;
+         *)
+           mdw_cv_tunnel=unet
+           ;;
+       esac
+       ;;
+      *bsd*)
+       mdw_cv_tunnel=bsd
        ;;
       *)
        ;;
       *)
-       tun=unet
-       AC_DEFINE([TUN_TYPE], [TUN_UNET],
-        [Set to the tunnel driver for your OS.  See TUN_* in tripe.h.])
+        mdw_cv_tunnel=slip
        ;;
     esac
        ;;
     esac
-    ;;
-  *bsd*)
-    tun=bsd
-    AC_DEFINE([TUN_TYPE], [TUN_BSD],
-    [Set to the tunnel driver for your OS.  See TUN_* in tripe.h.])
-    ;;
-  *)
-    AC_MSG_ERROR([Unsupported OS: no tunnel interface available])
-    ;;
+  ])
+  tun=$mdw_cv_tunnel
+fi
+
+case $tun in
+  linux | unet | bsd | slip) ;;
+  *) AC_MSG_ERROR([Unknown tunnel type]) ;;
 esac
 esac
+AC_DEFINE_UNQUOTED([TUN_TYPE], [TUN_`echo $tun | tr a-z A-Z`],
+  [Set to the tunnel driver for your OS.  See TUN_* in tripe.h.])
 AC_SUBST(tun)
 
 mdw_MLIB(2.0.0)
 AC_SUBST(tun)
 
 mdw_MLIB(2.0.0)
index 9f434bdc9f3e7b6cf3be42248c0906635cb1cd2e..35a0f08bb4e647b1f8dbb34565233fcab7cceaab 100644 (file)
@@ -654,6 +654,10 @@ create some more
 .BI /dev/tun nn
 files, it will work.
 .TP
 .BI /dev/tun nn
 files, it will work.
 .TP
+.BI "TUN \- slip no-slip-interfaces"
+The driver ran out of SLIP interfaces.  You probably need to preallocate
+some more and restart.
+.TP
 .BI "TUN - open-error " device " \-\- " message
 An attempt to open the tunnel device file
 .I device
 .BI "TUN - open-error " device " \-\- " message
 An attempt to open the tunnel device file
 .I device
@@ -676,6 +680,23 @@ and shouldn't be used any more.
 .BI "TUN \- unet ifname-too-long \-\- " message
 The Unet interface's name overflowed, so we couldn't read it properly.
 Unet is obsolete and shouldn't be used any more.
 .BI "TUN \- unet ifname-too-long \-\- " message
 The Unet interface's name overflowed, so we couldn't read it properly.
 Unet is obsolete and shouldn't be used any more.
+.TP
+.BI "TUN " ifname " slip eof"
+The SLIP driver encountered end-of-file on its input descriptor.
+Pending data is discarded, and no attempt is made to read any more data
+from that interface ever.
+.TP
+.BI "TUN " ifname " slip escape-end"
+The SLIP driver encountered an escaped `end' marker.  This probably
+means that someone's been sending it junk.  The erroneous packet is
+discarded, and we hope that we've rediscovered synchronization.
+.TP
+.BI "TUN " ifname " slip bad-escape"
+The SLIP driver encountered a escaped byte it wasn't expecting to see.
+The erroneous packet will be ignored.
+.TP
+.BI "TUN " ifname " slip overflow"
+The SLIP driver gave up reading a packet because it got too large.
 .SS "USER warnings"
 These are issued by administration clients using the
 .B WARN
 .SS "USER warnings"
 These are issued by administration clients using the
 .B WARN
index 373271a7440920e78e8292fefea0f0a0fa288265..bcfdcbb4a94829c059ecdefe7b2db03e38b9bf12 100644 (file)
@@ -477,6 +477,34 @@ at half the underlying hash function's output length.
 A `mask-generation function', used in the key-exchange.  The default is
 .IB hash \-mgf
 and there's no good reason to change it.
 A `mask-generation function', used in the key-exchange.  The default is
 .IB hash \-mgf
 and there's no good reason to change it.
+.SS "Using SLIP interfaces"
+Though not for the faint of heart, it is possible to get
+.B tripe
+to read and write network packets to a pair of file descriptors using
+SLIP encapsulation.  No fancy header compression of any kind is
+supported.  The intended use is that you allocate a pty pair, set the
+slave's line discipline to SLIP, and hand the
+.B tripe
+server the master end, though in fact any old file descriptors will do.
+.PP
+The SLIP descriptors must be set up and running before the daemon is
+started, and you must inform it about the SLIP descriptors it's meant to
+use in an environment variable
+.BR TRIPE_SLIPIF ,
+whose value must be a colon-separated list of items of the form
+.IR infd [ \c
+.BI , outfd \c
+.RB ] \c
+.BI = \c
+.IR ifname .
+If the
+.I outfd
+is omitted, the same file descriptor is used for input and output.
+.PP
+The output file descriptor should not block unless it really needs to:
+the
+.B tripe
+daemon assumes that it won't, and will get wait for it to accept output.
 .SS "About the name"
 The program's name is
 .BR tripe ,
 .SS "About the name"
 The program's name is
 .BR tripe ,
diff --git a/peer.c b/peer.c
index 5fdfc1bca4ec14354039b72a461d34e95985ccf4..15243b712c694715e0de45529bfe1702bf5ba8bb 100644 (file)
--- a/peer.c
+++ b/peer.c
@@ -80,8 +80,10 @@ static void p_read(int fd, unsigned mode, void *v)
   return;
 
 found:
   return;
 
 found:
-  T( trace(T_PEER, "peer: packet received from `%s'", p->name);
-     trace_block(T_PACKET, "peer: packet contents", buf_i, n); )
+  IF_TRACING(T_PEER, {
+    trace(T_PEER, "peer: packet received from `%s'", p->name);
+    trace_block(T_PACKET, "peer: packet contents", buf_i, n);
+  })
 
   /* --- Pick the packet apart --- */
 
 
   /* --- Pick the packet apart --- */
 
index b02b8269fd03aaa7b11497a892dd724bae7c99f6..82ada434fedee70eed4da0e475afe1fae3335e07 100755 (executable)
@@ -99,6 +99,12 @@ case `$tripe --tunnel` in
        ;;
     esac
     ;;
        ;;
     esac
     ;;
+  slip)
+    if test "$TRIPE_SLIPIF" = ""; then
+      echo >&2 "$tripe needs SLIP interfaces set up!"
+      exit 1
+    fi
+    ;;
 esac
   
 # --- Do what was wanted ---
 esac
   
 # --- Do what was wanted ---
diff --git a/tripe.c b/tripe.c
index 78a3d726c583f948cc387d02f3d2e4ab59906498..180177ee66450b8876ff63f3b9fe064017a616d3 100644 (file)
--- a/tripe.c
+++ b/tripe.c
@@ -247,7 +247,8 @@ int main(int argc, char *argv[])
        break;
 #endif
       case '0': {
        break;
 #endif
       case '0': {
-       static const char *tun[] = { "notdef", "unet", "bsd", "linux" };
+       static const char *tun[] =
+         { "notdef", "unet", "bsd", "linux", "slip" };
        puts(tun[TUN_TYPE]);
        exit(0);
       } break;
        puts(tun[TUN_TYPE]);
        exit(0);
       } break;
diff --git a/tripe.h b/tripe.h
index 320a2ca5218f91d4672aabf6e95a8f81ba4f2895..c8ad9ae1a40a42c2a278046f23eac11cf319cc0c 100644 (file)
--- a/tripe.h
+++ b/tripe.h
@@ -40,6 +40,7 @@
 #include <assert.h>
 #include <ctype.h>
 #include <errno.h>
 #include <assert.h>
 #include <ctype.h>
 #include <errno.h>
+#include <limits.h>
 #include <signal.h>
 #include <stdarg.h>
 #include <stddef.h>
 #include <signal.h>
 #include <stdarg.h>
 #include <stddef.h>
 #define TUN_UNET 1
 #define TUN_BSD 2
 #define TUN_LINUX 3
 #define TUN_UNET 1
 #define TUN_BSD 2
 #define TUN_LINUX 3
+#define TUN_SLIP 4
 
 /* --- Trace flags --- */
 
 
 /* --- Trace flags --- */
 
@@ -263,6 +265,16 @@ enum {
 #  include <linux/if_tun.h>
 #endif
 
 #  include <linux/if_tun.h>
 #endif
 
+#if TUN_TYPE == TUN_SLIP
+  typedef struct slipif {
+    struct slipif *next;               /* Next one in the list */
+    int ifd, ofd;                      /* File descriptors to talk on */
+    char *name;                                /* Interface name */
+    unsigned f;                                /* Various flags */
+#     define SLIPIFF_INUSE 1u          /*   Interface is in use */
+  } slipif;
+#endif
+
 typedef struct tunnel {
 #if TUN_TYPE == TUN_UNET 
   sel_file f;                          /* Selector for Usernet device */
 typedef struct tunnel {
 #if TUN_TYPE == TUN_UNET 
   sel_file f;                          /* Selector for Usernet device */
@@ -275,6 +287,16 @@ typedef struct tunnel {
   sel_file f;                          /* Selector for tunnel device */
   struct peer *p;                      /* Pointer to my peer */
   unsigned n;                          /* Number of my tunnel device */
   sel_file f;                          /* Selector for tunnel device */
   struct peer *p;                      /* Pointer to my peer */
   unsigned n;                          /* Number of my tunnel device */
+#elif TUN_TYPE == TUN_SLIP
+  slipif *sl;                          /* My interface record */
+  sel_file f;                          /* Selector for SLIP tty */
+  struct peer *p;                      /* Pointer to my peer */
+  unsigned st;                         /* Current parser state */
+#   define SLIPST_ESC 1u               /*   Last saw an escape character */
+#   define SLIPST_BAD 2u               /*   This packet is malformed */
+#   define SLIPST_EOF 4u               /*   File descriptor reported EOF */
+  size_t n;                            /* Number of bytes used in buffer */
+  octet buf[PKBUFSZ];                  /* Buffer for incoming data */
 #else
 #  error "No support for this tunnel type"
 #endif
 #else
 #  error "No support for this tunnel type"
 #endif
index 6aa5adb4219da4426728aa5505e20a0944e24d5d..ff65a5e7b032c4b0dea12456ad8020156a3d93ab 100644 (file)
@@ -105,7 +105,7 @@ int tun_create(tunnel *t, peer *p)
   }
   fdflags(fd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC);
   iff.ifr_name[0] = 0;
   }
   fdflags(fd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC);
   iff.ifr_name[0] = 0;
-  iff.ifr_flags = IFF_TUN;
+  iff.ifr_flags = IFF_TUN | IFF_NO_PI;
   if ((f = ioctl(fd, TUNSETIFF, &iff)) < 0) {
     a_warn("TUN - linux config-error -- %s", strerror(errno));
     close(fd);
   if ((f = ioctl(fd, TUNSETIFF, &iff)) < 0) {
     a_warn("TUN - linux config-error -- %s", strerror(errno));
     close(fd);
diff --git a/tun-slip.c b/tun-slip.c
new file mode 100644 (file)
index 0000000..1d1bd14
--- /dev/null
@@ -0,0 +1,325 @@
+/* -*-c-*-
+ *
+ * $Id$
+ *
+ * Tunnel packets via SLIP
+ *
+ * (c) 2005 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------* 
+ *
+ * This file is part of Trivial IP Encryption (TrIPE).
+ *
+ * TrIPE is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * TrIPE is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with TrIPE; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "tripe.h"
+
+/*----- Static variables --------------------------------------------------*/
+
+static slipif *slipifs;                        /* List of available interfaces */
+
+/*----- Main code ---------------------------------------------------------*/
+
+#if TUN_TYPE != TUN_SLIP
+#  error "Tunnel type mismatch: fix the Makefile"
+#endif
+
+#define SL_END 0xc0
+#define SL_ESC 0xdb
+#define SL_ESCEND 0xdc
+#define SL_ESCESC 0xdd
+
+/* --- @t_read@ --- *
+ *
+ * Arguments:  @int fd@ = file descriptor to read
+ *             @unsigned mode@ = what's happened
+ *             @void *v@ = pointer to tunnel block
+ *
+ * Returns:    ---
+ *
+ * Use:                Reads data from the tunnel.
+ */
+
+static void t_read(int fd, unsigned mode, void *v)
+{
+  tunnel *t = v;
+  ssize_t n;
+  const octet *p, *l, *ll;
+  octet *q;
+  unsigned st;
+  octet o;
+  buf b;
+
+  /* --- Read the input data --- */
+
+  n = read(fd, buf_t, sizeof(buf_t));
+  if (n < 0) {
+    if (errno == EINTR ||
+#ifdef EWOULDBLOCK
+       errno == EWOULDBLOCK ||
+#endif
+       errno == EAGAIN)
+      return;
+    a_warn("TUN %s read-error -- %s", t->sl->name, strerror(errno));
+    return;
+  }
+  if (!n) {
+    a_warn("TUN %s slip eof", t->sl->name);
+    t->st = SLIPST_EOF;
+    sel_rmfile(&t->f);
+    return;
+  }
+  IF_TRACING(T_TUNNEL, {
+    trace_block(T_PACKET, "tunnel: SLIP-encapsulated data",
+               buf_t, n);
+  })
+
+  /* --- Decapsulate the packet --- */
+
+  for (p = buf_t, l = p + n, st = t->st,
+       q = t->buf + t->n, ll = t->buf + sizeof(t->buf);
+       p < l;
+       p++) {
+    o = *p;
+    switch (o) {
+      case SL_END:
+       if (st & SLIPST_BAD)
+         ;
+       else if (st & SLIPST_ESC)
+         a_warn("TUN %s slip escape-end", t->sl->name);
+       else if (q == t->buf) {
+         T( trace(T_TUNNEL, "tunnel: empty packet"); )
+       } else {
+         IF_TRACING(T_TUNNEL, {
+           trace(T_TUNNEL, "tunnel: packet arrived");
+           trace_block(T_PACKET, "tunnel: packet contents",
+                       t->buf, q - t->buf);
+         })
+         buf_init(&b, t->buf, q - t->buf);
+         p_tun(t->p, &b);
+       }
+       q = t->buf;
+       st &= ~(SLIPST_ESC | SLIPST_BAD);
+       break;
+      case SL_ESC:
+       if ((st & SLIPST_ESC) && !(st & SLIPST_BAD)) {
+         a_warn("TUN %s slip bad-escape", t->sl->name);
+         st |= SLIPST_BAD;
+       } else
+         st |= SLIPST_ESC;
+       break;
+      case SL_ESCEND:
+       if (st & SLIPST_ESC)
+         o = SL_END;
+       goto emit;
+      case SL_ESCESC:
+       if (st & SLIPST_ESC)
+         o = SL_ESC;
+       goto emit;
+      default:
+       if ((st & SLIPST_ESC) && !(st & SLIPST_BAD)) {
+         a_warn("TUN %s slip bad-escape", t->sl->name);
+         st |= SLIPST_BAD;
+       }
+      emit:
+       if (!(st & SLIPST_BAD)) {
+         if (q < ll)
+           *q++ = o;
+         else {
+           a_warn("TUN %s slip overflow", t->sl->name);
+           st |= SLIPST_BAD;
+         }
+       }
+       st &= ~SLIPST_ESC;
+       break;
+    }
+  }
+
+  t->n = q - t->buf;
+  t->st = st;
+}
+
+/* --- @tun_init@ --- *
+ *
+ * Arguments:  ---
+ *
+ * Returns:    ---
+ *
+ * Use:                Initializes the tunneling system.  Maybe this will require
+ *             opening file descriptors or something.
+ */
+
+void tun_init(void)
+{
+  char *p, *q;
+  dstr d = DSTR_INIT;
+  slipif *sl, **tail = &slipifs;
+  unsigned long uli, ulo;
+  size_t n;
+
+  /* --- Build the list of available interfaces --- */
+
+  if ((p = getenv("TRIPE_SLIPIF")) == 0)
+    die(1, "no slip interfaces listed: set TRIPE_SLIPIF");
+  dstr_puts(&d, p);
+
+  p = d.buf;
+  for (;;) {
+    uli = strtoul(p, &q, 0);
+    if (uli > INT_MAX || q == p)
+      goto whine;
+    if (*q != ',')
+      ulo = uli;
+    else {
+      p = q + 1;
+      ulo = strtoul(p, &q, 0);
+      if (ulo > INT_MAX || q == p)
+       goto whine;
+    }
+    if (*q != '=' || (n = strcspn(q + 1, ":")) == 0)
+      goto whine;
+    sl = CREATE(slipif);
+    sl->next = 0;
+    sl->ifd = uli;
+    sl->ofd = ulo;
+    sl->name = xmalloc(n + 1);
+    sl->f = 0;
+    memcpy(sl->name, q + 1, n);
+    sl->name[n] = 0;
+    *tail = sl;
+    tail = &sl->next;
+    T( trace(T_TUNNEL, "tunnel: declared slipif %d,%d=%s",
+            sl->ifd, sl->ofd, sl->name); )
+    p = q + n + 1;
+    if (!*p)
+      break;
+    p++;
+  }
+  return;
+
+whine:
+  die(1, "bad slip interface list");
+}
+
+/* --- @tun_create@ --- *
+ *
+ * Arguments:  @tunnel *t@ = pointer to tunnel block
+ *             @peer *p@ = pointer to peer block
+ *
+ * Returns:    Zero if it worked, nonzero on failure.
+ *
+ * Use:                Initializes a new tunnel.
+ */
+
+int tun_create(tunnel *t, peer *p)
+{
+  slipif *sl;
+  static const char end[] = { SL_END, SL_END };
+
+  for (sl = slipifs; sl; sl = sl->next) {
+    if (!(sl->f & SLIPIFF_INUSE))
+      goto found;
+  }
+  a_warn("TUN - slip no-slip-interfaces");
+  return (-1);
+
+found:
+  t->p = p;
+  t->sl = sl;
+  t->st = 0;
+  t->n = 0;
+  sl->f |= SLIPIFF_INUSE;
+  sel_initfile(&sel, &t->f, sl->ifd, SEL_READ, t_read, t);
+  sel_addfile(&t->f);
+  write(sl->ofd, end, sizeof(end));
+  T( trace(T_TUNNEL, "tunnel: attached interface %s to peer `%s'",
+          sl->name, p_name(p)); )
+  return (0);
+}
+
+/* --- @tun_ifname@ --- *
+ *
+ * Arguments:  @tunnel *t@ = pointer to tunnel block
+ *
+ * Returns:    A pointer to the tunnel's interface name.
+ */
+
+const char *tun_ifname(tunnel *t)
+{
+  return (t->sl->name);
+}
+
+/* --- @tun_inject@ --- *
+ *
+ * Arguments:  @tunnel *t@ = pointer to tunnel block
+ *             @buf *b@ = buffer to send
+ *
+ * Returns:    ---
+ *
+ * Use:                Injects a packet into the local network stack.
+ */
+
+void tun_inject(tunnel *t, buf *b)
+{
+  octet buf[PKBUFSZ * 2 + 2];
+  const octet *p, *l;
+  octet *q;
+
+  IF_TRACING(T_TUNNEL, {
+    trace(T_TUNNEL, "tunnel: inject decrypted packet");
+    trace_block(T_PACKET, "tunnel: packet contents", BBASE(b), BLEN(b));
+  })
+
+  q = buf;
+  *q++ = SL_END;
+  for (p = BBASE(b), l = BCUR(b); p < l; p++) {
+    switch (*p) {
+      case SL_END: *q++ = SL_ESC; *q++ = SL_ESCEND; break;
+      case SL_ESC: *q++ = SL_ESC; *q++ = SL_ESCESC; break;
+      default: *q++ = *p; break;
+    }
+  }
+  *q++ = SL_END;
+  IF_TRACING(T_TUNNEL, {
+    trace_block(T_PACKET, "tunnel: SLIP-encapsulated contents",
+               buf, q - buf);
+  })
+  write(t->sl->ofd, buf, q - buf);
+}
+
+/* --- @tun_destroy@ --- *
+ *
+ * Arguments:  @tunnel *t@ = pointer to tunnel block
+ *
+ * Returns:    ---
+ *
+ * Use:                Destroys a tunnel.
+ */
+
+void tun_destroy(tunnel *t)
+{
+  /* --- If it reported EOF, leave it out-of-action --- */
+
+  if (!(t->st & SLIPST_EOF)) {
+    sel_rmfile(&t->f);
+    t->sl->f &= ~SLIPIFF_INUSE;
+  }
+}
+
+/*----- That's all, folks -------------------------------------------------*/