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);
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,
}
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:
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 */
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@ --- *
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;
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);
}
const tunnel_ops tun_bsd = {
"bsd",
t_init,
+ t_open,
t_create,
0,
t_inject,
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);
}
const tunnel_ops tun_linux = {
"linux",
t_init,
+ t_open,
t_create,
0,
t_inject,
/* --- @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.
* 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 };
const tunnel_ops tun_slip = {
"slip",
t_init,
+ 0,
t_create,
t_setifname,
t_inject,
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);
}
const tunnel_ops tun_unet = {
"unet",
t_init,
+ t_open,
t_create,
0,
t_inject,