Add VNC reverse connections, by Eddie Kohler.

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3951 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
balrog 2008-02-03 02:54:04 +00:00
parent 3d575329a5
commit 3aa3eea310
2 changed files with 54 additions and 21 deletions

View File

@ -421,21 +421,21 @@ syntax for the @var{display} is
@table @code @table @code
@item @var{interface}:@var{d} @item @var{host}:@var{d}
TCP connections will only be allowed from @var{interface} on display @var{d}. TCP connections will only be allowed from @var{host} on display @var{d}.
By convention the TCP port is 5900+@var{d}. Optionally, @var{interface} can By convention the TCP port is 5900+@var{d}. Optionally, @var{host} can
be omitted in which case the server will bind to all interfaces. be omitted in which case the server will accept connections from any host.
@item @var{unix}:@var{path} @item @code{unix}:@var{path}
Connections will be allowed over UNIX domain sockets where @var{path} is the Connections will be allowed over UNIX domain sockets where @var{path} is the
location of a unix socket to listen for connections on. location of a unix socket to listen for connections on.
@item none @item none
VNC is initialized by not started. The monitor @code{change} command can be used VNC is initialized but not started. The monitor @code{change} command
to later start the VNC server. can be used to later start the VNC server.
@end table @end table
@ -444,6 +444,13 @@ separated by commas. Valid options are
@table @code @table @code
@item reverse
Connect to a listening VNC client via a ``reverse'' connection. The
client is specified by the @var{display}. For reverse network
connections (@var{host}:@var{d},@code{reverse}), the @var{d} argument
is a TCP port number, not a display number.
@item password @item password
Require that password based authentication is used for client connections. Require that password based authentication is used for client connections.

54
vnc.c
View File

@ -1898,6 +1898,22 @@ static int protocol_version(VncState *vs, uint8_t *version, size_t len)
return 0; return 0;
} }
static void vnc_connect(VncState *vs)
{
VNC_DEBUG("New client on socket %d\n", vs->csock);
socket_set_nonblock(vs->csock);
qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
vnc_write(vs, "RFB 003.008\n", 12);
vnc_flush(vs);
vnc_read_when(vs, protocol_version, 12);
memset(vs->old_data, 0, vs->ds->linesize * vs->ds->height);
memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row));
vs->has_resize = 0;
vs->has_hextile = 0;
vs->ds->dpy_copy = NULL;
vnc_update_client(vs);
}
static void vnc_listen_read(void *opaque) static void vnc_listen_read(void *opaque)
{ {
VncState *vs = opaque; VncState *vs = opaque;
@ -1909,18 +1925,7 @@ static void vnc_listen_read(void *opaque)
vs->csock = accept(vs->lsock, (struct sockaddr *)&addr, &addrlen); vs->csock = accept(vs->lsock, (struct sockaddr *)&addr, &addrlen);
if (vs->csock != -1) { if (vs->csock != -1) {
VNC_DEBUG("New client on socket %d\n", vs->csock); vnc_connect(vs);
socket_set_nonblock(vs->csock);
qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, opaque);
vnc_write(vs, "RFB 003.008\n", 12);
vnc_flush(vs);
vnc_read_when(vs, protocol_version, 12);
memset(vs->old_data, 0, vs->ds->linesize * vs->ds->height);
memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row));
vs->has_resize = 0;
vs->has_hextile = 0;
vs->ds->dpy_copy = NULL;
vnc_update_client(vs);
} }
} }
@ -2087,6 +2092,7 @@ int vnc_display_open(DisplayState *ds, const char *display)
VncState *vs = ds ? (VncState *)ds->opaque : vnc_state; VncState *vs = ds ? (VncState *)ds->opaque : vnc_state;
const char *options; const char *options;
int password = 0; int password = 0;
int reverse = 0;
#if CONFIG_VNC_TLS #if CONFIG_VNC_TLS
int tls = 0, x509 = 0; int tls = 0, x509 = 0;
#endif #endif
@ -2103,6 +2109,8 @@ int vnc_display_open(DisplayState *ds, const char *display)
options++; options++;
if (strncmp(options, "password", 8) == 0) { if (strncmp(options, "password", 8) == 0) {
password = 1; /* Require password auth */ password = 1; /* Require password auth */
} else if (strncmp(options, "reverse", 7) == 0) {
reverse = 1;
#if CONFIG_VNC_TLS #if CONFIG_VNC_TLS
} else if (strncmp(options, "tls", 3) == 0) { } else if (strncmp(options, "tls", 3) == 0) {
tls = 1; /* Require TLS */ tls = 1; /* Require TLS */
@ -2196,7 +2204,9 @@ int vnc_display_open(DisplayState *ds, const char *display)
memset(uaddr.sun_path, 0, 108); memset(uaddr.sun_path, 0, 108);
snprintf(uaddr.sun_path, 108, "%s", p); snprintf(uaddr.sun_path, 108, "%s", p);
unlink(uaddr.sun_path); if (!reverse) {
unlink(uaddr.sun_path);
}
} else } else
#endif #endif
{ {
@ -2210,7 +2220,7 @@ int vnc_display_open(DisplayState *ds, const char *display)
return -1; return -1;
} }
iaddr.sin_port = htons(ntohs(iaddr.sin_port) + 5900); iaddr.sin_port = htons(ntohs(iaddr.sin_port) + (reverse ? 0 : 5900));
vs->lsock = socket(PF_INET, SOCK_STREAM, 0); vs->lsock = socket(PF_INET, SOCK_STREAM, 0);
if (vs->lsock == -1) { if (vs->lsock == -1) {
@ -2233,6 +2243,22 @@ int vnc_display_open(DisplayState *ds, const char *display)
} }
} }
if (reverse) {
if (connect(vs->lsock, addr, addrlen) == -1) {
fprintf(stderr, "Connection to VNC client failed\n");
close(vs->lsock);
vs->lsock = -1;
free(vs->display);
vs->display = NULL;
return -1;
} else {
vs->csock = vs->lsock;
vs->lsock = -1;
vnc_connect(vs);
return 0;
}
}
if (bind(vs->lsock, addr, addrlen) == -1) { if (bind(vs->lsock, addr, addrlen) == -1) {
fprintf(stderr, "bind() failed\n"); fprintf(stderr, "bind() failed\n");
close(vs->lsock); close(vs->lsock);