summaryrefslogtreecommitdiff
path: root/usr.sbin/vmd
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/vmd')
-rw-r--r--usr.sbin/vmd/Makefile4
-rw-r--r--usr.sbin/vmd/config.c41
-rw-r--r--usr.sbin/vmd/priv.c173
-rw-r--r--usr.sbin/vmd/proc.c12
-rw-r--r--usr.sbin/vmd/proc.h6
-rw-r--r--usr.sbin/vmd/vmd.c39
-rw-r--r--usr.sbin/vmd/vmd.h25
-rw-r--r--usr.sbin/vmd/vmm.c16
8 files changed, 282 insertions, 34 deletions
diff --git a/usr.sbin/vmd/Makefile b/usr.sbin/vmd/Makefile
index 2df31af8f3f..3fe88e58824 100644
--- a/usr.sbin/vmd/Makefile
+++ b/usr.sbin/vmd/Makefile
@@ -1,10 +1,10 @@
-# $OpenBSD: Makefile,v 1.8 2016/09/01 15:38:03 mlarkin Exp $
+# $OpenBSD: Makefile,v 1.9 2016/10/04 17:17:30 reyk Exp $
.if ${MACHINE} == "amd64"
PROG= vmd
SRCS= vmm.c loadfile_elf.c pci.c virtio.c i8259.c mc146818.c
-SRCS+= vmd.c control.c log.c proc.c config.c ns8250.c i8253.c
+SRCS+= vmd.c control.c log.c priv.c proc.c config.c ns8250.c i8253.c
SRCS+= parse.y
CFLAGS+= -Wall -I${.CURDIR}
diff --git a/usr.sbin/vmd/config.c b/usr.sbin/vmd/config.c
index c6ced578967..e3de3abbd35 100644
--- a/usr.sbin/vmd/config.c
+++ b/usr.sbin/vmd/config.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: config.c,v 1.12 2016/09/29 22:42:04 reyk Exp $ */
+/* $OpenBSD: config.c,v 1.13 2016/10/04 17:17:30 reyk Exp $ */
/*
* Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org>
@@ -20,6 +20,9 @@
#include <sys/queue.h>
#include <sys/time.h>
#include <sys/uio.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
#include <stdio.h>
#include <stdlib.h>
@@ -44,6 +47,7 @@ config_init(struct vmd *env)
/* Global configuration */
ps->ps_what[PROC_PARENT] = CONFIG_ALL;
ps->ps_what[PROC_VMM] = CONFIG_VMS;
+ ps->ps_what[PROC_PRIV] = 0;
/* Other configuration */
what = ps->ps_what[privsep_process];
@@ -110,6 +114,8 @@ config_getvm(struct privsep *ps, struct vm_create_params *vcp,
int fd, ttys_fd;
int kernfd = -1, *diskfds = NULL, *tapfds = NULL;
int saved_errno = 0;
+ char ptyname[VM_TTYNAME_MAX];
+ char ifname[IF_NAMESIZE];
errno = 0;
@@ -149,13 +155,15 @@ config_getvm(struct privsep *ps, struct vm_create_params *vcp,
TAILQ_INSERT_TAIL(env->vmd_vms, vm, vm_entry);
- if (privsep_process != PROC_PARENT) {
+ switch (privsep_process) {
+ case PROC_VMM:
if (kernel_fd == -1) {
log_debug("invalid kernel fd");
goto fail;
}
vm->vm_kernel = kernel_fd;
- } else {
+ break;
+ case PROC_PARENT:
diskfds = reallocarray(NULL, vcp->vcp_ndisks, sizeof(*diskfds));
if (diskfds == NULL) {
saved_errno = errno;
@@ -197,16 +205,22 @@ config_getvm(struct privsep *ps, struct vm_create_params *vcp,
/* Open disk network interfaces */
for (i = 0 ; i < vcp->vcp_nnics; i++) {
- if ((tapfds[i] = opentap()) == -1) {
+ if ((tapfds[i] = opentap(ifname)) == -1) {
saved_errno = errno;
log_warn("%s: can't open tap", __func__);
goto fail;
}
+
+ if ((vm->vm_ifnames[i] = strdup(ifname)) == NULL) {
+ saved_errno = errno;
+ log_warn("%s: can't save ifname", __func__);
+ goto fail;
+ }
}
/* Open TTY */
- if (openpty(&fd, &ttys_fd,
- vm->vm_ttyname, NULL, NULL) == -1) {
+ if (openpty(&fd, &ttys_fd, ptyname, NULL, NULL) == -1 ||
+ (vm->vm_ttyname = strdup(ptyname)) == NULL) {
saved_errno = errno;
log_warn("%s: can't open tty", __func__);
goto fail;
@@ -229,8 +243,10 @@ config_getvm(struct privsep *ps, struct vm_create_params *vcp,
}
proc_compose_imsg(ps, PROC_VMM, -1,
- IMSG_VMDOP_START_VM_END, vm->vm_vmid, fd,
- vcp, sizeof(*vcp));
+ IMSG_VMDOP_START_VM_END, vm->vm_vmid, fd, NULL, 0);
+ break;
+ default:
+ fatalx("vm received by invalid process");
}
free(diskfds);
@@ -303,10 +319,15 @@ config_getif(struct privsep *ps, struct imsg *imsg)
if (n >= vm->vm_params.vcp_nnics ||
vm->vm_ifs[n] != -1 || imsg->fd == -1) {
log_debug("invalid interface id");
- errno = EINVAL;
- return (-1);
+ goto fail;
}
vm->vm_ifs[n] = imsg->fd;
return (0);
+ fail:
+ if (imsg->fd != -1)
+ close(imsg->fd);
+ errno = EINVAL;
+ return (-1);
+
}
diff --git a/usr.sbin/vmd/priv.c b/usr.sbin/vmd/priv.c
new file mode 100644
index 00000000000..987b38c71e7
--- /dev/null
+++ b/usr.sbin/vmd/priv.c
@@ -0,0 +1,173 @@
+/* $OpenBSD: priv.c,v 1.1 2016/10/04 17:17:30 reyk Exp $ */
+
+/*
+ * Copyright (c) 2016 Reyk Floeter <reyk@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h> /* nitems */
+#include <sys/queue.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/ioctl.h>
+#include <sys/tree.h>
+
+#include <net/if.h>
+
+#include <errno.h>
+#include <event.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include "proc.h"
+#include "vmd.h"
+
+int priv_dispatch_parent(int, struct privsep_proc *, struct imsg *);
+void priv_run(struct privsep *, struct privsep_proc *, void *);
+
+int priv_getiftype(char *, char *, unsigned int *);
+int priv_findname(const char *, const char **);
+
+static struct privsep_proc procs[] = {
+ { "parent", PROC_PARENT, priv_dispatch_parent }
+};
+
+void
+priv(struct privsep *ps, struct privsep_proc *p)
+{
+ proc_run(ps, p, procs, nitems(procs), priv_run, NULL);
+}
+
+void
+priv_run(struct privsep *ps, struct privsep_proc *p, void *arg)
+{
+ struct vmd *env = ps->ps_env;
+
+ /*
+ * no pledge(2) in the "priv" process:
+ * write ioctls are not permitted by pledge.
+ */
+
+ /* Open our own socket for generic interface ioctls */
+ if ((env->vmd_fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
+ fatal("socket");
+}
+
+int
+priv_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg)
+{
+ const char *desct[] = { "tap", "switch", "bridge", NULL };
+ struct privsep *ps = p->p_ps;
+ struct vmop_ifreq vfr;
+ struct vmd *env = ps->ps_env;
+ struct ifreq ifr;
+ char type[IF_NAMESIZE];
+ unsigned int unit;
+
+ switch (imsg->hdr.type) {
+ case IMSG_VMDOP_PRIV_IFDESCR:
+ IMSG_SIZE_CHECK(imsg, &vfr);
+ memcpy(&vfr, imsg->data, sizeof(vfr));
+
+ /* We should not get malicious requests from the parent */
+ if (priv_getiftype(vfr.vfr_name, type, &unit) == -1 ||
+ priv_findname(type, desct) == -1)
+ fatalx("%s: rejected priv operation on interface: %s",
+ __func__, vfr.vfr_name);
+
+ strlcpy(ifr.ifr_name, vfr.vfr_name, sizeof(ifr.ifr_name));
+ ifr.ifr_data = (caddr_t)vfr.vfr_value;
+ if (ioctl(env->vmd_fd, SIOCSIFDESCR, &ifr) < 0)
+ log_warn("SIOCSIFDESCR");
+ break;
+ default:
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+priv_getiftype(char *ifname, char *type, unsigned int *unitptr)
+{
+ const char *errstr;
+ size_t span;
+ unsigned int unit;
+
+ /* Extract the name part */
+ span = strcspn(ifname, "0123456789");
+ if (span == 0 || span >= strlen(ifname) || span >= (IF_NAMESIZE - 1))
+ return (-1);
+ memcpy(type, ifname, span);
+ type[span] = 0;
+
+ /* Now parse the unit (we don't strictly validate the format here) */
+ unit = strtonum(ifname + span, 0, UINT_MAX, &errstr);
+ if (errstr != NULL)
+ return (-1);
+ if (unitptr != NULL)
+ *unitptr = unit;
+
+ return (0);
+}
+
+int
+priv_findname(const char *name, const char **names)
+{
+ unsigned int i;
+
+ for (i = 0; names[i] != NULL; i++) {
+ if (strcmp(name, names[i]) == 0)
+ return (0);
+ }
+
+ return (-1);
+}
+
+/*
+ * Called from the process peer
+ */
+
+int
+vm_priv_ifconfig(struct privsep *ps, struct vmd_vm *vm)
+{
+ struct vm_create_params *vcp = &vm->vm_params;
+ unsigned int i;
+ struct vmop_ifreq vfr;
+
+ for (i = 0; i < VMM_MAX_NICS_PER_VM; i++) {
+ if (vm->vm_ifnames[i] == NULL)
+ break;
+
+ if (strlcpy(vfr.vfr_name, vm->vm_ifnames[i],
+ sizeof(vfr.vfr_name)) >= sizeof(vfr.vfr_name))
+ return (-1);
+
+ /* Description can be truncated */
+ (void)snprintf(vfr.vfr_value, sizeof(vfr.vfr_value),
+ "vm%u-if%u-%s", vm->vm_vmid, i, vcp->vcp_name);
+
+ proc_compose(ps, PROC_PRIV, IMSG_VMDOP_PRIV_IFDESCR,
+ &vfr, sizeof(vfr));
+
+ /* XXX Add interface to bridge/switch */
+ }
+
+ return (0);
+}
diff --git a/usr.sbin/vmd/proc.c b/usr.sbin/vmd/proc.c
index 5e473717b2b..52ab19c2ef8 100644
--- a/usr.sbin/vmd/proc.c
+++ b/usr.sbin/vmd/proc.c
@@ -1,7 +1,7 @@
-/* $OpenBSD: proc.c,v 1.6 2016/09/29 22:42:04 reyk Exp $ */
+/* $OpenBSD: proc.c,v 1.7 2016/10/04 17:17:30 reyk Exp $ */
/*
- * Copyright (c) 2010 - 2014 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2010 - 2016 Reyk Floeter <reyk@openbsd.org>
* Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -498,7 +498,7 @@ proc_run(struct privsep *ps, struct privsep_proc *p,
struct privsep_proc *procs, unsigned int nproc,
void (*run)(struct privsep *, struct privsep_proc *, void *), void *arg)
{
- struct passwd *pw = ps->ps_pw;
+ struct passwd *pw;
const char *root;
struct control_sock *rcs;
@@ -518,6 +518,12 @@ proc_run(struct privsep *ps, struct privsep_proc *p,
fatalx(__func__);
}
+ /* Use non-standard user */
+ if (p->p_pw != NULL)
+ pw = p->p_pw;
+ else
+ pw = ps->ps_pw;
+
/* Change root directory */
if (p->p_chroot != NULL)
root = p->p_chroot;
diff --git a/usr.sbin/vmd/proc.h b/usr.sbin/vmd/proc.h
index b8ebdcc5085..053d9a527f5 100644
--- a/usr.sbin/vmd/proc.h
+++ b/usr.sbin/vmd/proc.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: proc.h,v 1.7 2016/09/29 22:42:04 reyk Exp $ */
+/* $OpenBSD: proc.h,v 1.8 2016/10/04 17:17:30 reyk Exp $ */
/*
* Copyright (c) 2010-2015 Reyk Floeter <reyk@openbsd.org>
@@ -89,6 +89,7 @@ enum privsep_procid {
PROC_PARENT = 0,
PROC_CONTROL,
PROC_VMM,
+ PROC_PRIV,
PROC_MAX,
} privsep_process;
@@ -135,9 +136,10 @@ struct privsep_proc {
struct imsg *);
void (*p_init)(struct privsep *,
struct privsep_proc *);
+ void (*p_shutdown)(void);
const char *p_chroot;
+ struct passwd *p_pw;
struct privsep *p_ps;
- void (*p_shutdown)(void);
};
struct privsep_fd {
diff --git a/usr.sbin/vmd/vmd.c b/usr.sbin/vmd/vmd.c
index c2c12db5e91..c4aadb8419d 100644
--- a/usr.sbin/vmd/vmd.c
+++ b/usr.sbin/vmd/vmd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vmd.c,v 1.30 2016/09/29 22:42:04 reyk Exp $ */
+/* $OpenBSD: vmd.c,v 1.31 2016/10/04 17:17:30 reyk Exp $ */
/*
* Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org>
@@ -49,10 +49,17 @@ int vmd_dispatch_vmm(int, struct privsep_proc *, struct imsg *);
struct vmd *env;
static struct privsep_proc procs[] = {
+ /* Keep "priv" on top as procs[0] */
+ { "priv", PROC_PRIV, NULL, priv },
{ "control", PROC_CONTROL, vmd_dispatch_control, control },
{ "vmm", PROC_VMM, vmd_dispatch_vmm, vmm },
+
};
+/* For the privileged process */
+static struct privsep_proc *proc_priv = &procs[0];
+static struct passwd proc_privpw;
+
int
vmd_dispatch_control(int fd, struct privsep_proc *p, struct imsg *imsg)
{
@@ -176,10 +183,18 @@ vmd_dispatch_vmm(int fd, struct privsep_proc *p, struct imsg *imsg)
errno = vmr.vmr_result;
log_warn("%s: failed to start vm", vcp->vcp_name);
vm_remove(vm);
- } else {
- log_info("%s: started vm %d successfully, tty %s",
- vcp->vcp_name, vcp->vcp_id, vm->vm_ttyname);
+ break;
+ }
+
+ /* Now configure all the interfaces */
+ if (vm_priv_ifconfig(ps, vm) == -1) {
+ log_warn("%s: failed to configure vm", vcp->vcp_name);
+ vm_remove(vm);
+ break;
}
+
+ log_info("%s: started vm %d successfully, tty %s",
+ vcp->vcp_name, vcp->vcp_id, vm->vm_ttyname);
break;
case IMSG_VMDOP_TERMINATE_VM_RESPONSE:
case IMSG_VMDOP_TERMINATE_VM_EVENT:
@@ -196,9 +211,10 @@ vmd_dispatch_vmm(int fd, struct privsep_proc *p, struct imsg *imsg)
case IMSG_VMDOP_GET_INFO_VM_DATA:
IMSG_SIZE_CHECK(imsg, &vir);
memcpy(&vir, imsg->data, sizeof(vir));
- if ((vm = vm_getbyid(vir.vir_info.vir_id)) != NULL)
+ if ((vm = vm_getbyid(vir.vir_info.vir_id)) != NULL) {
(void)strlcpy(vir.vir_ttyname, vm->vm_ttyname,
sizeof(vir.vir_ttyname));
+ }
if (proc_compose_imsg(ps, PROC_CONTROL, -1, imsg->hdr.type,
imsg->hdr.peerid, -1, &vir, sizeof(vir)) == -1) {
vm_remove(vm);
@@ -324,6 +340,7 @@ main(int argc, char **argv)
ps = &env->vmd_ps;
ps->ps_env = env;
+ env->vmd_fd = -1;
if (config_init(env) == -1)
fatal("failed to initialize configuration");
@@ -331,9 +348,9 @@ main(int argc, char **argv)
if ((ps->ps_pw = getpwnam(VMD_USER)) == NULL)
fatal("unknown user %s", VMD_USER);
- /* Configure the control socket */
- ps->ps_csock.cs_name = SOCKET_NAME;
- TAILQ_INIT(&ps->ps_rcsocks);
+ /* First proc runs as root without pledge but in default chroot */
+ proc_priv->p_pw = &proc_privpw; /* initialized to all 0 */
+ proc_priv->p_chroot = ps->ps_pw->pw_dir; /* from VMD_USER */
/* Open /dev/vmm */
if (env->vmd_noaction == 0) {
@@ -342,6 +359,10 @@ main(int argc, char **argv)
fatal("%s", VMM_NODE);
}
+ /* Configure the control socket */
+ ps->ps_csock.cs_name = SOCKET_NAME;
+ TAILQ_INIT(&ps->ps_rcsocks);
+
/* Configuration will be parsed after forking the children */
env->vmd_conffile = conffile;
@@ -517,12 +538,14 @@ vm_remove(struct vmd_vm *vm)
for (i = 0; i < VMM_MAX_NICS_PER_VM; i++) {
if (vm->vm_ifs[i] != -1)
close(vm->vm_ifs[i]);
+ free(vm->vm_ifnames[i]);
}
if (vm->vm_kernel != -1)
close(vm->vm_kernel);
if (vm->vm_tty != -1)
close(vm->vm_tty);
+ free(vm->vm_ttyname);
free(vm);
}
diff --git a/usr.sbin/vmd/vmd.h b/usr.sbin/vmd/vmd.h
index 8aacb0dc414..472b2d970d3 100644
--- a/usr.sbin/vmd/vmd.h
+++ b/usr.sbin/vmd/vmd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: vmd.h,v 1.25 2016/09/29 22:42:04 reyk Exp $ */
+/* $OpenBSD: vmd.h,v 1.26 2016/10/04 17:17:30 reyk Exp $ */
/*
* Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org>
@@ -18,9 +18,12 @@
#include <sys/types.h>
#include <sys/queue.h>
+#include <sys/socket.h>
#include <machine/vmmvar.h>
+#include <net/if.h>
+
#include <limits.h>
#include <pthread.h>
@@ -34,7 +37,7 @@
#define SOCKET_NAME "/var/run/vmd.sock"
#define VMM_NODE "/dev/vmm"
#define VM_NAME_MAX 64
-#define VM_TTYNAME_MAX 12
+#define VM_TTYNAME_MAX 16
#define MAX_TAP 256
#define NR_BACKLOG 5
@@ -52,12 +55,13 @@ enum imsg_type {
IMSG_VMDOP_START_VM_RESPONSE,
IMSG_VMDOP_TERMINATE_VM_REQUEST,
IMSG_VMDOP_TERMINATE_VM_RESPONSE,
+ IMSG_VMDOP_TERMINATE_VM_EVENT,
IMSG_VMDOP_GET_INFO_VM_REQUEST,
IMSG_VMDOP_GET_INFO_VM_DATA,
IMSG_VMDOP_GET_INFO_VM_END_DATA,
IMSG_VMDOP_LOAD,
IMSG_VMDOP_RELOAD,
- IMSG_VMDOP_TERMINATE_VM_EVENT
+ IMSG_VMDOP_PRIV_IFDESCR
};
struct vmop_result {
@@ -77,6 +81,12 @@ struct vmop_id {
char vid_name[VMM_MAX_NAME_LEN];
};
+struct vmop_ifreq {
+ uint32_t vfr_id;
+ char vfr_name[IF_NAMESIZE];
+ char vfr_value[VM_NAME_MAX];
+};
+
struct vmd_vm {
struct vm_create_params vm_params;
pid_t vm_pid;
@@ -84,7 +94,8 @@ struct vmd_vm {
int vm_kernel;
int vm_disks[VMM_MAX_DISKS_PER_VM];
int vm_ifs[VMM_MAX_NICS_PER_VM];
- char vm_ttyname[VM_TTYNAME_MAX];
+ char *vm_ifnames[VMM_MAX_NICS_PER_VM];
+ char *vm_ttyname;
int vm_tty;
uint32_t vm_peerid;
TAILQ_ENTRY(vmd_vm) vm_entry;
@@ -115,11 +126,15 @@ struct vmd_vm *vm_getbypid(pid_t);
void vm_remove(struct vmd_vm *);
char *get_string(uint8_t *, size_t);
+/* priv.c */
+void priv(struct privsep *, struct privsep_proc *);
+int vm_priv_ifconfig(struct privsep *, struct vmd_vm *);
+
/* vmm.c */
void vmm(struct privsep *, struct privsep_proc *);
int write_mem(paddr_t, void *buf, size_t);
int read_mem(paddr_t, void *buf, size_t);
-int opentap(void);
+int opentap(char *);
int fd_hasdata(int);
void mutex_lock(pthread_mutex_t *);
void mutex_unlock(pthread_mutex_t *);
diff --git a/usr.sbin/vmd/vmm.c b/usr.sbin/vmd/vmm.c
index f82294c816a..972cbdea3b0 100644
--- a/usr.sbin/vmd/vmm.c
+++ b/usr.sbin/vmd/vmm.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vmm.c,v 1.45 2016/09/29 22:42:04 reyk Exp $ */
+/* $OpenBSD: vmm.c,v 1.46 2016/10/04 17:17:30 reyk Exp $ */
/*
* Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org>
@@ -34,6 +34,8 @@
#include <machine/specialreg.h>
#include <machine/vmmvar.h>
+#include <net/if.h>
+
#include <errno.h>
#include <event.h>
#include <fcntl.h>
@@ -63,7 +65,7 @@ io_fn_t ioports_map[MAX_PORTS];
void vmm_sighdlr(int, short, void *);
int start_client_vmd(void);
-int opentap(void);
+int opentap(char *);
int start_vm(struct imsg *, uint32_t *);
int terminate_vm(struct vm_terminate_params *);
int get_info_vm(struct privsep *, struct imsg *, int);
@@ -374,11 +376,14 @@ terminate_vm(struct vm_terminate_params *vtp)
*
* Opens the next available tap device, up to MAX_TAP.
*
+ * Parameters
+ * ifname: an optional buffer of at least IF_NAMESIZE bytes.
+ *
* Returns a file descriptor to the tap node opened, or -1 if no tap
* devices were available.
*/
int
-opentap(void)
+opentap(char *ifname)
{
int i, fd;
char path[PATH_MAX];
@@ -386,8 +391,11 @@ opentap(void)
for (i = 0; i < MAX_TAP; i++) {
snprintf(path, PATH_MAX, "/dev/tap%d", i);
fd = open(path, O_RDWR | O_NONBLOCK);
- if (fd != -1)
+ if (fd != -1) {
+ if (ifname != NULL)
+ snprintf(ifname, IF_NAMESIZE, "tap%d", i);
return (fd);
+ }
}
return (-1);