qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

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 
     34 static QIODNSResolver *instance;
     35 static GOnce instance_init = G_ONCE_INIT;
     36 
     37 static 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 
     43 QIODNSResolver *qio_dns_resolver_get_instance(void)
     44 {
     45     g_once(&instance_init, qio_dns_resolve_init_instance, NULL);
     46     return instance;
     47 }
     48 
     49 static 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 
    138 static 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 
    152 int 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 
    181 struct QIODNSResolverLookupData {
    182     SocketAddress *addr;
    183     SocketAddress **addrs;
    184     size_t naddrs;
    185 };
    186 
    187 
    188 static 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 
    203 static 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 
    225 void 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 
    247 void 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 
    270 static const TypeInfo qio_dns_resolver_info = {
    271     .parent = TYPE_OBJECT,
    272     .name = TYPE_QIO_DNS_RESOLVER,
    273     .instance_size = sizeof(QIODNSResolver),
    274 };
    275 
    276 
    277 static void qio_dns_resolver_register_types(void)
    278 {
    279     type_register_static(&qio_dns_resolver_info);
    280 }
    281 
    282 
    283 type_init(qio_dns_resolver_register_types);