.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
+supported.
+.PP
+Two usage modes are supported: a preallocation system, whereby SLIP
+interfaces are created and passed to the
+.B tripe
+server at startup; and a dynamic system, where the server runs a script
+to allocate a new SLIP interface when it needs one. It is possible to
+use a mixture of these two modes, starting
.B tripe
-server the master end, though in fact any old file descriptors will do.
+with a few preallocated interfaces and having it allocate more
+dynamically as it needs them.
+.PP
+The behaviour of
+.BR tripe 's
+SLIP driver is controlled by the
+.B TRIPE_SLIPIF
+environment variable. The server will fail to start if this variable is
+not defined. The variable's value is a colon-delimited list of
+preallocated interfaces, followed optionally by the filename of a script
+to run to dynamically allocate more interfaces.
.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
+A static allocation entry has the form
.IR infd [ \c
.BI , outfd \c
.RB ] \c
.BI = \c
-.IR ifname .
+.IR ifname ,
If the
.I outfd
is omitted, the same file descriptor is used for input and output.
.PP
+The dynamic allocation script must be named by an absolute or relative
+pathname, beginning with
+.RB ` / '
+or
+.RB ` . '.
+The server will pass the script an argument, which is the name of the
+peer for which the interface is being created. The script should
+allocate a new SLIP interface (presumably by creating a pty pair),
+configure it appropriately, and write the interface's name to its
+standard output, followed by a newline. It should then read and write
+SLIP packets on its stdin and stdout. The script's stdin will be closed
+when the interface is no longer needed, and the server will attempt to
+send it a
+.B SIGTERM
+signal (though this may fail if the script runs with higher privileges
+than the server).
+.PP
The output file descriptor should not block unless it really needs to:
the
.B tripe
/*----- Static variables --------------------------------------------------*/
static slipif *slipifs; /* List of available interfaces */
+static const char *slipcmd; /* Script to make new interfaces */
/*----- Main code ---------------------------------------------------------*/
n = read(fd, buf_t, sizeof(buf_t));
if (n < 0) {
if (errno == EINTR ||
-#ifdef EWOULDBLOCK
+#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
errno == EWOULDBLOCK ||
#endif
errno == EAGAIN)
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");
+
+ /* --- Build the list of available interfaces --- */
+
dstr_puts(&d, p);
p = d.buf;
for (;;) {
+ if (*p == '/' || *p == '.') {
+ slipcmd = p;
+ T( trace(T_TUNNEL, "tunnel: declared slip command `%s'", slipcmd); )
+ break;
+ }
uli = strtoul(p, &q, 0);
if (uli > INT_MAX || q == p)
goto whine;
sl = CREATE(slipif);
sl->next = 0;
sl->ifd = uli;
+ fdflags(sl->ifd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC);
+ fdflags(sl->ofd, O_NONBLOCK, 0, FD_CLOEXEC, FD_CLOEXEC);
sl->ofd = ulo;
sl->name = xmalloc(n + 1);
+ sl->kid = -1;
sl->f = 0;
memcpy(sl->name, q + 1, n);
sl->name[n] = 0;
int tun_create(tunnel *t, peer *p)
{
- slipif *sl;
+ slipif *sl = 0;
+ int pin[2] = { -1, -1 }, pout[2] = { -1, -1 };
+ pid_t kid = -1;
+ dstr d = DSTR_INIT;
+ unsigned char ch;
static const char end[] = { SL_END, SL_END };
+ /* --- Try to find a spare static interface --- */
+
for (sl = slipifs; sl; sl = sl->next) {
- if (!(sl->f & SLIPIFF_INUSE))
+ if (!(sl->f & SLIPIFF_INUSE)) {
+ T( trace(T_TUNNEL, "tunnel: %s using static slipif %s",
+ p_name(p), sl->name); )
goto found;
+ }
}
- a_warn("TUN - slip no-slip-interfaces");
- return (-1);
+
+ /* --- If no dynamic interfaces are available, give up --- */
+
+ if (!slipcmd) {
+ a_warn("TUN %s slip no-slip-interfaces", p_name(p));
+ goto fail;
+ }
+
+ /* --- Fork off a child process to create a dynamic SLIP interface --- */
+
+ if (pipe(pin) || pipe(pout)) {
+ a_warn("TUN %s slip pipe-error -- %s", p_name(p), strerror(errno));
+ goto fail;
+ }
+ if ((kid = fork()) < 0) {
+ a_warn("TUN %s slip fork-error -- %s", p_name(p), strerror(errno));
+ goto fail;
+ }
+ if (!kid) {
+ close(pin[1]);
+ close(pout[0]);
+ dup2(pin[0], STDIN_FILENO);
+ dup2(pout[1], STDOUT_FILENO);
+ execlp(slipcmd, slipcmd, p_name(p), (char *)0);
+ _exit(127);
+ }
+
+ /* --- Read the interface name --- */
+
+ sl = CREATE(slipif);
+ close(pin[0]); pin[0] = -1;
+ close(pout[1]); pout[1] = -1;
+ for (;;) {
+ errno = EIO;
+ if (read(pout[0], &ch, 1) != 1 || ch == SL_END) {
+ a_warn("TUN %s slip read-ifname-failed -- %s",
+ p_name(p), strerror(errno));
+ goto fail;
+ }
+ if (ch == '\n')
+ break;
+ DPUTC(&d, (char)ch);
+ }
+ DPUTZ(&d);
+ sl->name = xstrdup(d.buf);
+ sl->ifd = pout[0];
+ sl->ofd = pin[1];
+ sl->kid = kid;
+ sl->next = 0;
+ sl->f = SLIPIFF_DYNAMIC;
+ T( trace(T_TUNNEL, "tunnel: %s using dynamic slipif %s",
+ p_name(p), sl->name); )
+ fdflags(pout[0], O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC);
+ fdflags(pin[1], O_NONBLOCK, 0, FD_CLOEXEC, FD_CLOEXEC);
+
+ /* --- Set up the new tunnel --- */
found:
t->p = p;
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)); )
+ dstr_destroy(&d);
return (0);
+
+ /* --- Tidy up after a failure --- */
+
+fail:
+#define CLOSE(fd) do if (fd != -1) close(fd); while (0)
+ CLOSE(pin[0]); CLOSE(pout[0]);
+ CLOSE(pin[1]); CLOSE(pout[1]);
+#undef CLOSE
+ if (kid != -1) kill(kid, SIGTERM);
+ if (sl && (sl->f & SLIPIFF_DYNAMIC)) DESTROY(sl);
+ dstr_destroy(&d);
+ return (-1);
}
/* --- @tun_ifname@ --- *
* Returns: A pointer to the tunnel's interface name.
*/
-const char *tun_ifname(tunnel *t)
-{
- return (t->sl->name);
-}
+const char *tun_ifname(tunnel *t) { return (t->sl->name); }
/* --- @tun_inject@ --- *
*
void tun_destroy(tunnel *t)
{
+ slipif *sl = t->sl;
+
/* --- If it reported EOF, leave it out-of-action --- */
if (!(t->st & SLIPST_EOF)) {
sel_rmfile(&t->f);
- t->sl->f &= ~SLIPIFF_INUSE;
+ sl->f &= ~SLIPIFF_INUSE;
+ }
+ if (sl && (sl->f & SLIPIFF_DYNAMIC)) {
+ T( trace(T_TUNNEL, "tunnel: releasing dynamic slipif %s", sl->name); )
+ close(sl->ofd);
+ close(sl->ifd);
+ kill(sl->kid, SIGTERM);
+ xfree(sl->name);
+ DESTROY(sl);
}
}