4 * Copyright (c) 2016 Red Hat, Inc.
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.
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.
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/>.
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"
30 #ifndef AI_NUMERICSERV
31 # define AI_NUMERICSERV 0
34 static QIODNSResolver
*instance
;
35 static GOnce instance_init
= G_ONCE_INIT
;
37 static gpointer
qio_dns_resolve_init_instance(gpointer unused G_GNUC_UNUSED
)
39 instance
= QIO_DNS_RESOLVER(object_new(TYPE_QIO_DNS_RESOLVER
));
43 QIODNSResolver
*qio_dns_resolver_get_instance(void)
45 g_once(&instance_init
, qio_dns_resolve_init_instance
, NULL
);
49 static int qio_dns_resolver_lookup_sync_inet(QIODNSResolver
*resolver
,
52 SocketAddress
***addrs
,
55 struct addrinfo ai
, *res
, *e
;
56 InetSocketAddress
*iaddr
= &addr
->u
.inet
;
58 char uaddr
[INET6_ADDRSTRLEN
+ 1];
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
;
72 ai
.ai_family
= inet_ai_family_from_address(iaddr
, &err
);
73 ai
.ai_socktype
= SOCK_STREAM
;
76 error_propagate(errp
, err
);
80 if (iaddr
->host
== NULL
) {
81 error_setg(errp
, "host not specified");
84 if (iaddr
->port
!= NULL
) {
85 pstrcpy(port
, sizeof(port
), iaddr
->port
);
90 rc
= getaddrinfo(strlen(iaddr
->host
) ? iaddr
->host
: NULL
,
91 strlen(port
) ? port
: NULL
, &ai
, &res
);
93 error_setg(errp
, "address resolution failed for %s:%s: %s",
94 iaddr
->host
, port
, gai_strerror(rc
));
98 for (e
= res
; e
!= NULL
; e
= e
->ai_next
) {
102 *addrs
= g_new0(SocketAddress
*, *naddrs
);
104 /* create socket + bind */
105 for (i
= 0, e
= res
; e
!= NULL
; i
++, e
= e
->ai_next
) {
106 SocketAddress
*newaddr
= g_new0(SocketAddress
, 1);
108 newaddr
->type
= SOCKET_ADDRESS_TYPE_INET
;
110 getnameinfo((struct sockaddr
*)e
->ai_addr
, e
->ai_addrlen
,
111 uaddr
, INET6_ADDRSTRLEN
, uport
, 32,
112 NI_NUMERICHOST
| NI_NUMERICSERV
);
114 newaddr
->u
.inet
= (InetSocketAddress
){
115 .host
= g_strdup(uaddr
),
116 .port
= g_strdup(uport
),
119 .has_to
= iaddr
->has_to
,
121 .has_ipv4
= iaddr
->has_ipv4
,
123 .has_ipv6
= iaddr
->has_ipv6
,
125 #ifdef HAVE_IPPROTO_MPTCP
126 .has_mptcp
= iaddr
->has_mptcp
,
127 .mptcp
= iaddr
->mptcp
,
131 (*addrs
)[i
] = newaddr
;
138 static int qio_dns_resolver_lookup_sync_nop(QIODNSResolver
*resolver
,
141 SocketAddress
***addrs
,
145 *addrs
= g_new0(SocketAddress
*, 1);
146 (*addrs
)[0] = QAPI_CLONE(SocketAddress
, addr
);
152 int qio_dns_resolver_lookup_sync(QIODNSResolver
*resolver
,
155 SocketAddress
***addrs
,
158 switch (addr
->type
) {
159 case SOCKET_ADDRESS_TYPE_INET
:
160 return qio_dns_resolver_lookup_sync_inet(resolver
,
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
,
181 struct QIODNSResolverLookupData
{
183 SocketAddress
**addrs
;
188 static void qio_dns_resolver_lookup_data_free(gpointer opaque
)
190 struct QIODNSResolverLookupData
*data
= opaque
;
193 qapi_free_SocketAddress(data
->addr
);
194 for (i
= 0; i
< data
->naddrs
; i
++) {
195 qapi_free_SocketAddress(data
->addrs
[i
]);
203 static void qio_dns_resolver_lookup_worker(QIOTask
*task
,
206 QIODNSResolver
*resolver
= QIO_DNS_RESOLVER(qio_task_get_source(task
));
207 struct QIODNSResolverLookupData
*data
= opaque
;
210 qio_dns_resolver_lookup_sync(resolver
,
216 qio_task_set_error(task
, err
);
218 qio_task_set_result_pointer(task
, opaque
, NULL
);
221 object_unref(OBJECT(resolver
));
225 void qio_dns_resolver_lookup_async(QIODNSResolver
*resolver
,
229 GDestroyNotify notify
)
232 struct QIODNSResolverLookupData
*data
=
233 g_new0(struct QIODNSResolverLookupData
, 1);
235 data
->addr
= QAPI_CLONE(SocketAddress
, addr
);
237 task
= qio_task_new(OBJECT(resolver
), func
, opaque
, notify
);
239 qio_task_run_in_thread(task
,
240 qio_dns_resolver_lookup_worker
,
242 qio_dns_resolver_lookup_data_free
,
247 void qio_dns_resolver_lookup_result(QIODNSResolver
*resolver
,
250 SocketAddress
***addrs
)
252 struct QIODNSResolverLookupData
*data
=
253 qio_task_get_result_pointer(task
);
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
]);
270 static const TypeInfo qio_dns_resolver_info
= {
271 .parent
= TYPE_OBJECT
,
272 .name
= TYPE_QIO_DNS_RESOLVER
,
273 .instance_size
= sizeof(QIODNSResolver
),
277 static void qio_dns_resolver_register_types(void)
279 type_register_static(&qio_dns_resolver_info
);
283 type_init(qio_dns_resolver_register_types
);