From eb5f3fea8a65306e424a353951208b11bd3aac22 Mon Sep 17 00:00:00 2001 Message-Id: From: Mark Wooding Date: Sat, 20 Dec 2008 17:06:10 +0000 Subject: [PATCH] peer, tunnels: New file-descriptor opening interface. Organization: Straylight/Edgeware From: Mark Wooding Separate initializing tunnel devices into distinct stages of obtaining an appropriate file descriptor, and configuring it and plumbing it into the select loop. Alas, this reduces the quality of error reporting when tunnel acquisition fails. This is a preliminary stage to implementing privilege separation in the TrIPE server. --- server/peer.c | 16 ++++++++++--- server/tripe.h | 3 ++- server/tun-bsd.c | 50 ++++++++++++++++++++++++--------------- server/tun-linux.c | 51 ++++++++++++++++++++++++++-------------- server/tun-slip.c | 4 +++- server/tun-unet.c | 58 ++++++++++++++++++++++++++++++---------------- 6 files changed, 120 insertions(+), 62 deletions(-) diff --git a/server/peer.c b/server/peer.c index 7f4d0940..3cb12ea2 100644 --- a/server/peer.c +++ b/server/peer.c @@ -724,6 +724,8 @@ static void p_setkatimer(peer *p) peer *p_create(peerspec *spec) { peer *p = CREATE(peer); + const tunnel_ops *tops = spec->tops; + int fd; unsigned f; p->byname = sym_find(&byname, spec->name, -1, sizeof(peer_byname), &f); @@ -740,11 +742,17 @@ peer *p_create(peerspec *spec) p->ifname = 0; memset(&p->st, 0, sizeof(stats)); p->st.t_start = time(0); - if ((p->t = spec->tops->create(p, &p->ifname)) == 0) + if (!tops->open) + fd = -1; + else if ((fd = tops->open(&p->ifname)) < 0) goto tidy_2; + if ((p->t = tops->create(p, fd, &p->ifname)) == 0) + goto tidy_3; + T( trace(T_TUNNEL, "peer: attached interface %s to peer `%s'", + p->ifname, p_name(p)); ) p_setkatimer(p); if (kx_init(&p->kx, p, &p->ks, p->spec.kxf)) - goto tidy_3; + goto tidy_4; a_notify("ADD", "?PEER", p, "%s", p->ifname, @@ -756,11 +764,13 @@ peer *p_create(peerspec *spec) } return (p); -tidy_3: +tidy_4: if (spec->t_ka) sel_rmtimer(&p->tka); xfree(p->ifname); p->t->ops->destroy(p->t); +tidy_3: + if (fd >= 0) close(fd); tidy_2: am_remove(&byaddr, p->byaddr); tidy_1: diff --git a/server/tripe.h b/server/tripe.h index 71c6023e..d955c88e 100644 --- a/server/tripe.h +++ b/server/tripe.h @@ -288,7 +288,8 @@ struct peer; typedef struct tunnel_ops { const char *name; /* Name of this tunnel driver */ void (*init)(void); /* Initializes the system */ - tunnel *(*create)(struct peer */*p*/, char **/*ifn*/); + int (*open)(char **/*ifn*/); /* Open tunnel and report ifname */ + tunnel *(*create)(struct peer */*p*/, int /*fd*/, char **/*ifn*/); /* Initializes a new tunnel */ void (*setifname)(tunnel */*t*/, const char */*ifn*/); /* Notifies ifname change */ diff --git a/server/tun-bsd.c b/server/tun-bsd.c index 49b5e0e2..200b5d93 100644 --- a/server/tun-bsd.c +++ b/server/tun-bsd.c @@ -38,7 +38,6 @@ struct tunnel { const tunnel_ops *ops; /* Pointer to operations */ sel_file f; /* Selector for tunnel device */ struct peer *p; /* Pointer to my peer */ - unsigned n; /* Number of my tunnel device */ }; /* --- @t_read@ --- * @@ -83,21 +82,20 @@ static void t_read(int fd, unsigned mode, void *v) static void t_init(void) { return; } -/* --- @t_create@ --- * +/* --- @t_open@ --- * * - * Arguments: @peer *p@ = pointer to peer block - * @char **ifn@ = where to put the interface name + * Arguments: @char **ifn@ = where to put the interface name * - * Returns: A tunnel block if it worked, or null on failure. + * Returns: A file descriptor, or @-1@ on failure. * - * Use: Initializes a new tunnel. + * Use: Opens a tunnel device. This will run with root privileges + * even if the rest of the server has dropped them. */ -static tunnel *t_create(peer *p, char **ifn) +static int t_open(char **ifn) { int fd; unsigned n; - tunnel *t; char buf[16]; n = 0; @@ -107,28 +105,41 @@ static tunnel *t_create(peer *p, char **ifn) break; switch (errno) { case EBUSY: - T( trace(T_TUNNEL, "tunnel device %u busy: skipping", n); ) - break; + T( trace(T_TUNNEL, "tunnel device %u busy: skipping", n); ) + break; case ENOENT: - a_warn("TUN", "-", "bsd", "no-tunnel-devices", A_END); - return (0); + a_warn("TUN", "-", "bsd", "no-tunnel-devices", A_END); + return (-1); default: - a_warn("TUN", "-", "open-error", "%s", buf, "?ERRNO", A_END); - break; + a_warn("TUN", "-", "open-error", "%s", buf, "?ERRNO", A_END); + break; } n++; } + return (fd); +} + +/* --- @t_create@ --- * + * + * Arguments: @peer *p@ = pointer to peer block + * @int fd@ = file descriptor of tunnel device + * @char **ifn@ = where to put the interface name + * + * Returns: A tunnel block if it worked, or null on failure. + * + * Use: Initializes a new tunnel. + */ +static tunnel *t_create(peer *p, int fd, char **ifn) +{ + tunnel *t; + + fdflags(fd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC); t = CREATE(tunnel); t->ops = &tun_bsd; - fdflags(fd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC); t->p = p; - t->n = n; sel_initfile(&sel, &t->f, fd, SEL_READ, t_read, t); sel_addfile(&t->f); - *ifn = xstrdup(buf + 5); - T( trace(T_TUNNEL, "tun-bsd: attached interface %s to peer `%s'", - *ifn, p_name(p)); ) return (t); } @@ -166,6 +177,7 @@ static void t_destroy(tunnel *t) const tunnel_ops tun_bsd = { "bsd", t_init, + t_open, t_create, 0, t_inject, diff --git a/server/tun-linux.c b/server/tun-linux.c index cffeb56d..11c7f37a 100644 --- a/server/tun-linux.c +++ b/server/tun-linux.c @@ -88,47 +88,61 @@ static void t_read(int fd, unsigned mode, void *v) static void t_init(void) { return; } -/* --- @t_create@ --- * +/* --- @t_open@ --- * * - * Arguments: @peer *p@ = pointer to peer block - * @char **ifn@ = where to put the interface name + * Arguments: @char **ifn@ = where to put the interface name * - * Returns: A tunnel block if it worked, or null on failure. + * Returns: A file descriptor, or @-1@ on failure. * - * Use: Initializes a new tunnel. + * Use: Opens a tunnel device. This will run with root privileges + * even if the rest of the server has dropped them. */ -static tunnel *t_create(peer *p, char **ifn) +static int t_open(char **ifn) { int fd; - int f; struct ifreq iff; - tunnel *t; if ((fd = open("/dev/net/tun", O_RDWR)) < 0) { a_warn("TUN", "-", "linux", - "open-error", "/dev/net/tun", "?ERRNO", - A_END); - return (0); + "open-error", "/dev/net/tun", "?ERRNO", + A_END); + return (-1); } - fdflags(fd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC); memset(&iff, 0, sizeof(iff)); iff.ifr_name[0] = 0; iff.ifr_flags = IFF_TUN | IFF_NO_PI; - if ((f = ioctl(fd, TUNSETIFF, &iff)) < 0) { + if (ioctl(fd, TUNSETIFF, &iff) < 0) { a_warn("TUN", "-", "linux", "config-error", "?ERRNO", A_END); close(fd); - return (0); + return (-1); } + iff.ifr_name[IFNAMSIZ - 1] = 0; + *ifn = xstrdup(iff.ifr_name); + return (fd); +} + +/* --- @t_create@ --- * + * + * Arguments: @peer *p@ = pointer to peer block + * @int fd@ = file descriptor of tunnel device + * @char **ifn@ = where to put the interface name + * + * Returns: A tunnel block if it worked, or null on failure. + * + * Use: Initializes a new tunnel. + */ + +static tunnel *t_create(peer *p, int fd, char **ifn) +{ + tunnel *t; + + fdflags(fd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC); t = CREATE(tunnel); t->ops = &tun_linux; t->p = p; sel_initfile(&sel, &t->f, fd, SEL_READ, t_read, t); sel_addfile(&t->f); - iff.ifr_name[IFNAMSIZ - 1] = 0; - *ifn = xstrdup(iff.ifr_name); - T( trace(T_TUNNEL, "tun-linux: attached interface %s to peer `%s'", - *ifn, p_name(p)); ) return (t); } @@ -166,6 +180,7 @@ static void t_destroy(tunnel *t) const tunnel_ops tun_linux = { "linux", t_init, + t_open, t_create, 0, t_inject, diff --git a/server/tun-slip.c b/server/tun-slip.c index d405cc49..4afef753 100644 --- a/server/tun-slip.c +++ b/server/tun-slip.c @@ -246,6 +246,7 @@ whine: /* --- @t_create@ --- * * * Arguments: @peer *p@ = pointer to peer block + * @int fd@ = file descriptor of tunnel device (unused) * @char **ifn@ = where to put the interface name * * Returns: A tunnel block if it worked, or null on failure. @@ -253,7 +254,7 @@ whine: * Use: Initializes a new tunnel. */ -static tunnel *t_create(peer *p, char **ifn) +static tunnel *t_create(peer *p, int fd, char **ifn) { slipif *sl = 0; int pin[2] = { -1, -1 }, pout[2] = { -1, -1 }; @@ -440,6 +441,7 @@ static void t_destroy(tunnel *t) const tunnel_ops tun_slip = { "slip", t_init, + 0, t_create, t_setifname, t_inject, diff --git a/server/tun-unet.c b/server/tun-unet.c index 2d11ca0f..88ce83d0 100644 --- a/server/tun-unet.c +++ b/server/tun-unet.c @@ -88,48 +88,65 @@ static void t_read(int fd, unsigned mode, void *v) static void t_init(void) { return; } -/* --- @t_create@ --- * +/* --- @t_open@ --- * * - * Arguments: @tunnel *t@ = pointer to tunnel block - * @peer *p@ = pointer to peer block - * @char *ifn@ = where to put the interface name + * Arguments: @char **ifn@ = where to put the interface name * - * Returns: A tunnel block if it worked, or null on failure. + * Returns: A file descriptor, or @-1@ on failure. * - * Use: Initializes a new tunnel. + * Use: Opens a tunnel device. This will run with root privileges + * even if the rest of the server has dropped them. */ -static tunnel *t_create(peer *p, char **ifn) +static int t_open(char **ifn) { int fd; - tunnel *t; int f; struct unet_info uni; if ((fd = open("/dev/unet", O_RDWR)) < 0) { a_warn("TUN", "-", "unet", "open-error", "/dev/unet", "?ERRNO", A_END); - return (0); + goto fail_0; } - fdflags(fd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC); if ((f = ioctl(fd, UNIOCGIFFLAGS)) < 0 || ioctl(fd, UNIOCSIFFLAGS, f | IFF_POINTOPOINT)) { a_warn("TUN", "-", "unet", "config-error", "?ERRNO", A_END); - close(fd); - return (0); + goto fail_1; } + if (ioctl(t->f.fd, UNIOCGINFO, &uni)) { + a_warn("TUN", "-", "unet", "getinfo-error", "?ERRNO", A_END); + goto fail_1; + } + *ifn = xstrdup(uni.uni_ifname); + return (fd); + +fail_1: + close(fd); +fail_0: + return (-1); +} + +/* --- @t_create@ --- * + * + * Arguments: @peer *p@ = pointer to peer block + * @int fd@ = file descriptor of tunnel device + * @char **ifn@ = where to put the interface name + * + * Returns: A tunnel block if it worked, or null on failure. + * + * Use: Initializes a new tunnel. + */ + +static tunnel *t_create(peer *p, int fd, char **ifn) +{ + tunnel *t; + + fdflags(fd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC); t = CREATE(tunnel); t->ops = &tun_unet; t->p = p; sel_initfile(&sel, &t->f, fd, SEL_READ, t_read, t); sel_addfile(&t->f); - - if (ioctl(t->f.fd, UNIOCGINFO, &uni)) { - a_warn("TUN", "-", "unet", "getinfo-error", "?ERRNO", A_END); - return (0); - } - *ifn = xstrdup(uni.uni_ifname); - T( trace(T_TUNNEL, "tun-unet: attached interface %s to peer `%s'", - *ifn, p_name(p)); ) return (t); } @@ -167,6 +184,7 @@ static void t_destroy(tunnel *t) const tunnel_ops tun_unet = { "unet", t_init, + t_open, t_create, 0, t_inject, -- [mdw]