QEMU supports serving VNC over a unix domain socket rather than traditional TCP host/port. This is specified with: <graphics type='vnc' socket='/foo/bar/baz'/> This provides better security access control than VNC listening on 127.0.0.1, but will cause issues with tools that rely on the lax security (virt-manager in fedora runs as regular user by default, and wouldn't be able to access a socket owned by 'qemu' or 'root'). Also not currently supported by any clients, though I have patches for virt-manager, and virt-viewer should be simple to update. v2: schema: Make listen vs. socket a <choice> Signed-off-by: Cole Robinson <crobinso@xxxxxxxxxx> --- docs/formatdomain.html.in | 6 ++- docs/schemas/domain.rng | 47 +++++++++++------- src/conf/domain_conf.c | 30 +++++++---- src/conf/domain_conf.h | 1 + src/qemu/qemu_command.c | 52 +++++++++++++------- src/qemu/qemu_driver.c | 1 + tests/qemuargv2xmltest.c | 1 + .../qemuxml2argv-graphics-vnc-socket.args | 1 + .../qemuxml2argv-graphics-vnc-socket.xml | 30 +++++++++++ tests/qemuxml2argvtest.c | 1 + 10 files changed, 122 insertions(+), 48 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-graphics-vnc-socket.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-graphics-vnc-socket.xml diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index e9fcea1..fbcff0b 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -1153,7 +1153,11 @@ qemu-kvm -net nic,model=? /dev/null in clear text. The <code>keymap</code> attribute specifies the keymap to use. It is possible to set a limit on the validity of the password be giving an timestamp <code>passwdValidTo='2010-04-09T15:51:00'</code> - assumed to be in UTC. NB, this may not be supported by all hypervisors. + assumed to be in UTC. NB, this may not be supported by all hypervisors.<br> + <br> + Rather than using listen/port, QEMU supports a <code>socket</code> + attribute for listening on a unix domain socket path. + <span class="since">Since 0.8.8</span> </dd> <dt><code>"spice"</code></dt> <dd> diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng index 9c1e9bb..1907e49 100644 --- a/docs/schemas/domain.rng +++ b/docs/schemas/domain.rng @@ -1104,24 +1104,35 @@ <attribute name="type"> <value>vnc</value> </attribute> - <optional> - <attribute name="port"> - <ref name="PortNumber"/> - </attribute> - </optional> - <optional> - <attribute name="autoport"> - <choice> - <value>yes</value> - <value>no</value> - </choice> - </attribute> - </optional> - <optional> - <attribute name="listen"> - <ref name="addrIP"/> - </attribute> - </optional> + <choice> + <group> + <optional> + <attribute name="port"> + <ref name="PortNumber"/> + </attribute> + </optional> + <optional> + <attribute name="autoport"> + <choice> + <value>yes</value> + <value>no</value> + </choice> + </attribute> + </optional> + <optional> + <attribute name="listen"> + <ref name="addrIP"/> + </attribute> + </optional> + </group> + <group> + <optional> + <attribute name="socket"> + <ref name="absFilePath"/> + </attribute> + </optional> + </group> + </choice> <optional> <attribute name="passwd"> <text/> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 5b1c907..4621ae2 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -477,6 +477,7 @@ void virDomainGraphicsDefFree(virDomainGraphicsDefPtr def) switch (def->type) { case VIR_DOMAIN_GRAPHICS_TYPE_VNC: VIR_FREE(def->data.vnc.listenAddr); + VIR_FREE(def->data.vnc.socket); VIR_FREE(def->data.vnc.keymap); virDomainGraphicsAuthDefClear(&def->data.vnc.auth); break; @@ -3365,6 +3366,7 @@ virDomainGraphicsDefParseXML(xmlNodePtr node, int flags) { } def->data.vnc.listenAddr = virXMLPropString(node, "listen"); + def->data.vnc.socket = virXMLPropString(node, "socket"); def->data.vnc.keymap = virXMLPropString(node, "keymap"); if (virDomainGraphicsAuthDefParseXML(node, &def->data.vnc.auth) < 0) @@ -6868,19 +6870,25 @@ virDomainGraphicsDefFormat(virBufferPtr buf, switch (def->type) { case VIR_DOMAIN_GRAPHICS_TYPE_VNC: - if (def->data.vnc.port && - (!def->data.vnc.autoport || !(flags & VIR_DOMAIN_XML_INACTIVE))) - virBufferVSprintf(buf, " port='%d'", - def->data.vnc.port); - else if (def->data.vnc.autoport) - virBufferAddLit(buf, " port='-1'"); + if (def->data.vnc.socket) { + if (def->data.vnc.socket) + virBufferVSprintf(buf, " socket='%s'", + def->data.vnc.socket); + } else { + if (def->data.vnc.port && + (!def->data.vnc.autoport || !(flags & VIR_DOMAIN_XML_INACTIVE))) + virBufferVSprintf(buf, " port='%d'", + def->data.vnc.port); + else if (def->data.vnc.autoport) + virBufferAddLit(buf, " port='-1'"); - virBufferVSprintf(buf, " autoport='%s'", - def->data.vnc.autoport ? "yes" : "no"); + virBufferVSprintf(buf, " autoport='%s'", + def->data.vnc.autoport ? "yes" : "no"); - if (def->data.vnc.listenAddr) - virBufferVSprintf(buf, " listen='%s'", - def->data.vnc.listenAddr); + if (def->data.vnc.listenAddr) + virBufferVSprintf(buf, " listen='%s'", + def->data.vnc.listenAddr); + } if (def->data.vnc.keymap) virBufferEscapeString(buf, " keymap='%s'", diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 3da26e9..8c637b9 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -574,6 +574,7 @@ struct _virDomainGraphicsDef { unsigned int autoport :1; char *listenAddr; char *keymap; + char *socket; virDomainGraphicsAuthDef auth; } vnc; struct { diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index a0075a4..8e86f43 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -3512,7 +3512,11 @@ qemuBuildCommandLine(virConnectPtr conn, def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) { virBuffer opt = VIR_BUFFER_INITIALIZER; - if (qemuCmdFlags & QEMUD_CMD_FLAG_VNC_COLON) { + if (def->graphics[0]->data.vnc.socket) { + virBufferVSprintf(&opt, "unix:%s", + def->graphics[0]->data.vnc.socket); + + } else if (qemuCmdFlags & QEMUD_CMD_FLAG_VNC_COLON) { if (def->graphics[0]->data.vnc.listenAddr) virBufferAdd(&opt, def->graphics[0]->data.vnc.listenAddr, -1); else if (driver->vncListen) @@ -3521,6 +3525,12 @@ qemuBuildCommandLine(virConnectPtr conn, virBufferVSprintf(&opt, ":%d", def->graphics[0]->data.vnc.port - 5900); + } else { + virBufferVSprintf(&opt, "%d", + def->graphics[0]->data.vnc.port - 5900); + } + + if (qemuCmdFlags & QEMUD_CMD_FLAG_VNC_COLON) { if (def->graphics[0]->data.vnc.auth.passwd || driver->vncPassword) virBufferAddLit(&opt, ",password"); @@ -3545,9 +3555,6 @@ qemuBuildCommandLine(virConnectPtr conn, /* TODO: Support ACLs later */ } - } else { - virBufferVSprintf(&opt, "%d", - def->graphics[0]->data.vnc.port - 5900); } virCommandAddArg(cmd, "-vnc"); @@ -5175,24 +5182,33 @@ virDomainDefPtr qemuParseCommandLine(virCapsPtr caps, goto no_memory; vnc->type = VIR_DOMAIN_GRAPHICS_TYPE_VNC; - tmp = strchr(val, ':'); - if (tmp) { - char *opts; - if (virStrToLong_i(tmp+1, &opts, 10, &vnc->data.vnc.port) < 0) { - VIR_FREE(vnc); - qemuReportError(VIR_ERR_INTERNAL_ERROR, \ - _("cannot parse VNC port '%s'"), tmp+1); - goto error; - } - vnc->data.vnc.listenAddr = strndup(val, tmp-val); - if (!vnc->data.vnc.listenAddr) { + if (STRPREFIX(val, "unix:")) { + vnc->data.vnc.socket = strdup(val + 5); + if (!vnc->data.vnc.socket) { VIR_FREE(vnc); goto no_memory; } - vnc->data.vnc.port += 5900; - vnc->data.vnc.autoport = 0; } else { - vnc->data.vnc.autoport = 1; + tmp = strchr(val, ':'); + if (tmp) { + char *opts; + if (virStrToLong_i(tmp+1, &opts, 10, + &vnc->data.vnc.port) < 0) { + VIR_FREE(vnc); + qemuReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot parse VNC port '%s'"), tmp+1); + goto error; + } + vnc->data.vnc.listenAddr = strndup(val, tmp-val); + if (!vnc->data.vnc.listenAddr) { + VIR_FREE(vnc); + goto no_memory; + } + vnc->data.vnc.port += 5900; + vnc->data.vnc.autoport = 0; + } else { + vnc->data.vnc.autoport = 1; + } } if (VIR_REALLOC_N(def->graphics, def->ngraphics+1) < 0) { diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index a56b2f4..8a9ed42 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -2672,6 +2672,7 @@ static int qemudStartVMDaemon(virConnectPtr conn, if (vm->def->ngraphics == 1) { if (vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC && + !vm->def->graphics[0]->data.vnc.socket && vm->def->graphics[0]->data.vnc.autoport) { int port = qemudNextFreePort(driver, QEMU_VNC_PORT_MIN); if (port < 0) { diff --git a/tests/qemuargv2xmltest.c b/tests/qemuargv2xmltest.c index 8338af3..7499ba0 100644 --- a/tests/qemuargv2xmltest.c +++ b/tests/qemuargv2xmltest.c @@ -178,6 +178,7 @@ mymain(int argc, char **argv) DO_TEST("disk-drive-network-sheepdog"); DO_TEST("disk-usb"); DO_TEST("graphics-vnc"); + DO_TEST("graphics-vnc-socket"); driver.vncSASL = 1; driver.vncSASLdir = strdup("/root/.sasl2"); diff --git a/tests/qemuxml2argvdata/qemuxml2argv-graphics-vnc-socket.args b/tests/qemuxml2argvdata/qemuxml2argv-graphics-vnc-socket.args new file mode 100644 index 0000000..055c562 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-graphics-vnc-socket.args @@ -0,0 +1 @@ +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test QEMU_AUDIO_DRV=none /usr/bin/qemu -S -M pc -m 214 -smp 1 -monitor unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -serial none -parallel none -usb -vnc unix:/tmp/foo.socket diff --git a/tests/qemuxml2argvdata/qemuxml2argv-graphics-vnc-socket.xml b/tests/qemuxml2argvdata/qemuxml2argv-graphics-vnc-socket.xml new file mode 100644 index 0000000..d6ad72b --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-graphics-vnc-socket.xml @@ -0,0 +1,30 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory>219200</memory> + <currentMemory>219200</currentMemory> + <vcpu>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + <address type='drive' controller='0' bus='0' unit='0'/> + </disk> + <controller type='ide' index='0'/> + <input type='mouse' bus='ps2'/> + <graphics type='vnc' socket='/tmp/foo.socket'/> + <video> + <model type='cirrus' vram='9216' heads='1'/> + </video> + <memballoon model='virtio'/> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 6760f67..8a1d5f7 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -316,6 +316,7 @@ mymain(int argc, char **argv) DO_TEST("disk-scsi-device-auto", QEMUD_CMD_FLAG_DRIVE | QEMUD_CMD_FLAG_DEVICE | QEMUD_CMD_FLAG_NODEFCONFIG, false); DO_TEST("graphics-vnc", 0, false); + DO_TEST("graphics-vnc-socket", 0, false); driver.vncSASL = 1; driver.vncSASLdir = strdup("/root/.sasl2"); -- 1.7.3.2 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list