cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

dns-resolver.c (8178B)


      1/*
      2 * QEMU DNS resolver
      3 *
      4 * Copyright (c) 2016 Red Hat, Inc.
      5 *
      6 * This library is free software; you can redistribute it and/or
      7 * modify it under the terms of the GNU Lesser General Public
      8 * License as published by the Free Software Foundation; either
      9 * version 2.1 of the License, or (at your option) any later version.
     10 *
     11 * This library is distributed in the hope that it will be useful,
     12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14 * Lesser General Public License for more details.
     15 *
     16 * You should have received a copy of the GNU Lesser General Public
     17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
     18 *
     19 */
     20
     21#include "qemu/osdep.h"
     22#include "io/dns-resolver.h"
     23#include "qapi/clone-visitor.h"
     24#include "qapi/qapi-visit-sockets.h"
     25#include "qemu/sockets.h"
     26#include "qapi/error.h"
     27#include "qemu/cutils.h"
     28#include "qemu/module.h"
     29
     30#ifndef AI_NUMERICSERV
     31# define AI_NUMERICSERV 0
     32#endif
     33
     34static QIODNSResolver *instance;
     35static GOnce instance_init = G_ONCE_INIT;
     36
     37static gpointer qio_dns_resolve_init_instance(gpointer unused G_GNUC_UNUSED)
     38{
     39    instance = QIO_DNS_RESOLVER(object_new(TYPE_QIO_DNS_RESOLVER));
     40    return NULL;
     41}
     42
     43QIODNSResolver *qio_dns_resolver_get_instance(void)
     44{
     45    g_once(&instance_init, qio_dns_resolve_init_instance, NULL);
     46    return instance;
     47}
     48
     49static int qio_dns_resolver_lookup_sync_inet(QIODNSResolver *resolver,
     50                                             SocketAddress *addr,
     51                                             size_t *naddrs,
     52                                             SocketAddress ***addrs,
     53                                             Error **errp)
     54{
     55    struct addrinfo ai, *res, *e;
     56    InetSocketAddress *iaddr = &addr->u.inet;
     57    char port[33];
     58    char uaddr[INET6_ADDRSTRLEN + 1];
     59    char uport[33];
     60    int rc;
     61    Error *err = NULL;
     62    size_t i;
     63
     64    *naddrs = 0;
     65    *addrs = NULL;
     66
     67    memset(&ai, 0, sizeof(ai));
     68    ai.ai_flags = AI_PASSIVE;
     69    if (iaddr->has_numeric && iaddr->numeric) {
     70        ai.ai_flags |= AI_NUMERICHOST | AI_NUMERICSERV;
     71    }
     72    ai.ai_family = inet_ai_family_from_address(iaddr, &err);
     73    ai.ai_socktype = SOCK_STREAM;
     74
     75    if (err) {
     76        error_propagate(errp, err);
     77        return -1;
     78    }
     79
     80    if (iaddr->host == NULL) {
     81        error_setg(errp, "host not specified");
     82        return -1;
     83    }
     84    if (iaddr->port != NULL) {
     85        pstrcpy(port, sizeof(port), iaddr->port);
     86    } else {
     87        port[0] = '\0';
     88    }
     89
     90    rc = getaddrinfo(strlen(iaddr->host) ? iaddr->host : NULL,
     91                     strlen(port) ? port : NULL, &ai, &res);
     92    if (rc != 0) {
     93        error_setg(errp, "address resolution failed for %s:%s: %s",
     94                   iaddr->host, port, gai_strerror(rc));
     95        return -1;
     96    }
     97
     98    for (e = res; e != NULL; e = e->ai_next) {
     99        (*naddrs)++;
    100    }
    101
    102    *addrs = g_new0(SocketAddress *, *naddrs);
    103
    104    /* create socket + bind */
    105    for (i = 0, e = res; e != NULL; i++, e = e->ai_next) {
    106        SocketAddress *newaddr = g_new0(SocketAddress, 1);
    107
    108        newaddr->type = SOCKET_ADDRESS_TYPE_INET;
    109
    110        getnameinfo((struct sockaddr *)e->ai_addr, e->ai_addrlen,
    111                    uaddr, INET6_ADDRSTRLEN, uport, 32,
    112                    NI_NUMERICHOST | NI_NUMERICSERV);
    113
    114        newaddr->u.inet = (InetSocketAddress){
    115            .host = g_strdup(uaddr),
    116            .port = g_strdup(uport),
    117            .has_numeric = true,
    118            .numeric = true,
    119            .has_to = iaddr->has_to,
    120            .to = iaddr->to,
    121            .has_ipv4 = iaddr->has_ipv4,
    122            .ipv4 = iaddr->ipv4,
    123            .has_ipv6 = iaddr->has_ipv6,
    124            .ipv6 = iaddr->ipv6,
    125#ifdef HAVE_IPPROTO_MPTCP
    126            .has_mptcp = iaddr->has_mptcp,
    127            .mptcp = iaddr->mptcp,
    128#endif
    129        };
    130
    131        (*addrs)[i] = newaddr;
    132    }
    133    freeaddrinfo(res);
    134    return 0;
    135}
    136
    137
    138static int qio_dns_resolver_lookup_sync_nop(QIODNSResolver *resolver,
    139                                            SocketAddress *addr,
    140                                            size_t *naddrs,
    141                                            SocketAddress ***addrs,
    142                                            Error **errp)
    143{
    144    *naddrs = 1;
    145    *addrs = g_new0(SocketAddress *, 1);
    146    (*addrs)[0] = QAPI_CLONE(SocketAddress, addr);
    147
    148    return 0;
    149}
    150
    151
    152int qio_dns_resolver_lookup_sync(QIODNSResolver *resolver,
    153                                 SocketAddress *addr,
    154                                 size_t *naddrs,
    155                                 SocketAddress ***addrs,
    156                                 Error **errp)
    157{
    158    switch (addr->type) {
    159    case SOCKET_ADDRESS_TYPE_INET:
    160        return qio_dns_resolver_lookup_sync_inet(resolver,
    161                                                 addr,
    162                                                 naddrs,
    163                                                 addrs,
    164                                                 errp);
    165
    166    case SOCKET_ADDRESS_TYPE_UNIX:
    167    case SOCKET_ADDRESS_TYPE_VSOCK:
    168    case SOCKET_ADDRESS_TYPE_FD:
    169        return qio_dns_resolver_lookup_sync_nop(resolver,
    170                                                addr,
    171                                                naddrs,
    172                                                addrs,
    173                                                errp);
    174
    175    default:
    176        abort();
    177    }
    178}
    179
    180
    181struct QIODNSResolverLookupData {
    182    SocketAddress *addr;
    183    SocketAddress **addrs;
    184    size_t naddrs;
    185};
    186
    187
    188static void qio_dns_resolver_lookup_data_free(gpointer opaque)
    189{
    190    struct QIODNSResolverLookupData *data = opaque;
    191    size_t i;
    192
    193    qapi_free_SocketAddress(data->addr);
    194    for (i = 0; i < data->naddrs; i++) {
    195        qapi_free_SocketAddress(data->addrs[i]);
    196    }
    197
    198    g_free(data->addrs);
    199    g_free(data);
    200}
    201
    202
    203static void qio_dns_resolver_lookup_worker(QIOTask *task,
    204                                           gpointer opaque)
    205{
    206    QIODNSResolver *resolver = QIO_DNS_RESOLVER(qio_task_get_source(task));
    207    struct QIODNSResolverLookupData *data = opaque;
    208    Error *err = NULL;
    209
    210    qio_dns_resolver_lookup_sync(resolver,
    211                                 data->addr,
    212                                 &data->naddrs,
    213                                 &data->addrs,
    214                                 &err);
    215    if (err) {
    216        qio_task_set_error(task, err);
    217    } else {
    218        qio_task_set_result_pointer(task, opaque, NULL);
    219    }
    220
    221    object_unref(OBJECT(resolver));
    222}
    223
    224
    225void qio_dns_resolver_lookup_async(QIODNSResolver *resolver,
    226                                   SocketAddress *addr,
    227                                   QIOTaskFunc func,
    228                                   gpointer opaque,
    229                                   GDestroyNotify notify)
    230{
    231    QIOTask *task;
    232    struct QIODNSResolverLookupData *data =
    233        g_new0(struct QIODNSResolverLookupData, 1);
    234
    235    data->addr = QAPI_CLONE(SocketAddress, addr);
    236
    237    task = qio_task_new(OBJECT(resolver), func, opaque, notify);
    238
    239    qio_task_run_in_thread(task,
    240                           qio_dns_resolver_lookup_worker,
    241                           data,
    242                           qio_dns_resolver_lookup_data_free,
    243                           NULL);
    244}
    245
    246
    247void qio_dns_resolver_lookup_result(QIODNSResolver *resolver,
    248                                    QIOTask *task,
    249                                    size_t *naddrs,
    250                                    SocketAddress ***addrs)
    251{
    252    struct QIODNSResolverLookupData *data =
    253        qio_task_get_result_pointer(task);
    254    size_t i;
    255
    256    *naddrs = 0;
    257    *addrs = NULL;
    258    if (!data) {
    259        return;
    260    }
    261
    262    *naddrs = data->naddrs;
    263    *addrs = g_new0(SocketAddress *, data->naddrs);
    264    for (i = 0; i < data->naddrs; i++) {
    265        (*addrs)[i] = QAPI_CLONE(SocketAddress, data->addrs[i]);
    266    }
    267}
    268
    269
    270static const TypeInfo qio_dns_resolver_info = {
    271    .parent = TYPE_OBJECT,
    272    .name = TYPE_QIO_DNS_RESOLVER,
    273    .instance_size = sizeof(QIODNSResolver),
    274};
    275
    276
    277static void qio_dns_resolver_register_types(void)
    278{
    279    type_register_static(&qio_dns_resolver_info);
    280}
    281
    282
    283type_init(qio_dns_resolver_register_types);