/*----- 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);
}
}