예제 #1
0
static int tcp_chr_wait_connected(Chardev *chr, Error **errp)
{
    SocketChardev *s = SOCKET_CHARDEV(chr);
    QIOChannelSocket *sioc;

    /* It can't wait on s->connected, since it is set asynchronously
     * in TLS and telnet cases, only wait for an accepted socket */
    while (!s->ioc) {
        if (s->is_listen) {
            error_report("QEMU waiting for connection on: %s",
                         chr->filename);
            qio_channel_set_blocking(QIO_CHANNEL(s->listen_ioc), true, NULL);
            tcp_chr_accept(QIO_CHANNEL(s->listen_ioc), G_IO_IN, chr);
            qio_channel_set_blocking(QIO_CHANNEL(s->listen_ioc), false, NULL);
        } else {
            sioc = qio_channel_socket_new();
            tcp_chr_set_client_ioc_name(chr, sioc);
            if (qio_channel_socket_connect_sync(sioc, s->addr, errp) < 0) {
                object_unref(OBJECT(sioc));
                return -1;
            }
            tcp_chr_new_client(chr, sioc);
            object_unref(OBJECT(sioc));
        }
    }

    return 0;
}
예제 #2
0
static int tcp_chr_new_client(Chardev *chr, QIOChannelSocket *sioc)
{
    SocketChardev *s = SOCKET_CHARDEV(chr);

    if (s->ioc != NULL) {
        return -1;
    }

    s->ioc = QIO_CHANNEL(sioc);
    object_ref(OBJECT(sioc));
    s->sioc = sioc;
    object_ref(OBJECT(sioc));

    qio_channel_set_blocking(s->ioc, false, NULL);

    if (s->do_nodelay) {
        qio_channel_set_delay(s->ioc, false);
    }
    if (s->listen_tag) {
        g_source_remove(s->listen_tag);
        s->listen_tag = 0;
    }

    if (s->tls_creds) {
        tcp_chr_tls_init(chr);
    } else {
        if (s->do_telnetopt) {
            tcp_chr_telnet_init(chr);
        } else {
            tcp_chr_connect(chr);
        }
    }

    return 0;
}
예제 #3
0
파일: channel-tls.c 프로젝트: JMR-b/qemu
static int qio_channel_tls_set_blocking(QIOChannel *ioc,
                                        bool enabled,
                                        Error **errp)
{
    QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);

    return qio_channel_set_blocking(tioc->master, enabled, errp);
}
예제 #4
0
static int qio_channel_websock_set_blocking(QIOChannel *ioc,
                                            bool enabled,
                                            Error **errp)
{
    QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK(ioc);

    qio_channel_set_blocking(wioc->master, enabled, errp);
    return 0;
}
예제 #5
0
/* This thread receives all data using iovecs */
static gpointer test_io_thread_reader(gpointer opaque)
{
    QIOChannelTest *data = opaque;

    qio_channel_set_blocking(data->dst, data->blocking, NULL);

    qio_channel_readv_all(data->dst,
                          data->outputv,
                          data->niov,
                          &data->readerr);

    return NULL;
}
예제 #6
0
/* This thread sends all data using iovecs */
static gpointer test_io_thread_writer(gpointer opaque)
{
    QIOChannelTest *data = opaque;

    qio_channel_set_blocking(data->src, data->blocking, NULL);

    qio_channel_writev_all(data->src,
                           data->inputv,
                           data->niov,
                           &data->writeerr);

    return NULL;
}
예제 #7
0
/*
 * This tests validation checking of peer certificates
 *
 * This is replicating the checks that are done for an
 * active TLS session after handshake completes. To
 * simulate that we create our TLS contexts, skipping
 * sanity checks. When then get a socketpair, and
 * initiate a TLS session across them. Finally do
 * do actual cert validation tests
 */
