diff --git a/usr.sbin/bhyve/bhyve.8 b/usr.sbin/bhyve/bhyve.8 --- a/usr.sbin/bhyve/bhyve.8 +++ b/usr.sbin/bhyve/bhyve.8 @@ -873,7 +873,7 @@ .Bl -bullet .Sm off .It -.Op Cm rfb= Ar ip-and-port +.Op Cm rfb= Ar address .Op Cm ,w= Ar width .Op Cm ,h= Ar height .Op Cm ,vga= Ar vgaconf @@ -884,9 +884,9 @@ .Pp Configuration options are defined as follows: .Bl -tag -width 10n -.It Cm rfb= Ns Ar ip-and-port Pq or Cm tcp= Ns Ar ip-and-port -An IP address and a port VNC should listen on. -There are two formats: +.It Cm rfb= Ns Ar address Pq or Cm tcp= Ns Ar address +A UNIX domain socket or IP address and a port VNC should listen on. +There are three possible formats: .Pp .Bl -bullet -compact .It @@ -898,11 +898,15 @@ .Sm off .Cm \&[ Ar IPv6%zone Cm \&] Cm \&: Ar port .Sm on +.It +.Sm off +.Ar /path/to/socket.sock +.Sm on .El .Pp The default is to listen on localhost IPv4 address and default VNC port 5900. An IPv6 address must be enclosed in square brackets and may contain an -optional zone identifier. +optional zone identifier. A UNIX domain socket path must be absolute. .It Cm w= Ns Ar width No and Cm h= Ns Ar height A display resolution, width and height, respectively. If not specified, a default resolution of 1024x768 pixels will be used. diff --git a/usr.sbin/bhyve/bhyve_config.5 b/usr.sbin/bhyve/bhyve_config.5 --- a/usr.sbin/bhyve/bhyve_config.5 +++ b/usr.sbin/bhyve/bhyve_config.5 @@ -520,7 +520,7 @@ a MAC address is generated from a hash of the device's PCI address. .El .Ss Frame Buffer Settings -.Bl -column "password" "[IP:]port" "127.0.0.1:5900" +.Bl -column "password" "/my/unix.sock" "127.0.0.1:5900" .It Sy Name Ta Sy Format Ta Sy Default Ta Sy Description .It Va wait Ta bool Ta false Ta Wait for a remote connection before starting the VM. @@ -532,6 +532,8 @@ .Xr getaddrinfo 3 . A bare port number may be given in which case the IPv4 localhost address is used. +.It Va rfb Ta Ar /my/unix.sock Ta Ta +Alternatively, provide an absolute path for a UNIX domain socket. .It Va vga Ta string Ta io Ta VGA configuration. More details are provided in diff --git a/usr.sbin/bhyve/pci_fbuf.c b/usr.sbin/bhyve/pci_fbuf.c --- a/usr.sbin/bhyve/pci_fbuf.c +++ b/usr.sbin/bhyve/pci_fbuf.c @@ -252,6 +252,7 @@ value = get_config_value_node(nvl, "tcp"); if (value != NULL) { /* + * UNIX -- /path/to/socket.sock * IPv4 -- host-ip:port * IPv6 -- [host-ip%zone]:port * XXX for now port is mandatory for IPv4. @@ -279,6 +280,8 @@ value); return (-1); } + } else if (value[0] == '/') { + sc->rfb_host = strdup(value); } else { cp = strchr(value, ':'); if (cp == NULL) { diff --git a/usr.sbin/bhyve/rfb.c b/usr.sbin/bhyve/rfb.c --- a/usr.sbin/bhyve/rfb.c +++ b/usr.sbin/bhyve/rfb.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -1261,6 +1262,7 @@ struct rfb_softc *rc; struct addrinfo *ai = NULL; struct addrinfo hints; + struct sockaddr_un sun; int on = 1; int cnt; #ifndef WITHOUT_CAPSICUM @@ -1301,25 +1303,38 @@ hostname = "[::1]"; #endif - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV | AI_PASSIVE; - - if ((e = getaddrinfo(hostname, servname, &hints, &ai)) != 0) { - EPRINTLN("getaddrinfo: %s", gai_strerror(e)); - goto error; + if (hostname[0] == '/') { + memset(&sun, 0, sizeof(sun)); + sun.sun_family = AF_UNIX; + strncpy(sun.sun_path, hostname, sizeof(sun.sun_path) - 1); + rc->sfd = socket(AF_UNIX, SOCK_STREAM, 0); + } else { + memset(&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_STREAM; + hints.ai_family = AF_UNSPEC; + hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV | AI_PASSIVE; + + if ((e = getaddrinfo(hostname, servname, &hints, &ai)) != 0) { + EPRINTLN("getaddrinfo: %s", gai_strerror(e)); + goto error; + } + rc->sfd = socket(ai->ai_family, ai->ai_socktype, 0); } - rc->sfd = socket(ai->ai_family, ai->ai_socktype, 0); if (rc->sfd < 0) { perror("socket"); goto error; } + /* No effect for UNIX domain sockets. */ setsockopt(rc->sfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); - if (bind(rc->sfd, ai->ai_addr, ai->ai_addrlen) < 0) { + if (hostname[0] == '/') { + unlink(hostname); + e = bind(rc->sfd, (struct sockaddr *)&sun, SUN_LEN(&sun)); + } else + e = bind(rc->sfd, ai->ai_addr, ai->ai_addrlen); + if (e < 0) { perror("bind"); goto error; } @@ -1355,13 +1370,14 @@ DPRINTF(("rfb client connected")); } - freeaddrinfo(ai); + if (hostname[0] != '/') + freeaddrinfo(ai); return (0); error: if (rc->pixfmt_mtx) pthread_mutex_destroy(&rc->pixfmt_mtx); - if (ai != NULL) + if (hostname[0] != '/' && ai != NULL) freeaddrinfo(ai); if (rc->sfd != -1) close(rc->sfd);