nbd: enable use of TLS with nbd-server-start command

This modifies the nbd-server-start QMP command so that it
is possible to request use of TLS. This is done by adding
a new optional parameter "tls-creds" which provides the ID
of a previously created QCryptoTLSCreds object instance.

TLS is only supported when using an IPv4/IPv6 socket listener.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-Id: <1455129674-17255-17-git-send-email-berrange@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Daniel P. Berrange 2016-02-10 18:41:14 +00:00 committed by Paolo Bonzini
parent 145614a112
commit ddffee3904
4 changed files with 105 additions and 25 deletions

View file

@ -20,42 +20,126 @@
#include "block/nbd.h"
#include "io/channel-socket.h"
static QIOChannelSocket *server_ioc;
static int server_watch = -1;
typedef struct NBDServerData {
QIOChannelSocket *listen_ioc;
int watch;
QCryptoTLSCreds *tlscreds;
} NBDServerData;
static NBDServerData *nbd_server;
static gboolean nbd_accept(QIOChannel *ioc, GIOCondition condition,
gpointer opaque)
{
QIOChannelSocket *cioc;
if (!nbd_server) {
return FALSE;
}
cioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc),
NULL);
if (!cioc) {
return TRUE;
}
nbd_client_new(NULL, cioc, NULL, NULL, nbd_client_put);
nbd_client_new(NULL, cioc,
nbd_server->tlscreds, NULL,
nbd_client_put);
object_unref(OBJECT(cioc));
return TRUE;
}
void qmp_nbd_server_start(SocketAddress *addr, Error **errp)
static void nbd_server_free(NBDServerData *server)
{
if (server_ioc) {
if (!server) {
return;
}
if (server->watch != -1) {
g_source_remove(server->watch);
}
object_unref(OBJECT(server->listen_ioc));
if (server->tlscreds) {
object_unref(OBJECT(server->tlscreds));
}
g_free(server);
}
static QCryptoTLSCreds *nbd_get_tls_creds(const char *id, Error **errp)
{
Object *obj;
QCryptoTLSCreds *creds;
obj = object_resolve_path_component(
object_get_objects_root(), id);
if (!obj) {
error_setg(errp, "No TLS credentials with id '%s'",
id);
return NULL;
}
creds = (QCryptoTLSCreds *)
object_dynamic_cast(obj, TYPE_QCRYPTO_TLS_CREDS);
if (!creds) {
error_setg(errp, "Object with id '%s' is not TLS credentials",
id);
return NULL;
}
if (creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
error_setg(errp,
"Expecting TLS credentials with a server endpoint");
return NULL;
}
object_ref(obj);
return creds;
}
void qmp_nbd_server_start(SocketAddress *addr,
bool has_tls_creds, const char *tls_creds,
Error **errp)
{
if (nbd_server) {
error_setg(errp, "NBD server already running");
return;
}
server_ioc = qio_channel_socket_new();
if (qio_channel_socket_listen_sync(server_ioc, addr, errp) < 0) {
return;
nbd_server = g_new0(NBDServerData, 1);
nbd_server->watch = -1;
nbd_server->listen_ioc = qio_channel_socket_new();
if (qio_channel_socket_listen_sync(
nbd_server->listen_ioc, addr, errp) < 0) {
goto error;
}
server_watch = qio_channel_add_watch(QIO_CHANNEL(server_ioc),
G_IO_IN,
nbd_accept,
NULL,
NULL);
if (has_tls_creds) {
nbd_server->tlscreds = nbd_get_tls_creds(tls_creds, errp);
if (!nbd_server->tlscreds) {
goto error;
}
if (addr->type != SOCKET_ADDRESS_KIND_INET) {
error_setg(errp, "TLS is only supported with IPv4/IPv6");
goto error;
}
}
nbd_server->watch = qio_channel_add_watch(
QIO_CHANNEL(nbd_server->listen_ioc),
G_IO_IN,
nbd_accept,
NULL,
NULL);
return;
error:
nbd_server_free(nbd_server);
nbd_server = NULL;
}
void qmp_nbd_server_add(const char *device, bool has_writable, bool writable,
@ -64,7 +148,7 @@ void qmp_nbd_server_add(const char *device, bool has_writable, bool writable,
BlockBackend *blk;
NBDExport *exp;
if (!server_ioc) {
if (!nbd_server) {
error_setg(errp, "NBD server not running");
return;
}
@ -110,12 +194,6 @@ void qmp_nbd_server_stop(Error **errp)
{
nbd_export_close_all();
if (server_watch != -1) {
g_source_remove(server_watch);
server_watch = -1;
}
if (server_ioc) {
object_unref(OBJECT(server_ioc));
server_ioc = NULL;
}
nbd_server_free(nbd_server);
nbd_server = NULL;
}

2
hmp.c
View file

@ -1793,7 +1793,7 @@ void hmp_nbd_server_start(Monitor *mon, const QDict *qdict)
goto exit;
}
qmp_nbd_server_start(addr, &local_err);
qmp_nbd_server_start(addr, false, NULL, &local_err);
qapi_free_SocketAddress(addr);
if (local_err != NULL) {
goto exit;

View file

@ -146,13 +146,15 @@
# QEMU instance could refer to them as "nbd:HOST:PORT:exportname=NAME".
#
# @addr: Address on which to listen.
# @tls-creds: (optional) ID of the TLS credentials object. Since 2.6
#
# Returns: error if the server is already running.
#
# Since: 1.3.0
##
{ 'command': 'nbd-server-start',
'data': { 'addr': 'SocketAddress' } }
'data': { 'addr': 'SocketAddress',
'*tls-creds': 'str'} }
##
# @nbd-server-add:

View file

@ -3825,7 +3825,7 @@ EQMP
{
.name = "nbd-server-start",
.args_type = "addr:q",
.args_type = "addr:q,tls-creds:s?",
.mhandler.cmd_new = qmp_marshal_nbd_server_start,
},
{