static void test_io_channel_tls(const void *opaque)
{
    struct QIOChannelTLSTestData *data =
        (struct QIOChannelTLSTestData *)opaque;
    QCryptoTLSCreds *clientCreds;
    QCryptoTLSCreds *serverCreds;
    QIOChannelTLS *clientChanTLS;
    QIOChannelTLS *serverChanTLS;
    QIOChannelSocket *clientChanSock;
    QIOChannelSocket *serverChanSock;
    qemu_acl *acl;
    const char * const *wildcards;
    int channel[2];
    struct QIOChannelTLSHandshakeData clientHandshake = { false, false };
    struct QIOChannelTLSHandshakeData serverHandshake = { false, false };
    Error *err = NULL;
    QIOChannelTest *test;
    GMainContext *mainloop;

    /* We'll use this for our fake client-server connection */
    g_assert(socketpair(AF_UNIX, SOCK_STREAM, 0, channel) == 0);

#define CLIENT_CERT_DIR "tests/test-crypto-tlssession-client/"
#define SERVER_CERT_DIR "tests/test-crypto-tlssession-server/"
    mkdir(CLIENT_CERT_DIR, 0700);
    mkdir(SERVER_CERT_DIR, 0700);

    unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT);
    unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_CERT);
    unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_KEY);

    unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT);
    unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_CERT);
    unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_KEY);

    g_assert(link(data->servercacrt,
                  SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT) == 0);
    g_assert(link(data->servercrt,
                  SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_CERT) == 0);
    g_assert(link(KEYFILE,
                  SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_KEY) == 0);

    g_assert(link(data->clientcacrt,
                  CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT) == 0);
    g_assert(link(data->clientcrt,
                  CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_CERT) == 0);
    g_assert(link(KEYFILE,
                  CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_KEY) == 0);

    clientCreds = test_tls_creds_create(
        QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT,
        CLIENT_CERT_DIR,
        &err);
    g_assert(clientCreds != NULL);

    serverCreds = test_tls_creds_create(
        QCRYPTO_TLS_CREDS_ENDPOINT_SERVER,
        SERVER_CERT_DIR,
        &err);
    g_assert(serverCreds != NULL);

    acl = qemu_acl_init("channeltlsacl");
    qemu_acl_reset(acl);
    wildcards = data->wildcards;
    while (wildcards && *wildcards) {
        qemu_acl_append(acl, 0, *wildcards);
        wildcards++;
    }

    clientChanSock = qio_channel_socket_new_fd(
        channel[0], &err);
    g_assert(clientChanSock != NULL);
    serverChanSock = qio_channel_socket_new_fd(
        channel[1], &err);
    g_assert(serverChanSock != NULL);

    /*
     * We have an evil loop to do the handshake in a single
     * thread, so we need these non-blocking to avoid deadlock
     * of ourselves
     */
    qio_channel_set_blocking(QIO_CHANNEL(clientChanSock), false, NULL);
    qio_channel_set_blocking(QIO_CHANNEL(serverChanSock), false, NULL);

    /* Now the real part of the test, setup the sessions */
    clientChanTLS = qio_channel_tls_new_client(
        QIO_CHANNEL(clientChanSock), clientCreds,
        data->hostname, &err);
    g_assert(clientChanTLS != NULL);

    serverChanTLS = qio_channel_tls_new_server(
        QIO_CHANNEL(serverChanSock), serverCreds,
        "channeltlsacl", &err);
    g_assert(serverChanTLS != NULL);

    qio_channel_tls_handshake(clientChanTLS,
                              test_tls_handshake_done,
                              &clientHandshake,
                              NULL);
    qio_channel_tls_handshake(serverChanTLS,
                              test_tls_handshake_done,
                              &serverHandshake,
                              NULL);

    /*
     * Finally we loop around & around doing handshake on each
     * session until we get an error, or the handshake completes.
     * This relies on the socketpair being nonblocking to avoid
     * deadlocking ourselves upon handshake
     */
    mainloop = g_main_context_default();
    do {
        g_main_context_iteration(mainloop, TRUE);
    } while (!clientHandshake.finished &&
             !serverHandshake.finished);

    g_assert(clientHandshake.failed == data->expectClientFail);
    g_assert(serverHandshake.failed == data->expectServerFail);

    test = qio_channel_test_new();
    qio_channel_test_run_threads(test, false,
                                 QIO_CHANNEL(clientChanTLS),
                                 QIO_CHANNEL(serverChanTLS));
    qio_channel_test_validate(test);

    test = qio_channel_test_new();
    qio_channel_test_run_threads(test, true,
                                 QIO_CHANNEL(clientChanTLS),
                                 QIO_CHANNEL(serverChanTLS));
    qio_channel_test_validate(test);

    unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT);
    unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_CERT);
    unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_KEY);

    unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT);
    unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_CERT);
    unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_KEY);

    rmdir(CLIENT_CERT_DIR);
    rmdir(SERVER_CERT_DIR);

    object_unparent(OBJECT(serverCreds));
    object_unparent(OBJECT(clientCreds));

    object_unref(OBJECT(serverChanTLS));
    object_unref(OBJECT(clientChanTLS));

    object_unref(OBJECT(serverChanSock));
    object_unref(OBJECT(clientChanSock));

    close(channel[0]);
    close(channel[1]);
}
예제 #8
0
void nbd_client_close(BlockDriverState *bs)
{
    NbdClientSession *client = nbd_get_client_session(bs);
    struct nbd_request request = {
        .type = NBD_CMD_DISC,
        .from = 0,
        .len = 0
    };

    if (client->ioc == NULL) {
        return;
    }

    nbd_send_request(client->ioc, &request);

    nbd_teardown_connection(bs);
}

int nbd_client_init(BlockDriverState *bs,
                    QIOChannelSocket *sioc,
                    const char *export,
                    QCryptoTLSCreds *tlscreds,
                    const char *hostname,
                    Error **errp)
{
    NbdClientSession *client = nbd_get_client_session(bs);
    int ret;

    /* NBD handshake */
    logout("session init %s\n", export);
    qio_channel_set_blocking(QIO_CHANNEL(sioc), true, NULL);

    ret = nbd_receive_negotiate(QIO_CHANNEL(sioc), export,
                                &client->nbdflags,
                                tlscreds, hostname,
                                &client->ioc,
                                &client->size, errp);
    if (ret < 0) {
        logout("Failed to negotiate with the NBD server\n");
        return ret;
    }

    qemu_co_mutex_init(&client->send_mutex);
    qemu_co_mutex_init(&client->free_sema);
    client->sioc = sioc;
    object_ref(OBJECT(client->sioc));

    if (!client->ioc) {
        client->ioc = QIO_CHANNEL(sioc);
        object_ref(OBJECT(client->ioc));
    }

    /* Now that we're connected, set the socket to be non-blocking and
     * kick the reply mechanism.  */
    qio_channel_set_blocking(QIO_CHANNEL(sioc), false, NULL);

    nbd_client_attach_aio_context(bs, bdrv_get_aio_context(bs));

    logout("Established connection with NBD server\n");
    return 0;
}