Coverage Report

Created: 2025-07-01 07:09

/src/glib/gio/gthreadedresolver.c
Line
Count
Source (jump to first uncovered line)
1
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3
/* GIO - GLib Input, Output and Streaming Library
4
 *
5
 * Copyright (C) 2008 Red Hat, Inc.
6
 * Copyright (C) 2018 Igalia S.L.
7
 *
8
 * This library is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU Lesser General Public
10
 * License as published by the Free Software Foundation; either
11
 * version 2.1 of the License, or (at your option) any later version.
12
 *
13
 * This library is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
 * Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General
19
 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
20
 */
21
22
#include "config.h"
23
#include <glib.h>
24
#include "glibintl.h"
25
26
#include <stdio.h>
27
#include <string.h>
28
29
#include "gthreadedresolver.h"
30
#include "gnetworkingprivate.h"
31
32
#include "gcancellable.h"
33
#include "ginetaddress.h"
34
#include "ginetsocketaddress.h"
35
#include "gtask.h"
36
#include "gsocketaddress.h"
37
#include "gsrvtarget.h"
38
39
40
G_DEFINE_TYPE (GThreadedResolver, g_threaded_resolver, G_TYPE_RESOLVER)
41
42
static void
43
g_threaded_resolver_init (GThreadedResolver *gtr)
44
0
{
45
0
}
46
47
static GResolverError
48
g_resolver_error_from_addrinfo_error (gint err)
49
0
{
50
0
  switch (err)
51
0
    {
52
0
    case EAI_FAIL:
53
0
#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
54
0
    case EAI_NODATA:
55
0
#endif
56
0
    case EAI_NONAME:
57
0
      return G_RESOLVER_ERROR_NOT_FOUND;
58
59
0
    case EAI_AGAIN:
60
0
      return G_RESOLVER_ERROR_TEMPORARY_FAILURE;
61
62
0
    default:
63
0
      return G_RESOLVER_ERROR_INTERNAL;
64
0
    }
65
0
}
66
67
typedef struct {
68
  char *hostname;
69
  int address_family;
70
} LookupData;
71
72
static LookupData *
73
lookup_data_new (const char *hostname,
74
                 int         address_family)
75
0
{
76
0
  LookupData *data = g_new (LookupData, 1);
77
0
  data->hostname = g_strdup (hostname);
78
0
  data->address_family = address_family;
79
0
  return data;
80
0
}
81
82
static void
83
lookup_data_free (LookupData *data)
84
0
{
85
0
  g_free (data->hostname);
86
0
  g_free (data);
87
0
}
88
89
static void
90
do_lookup_by_name (GTask         *task,
91
                   gpointer       source_object,
92
                   gpointer       task_data,
93
                   GCancellable  *cancellable)
94
0
{
95
0
  LookupData *lookup_data = task_data;
96
0
  const char *hostname = lookup_data->hostname;
97
0
  struct addrinfo *res = NULL;
98
0
  GList *addresses;
99
0
  gint retval;
100
0
  struct addrinfo addrinfo_hints = { 0 };
101
102
0
#ifdef AI_ADDRCONFIG
103
0
  addrinfo_hints.ai_flags = AI_ADDRCONFIG;
104
0
#endif
105
  /* socktype and protocol don't actually matter, they just get copied into the
106
  * returned addrinfo structures (and then we ignore them). But if
107
  * we leave them unset, we'll get back duplicate answers.
108
  */
109
0
  addrinfo_hints.ai_socktype = SOCK_STREAM;
110
0
  addrinfo_hints.ai_protocol = IPPROTO_TCP;
111
112
0
  addrinfo_hints.ai_family = lookup_data->address_family;
113
0
  retval = getaddrinfo (hostname, NULL, &addrinfo_hints, &res);
114
115
0
  if (retval == 0)
116
0
    {
117
0
      struct addrinfo *ai;
118
0
      GSocketAddress *sockaddr;
119
0
      GInetAddress *addr;
120
121
0
      addresses = NULL;
122
0
      for (ai = res; ai; ai = ai->ai_next)
123
0
        {
124
0
          sockaddr = g_socket_address_new_from_native (ai->ai_addr, ai->ai_addrlen);
125
0
          if (!sockaddr)
126
0
            continue;
127
0
          if (!G_IS_INET_SOCKET_ADDRESS (sockaddr))
128
0
            {
129
0
              g_clear_object (&sockaddr);
130
0
              continue;
131
0
            }
132
133
0
          addr = g_object_ref (g_inet_socket_address_get_address ((GInetSocketAddress *)sockaddr));
134
0
          addresses = g_list_prepend (addresses, addr);
135
0
          g_object_unref (sockaddr);
136
0
        }
137
138
0
      if (addresses != NULL)
139
0
        {
140
0
          addresses = g_list_reverse (addresses);
141
0
          g_task_return_pointer (task, addresses,
142
0
                                 (GDestroyNotify)g_resolver_free_addresses);
143
0
        }
144
0
      else
145
0
        {
146
          /* All addresses failed to be converted to GSocketAddresses. */
147
0
          g_task_return_new_error (task,
148
0
                                   G_RESOLVER_ERROR,
149
0
                                   G_RESOLVER_ERROR_NOT_FOUND,
150
0
                                   _("Error resolving “%s”: %s"),
151
0
                                   hostname,
152
0
                                   _("No valid addresses were found"));
153
0
        }
154
0
    }
155
0
  else
156
0
    {
157
#ifdef G_OS_WIN32
158
      gchar *error_message = g_win32_error_message (WSAGetLastError ());
159
#else
160
0
      gchar *error_message = g_locale_to_utf8 (gai_strerror (retval), -1, NULL, NULL, NULL);
161
0
      if (error_message == NULL)
162
0
        error_message = g_strdup ("[Invalid UTF-8]");
163
0
#endif
164
165
0
      g_task_return_new_error (task,
166
0
                               G_RESOLVER_ERROR,
167
0
                               g_resolver_error_from_addrinfo_error (retval),
168
0
                               _("Error resolving “%s”: %s"),
169
0
                               hostname, error_message);
170
0
      g_free (error_message);
171
0
    }
172
173
0
  if (res)
174
0
    freeaddrinfo (res);
175
0
}
176
177
static GList *
178
lookup_by_name (GResolver     *resolver,
179
                const gchar   *hostname,
180
                GCancellable  *cancellable,
181
                GError       **error)
182
0
{
183
0
  GTask *task;
184
0
  GList *addresses;
185
0
  LookupData *data;
186
187
0
  data = lookup_data_new (hostname, AF_UNSPEC);
188
0
  task = g_task_new (resolver, cancellable, NULL, NULL);
189
0
  g_task_set_source_tag (task, lookup_by_name);
190
0
  g_task_set_name (task, "[gio] resolver lookup");
191
0
  g_task_set_task_data (task, data, (GDestroyNotify)lookup_data_free);
192
0
  g_task_set_return_on_cancel (task, TRUE);
193
0
  g_task_run_in_thread_sync (task, do_lookup_by_name);
194
0
  addresses = g_task_propagate_pointer (task, error);
195
0
  g_object_unref (task);
196
197
0
  return addresses;
198
0
}
199
200
static int
201
flags_to_family (GResolverNameLookupFlags flags)
202
0
{
203
0
  int address_family = AF_UNSPEC;
204
205
0
  if (flags & G_RESOLVER_NAME_LOOKUP_FLAGS_IPV4_ONLY)
206
0
    address_family = AF_INET;
207
208
0
  if (flags & G_RESOLVER_NAME_LOOKUP_FLAGS_IPV6_ONLY)
209
0
    {
210
0
      address_family = AF_INET6;
211
      /* You can only filter by one family at a time */
212
0
      g_return_val_if_fail (!(flags & G_RESOLVER_NAME_LOOKUP_FLAGS_IPV4_ONLY), address_family);
213
0
    }
214
215
0
  return address_family;
216
0
}
217
218
static GList *
219
lookup_by_name_with_flags (GResolver                 *resolver,
220
                           const gchar               *hostname,
221
                           GResolverNameLookupFlags   flags,
222
                           GCancellable              *cancellable,
223
                           GError                   **error)
224
0
{
225
0
  GTask *task;
226
0
  GList *addresses;
227
0
  LookupData *data;
228
229
0
  data = lookup_data_new (hostname, flags_to_family (flags));
230
0
  task = g_task_new (resolver, cancellable, NULL, NULL);
231
0
  g_task_set_source_tag (task, lookup_by_name_with_flags);
232
0
  g_task_set_name (task, "[gio] resolver lookup");
233
0
  g_task_set_task_data (task, data, (GDestroyNotify)lookup_data_free);
234
0
  g_task_set_return_on_cancel (task, TRUE);
235
0
  g_task_run_in_thread_sync (task, do_lookup_by_name);
236
0
  addresses = g_task_propagate_pointer (task, error);
237
0
  g_object_unref (task);
238
239
0
  return addresses;
240
0
}
241
242
static void
243
lookup_by_name_with_flags_async (GResolver                *resolver,
244
                                 const gchar              *hostname,
245
                                 GResolverNameLookupFlags  flags,
246
                                 GCancellable             *cancellable,
247
                                 GAsyncReadyCallback       callback,
248
                                 gpointer                  user_data)
249
0
{
250
0
  GTask *task;
251
0
  LookupData *data;
252
253
0
  data = lookup_data_new (hostname, flags_to_family (flags));
254
0
  task = g_task_new (resolver, cancellable, callback, user_data);
255
0
  g_task_set_source_tag (task, lookup_by_name_with_flags_async);
256
0
  g_task_set_name (task, "[gio] resolver lookup");
257
0
  g_task_set_task_data (task, data, (GDestroyNotify)lookup_data_free);
258
0
  g_task_set_return_on_cancel (task, TRUE);
259
0
  g_task_run_in_thread (task, do_lookup_by_name);
260
0
  g_object_unref (task);
261
0
}
262
263
static void
264
lookup_by_name_async (GResolver           *resolver,
265
                      const gchar         *hostname,
266
                      GCancellable        *cancellable,
267
                      GAsyncReadyCallback  callback,
268
                      gpointer             user_data)
269
0
{
270
0
  lookup_by_name_with_flags_async (resolver,
271
0
                                   hostname,
272
0
                                   G_RESOLVER_NAME_LOOKUP_FLAGS_DEFAULT,
273
0
                                   cancellable,
274
0
                                   callback,
275
0
                                   user_data);
276
0
}
277
278
static GList *
279
lookup_by_name_finish (GResolver     *resolver,
280
                       GAsyncResult  *result,
281
                       GError       **error)
282
0
{
283
0
  g_return_val_if_fail (g_task_is_valid (result, resolver), NULL);
284
285
0
  return g_task_propagate_pointer (G_TASK (result), error);
286
0
}
287
288
static GList *
289
lookup_by_name_with_flags_finish (GResolver     *resolver,
290
                                  GAsyncResult  *result,
291
                                  GError       **error)
292
0
{
293
0
  g_return_val_if_fail (g_task_is_valid (result, resolver), NULL);
294
295
0
  return g_task_propagate_pointer (G_TASK (result), error);
296
0
}
297
298
static void
299
do_lookup_by_address (GTask         *task,
300
                      gpointer       source_object,
301
                      gpointer       task_data,
302
                      GCancellable  *cancellable)
303
0
{
304
0
  GInetAddress *address = task_data;
305
0
  struct sockaddr_storage sockaddr;
306
0
  gsize sockaddr_size;
307
0
  GSocketAddress *gsockaddr;
308
0
  gchar name[NI_MAXHOST];
309
0
  gint retval;
310
311
0
  gsockaddr = g_inet_socket_address_new (address, 0);
312
0
  g_socket_address_to_native (gsockaddr, (struct sockaddr *)&sockaddr,
313
0
                              sizeof (sockaddr), NULL);
314
0
  sockaddr_size = g_socket_address_get_native_size (gsockaddr);
315
0
  g_object_unref (gsockaddr);
316
317
0
  retval = getnameinfo ((struct sockaddr *)&sockaddr, sockaddr_size,
318
0
                        name, sizeof (name), NULL, 0, NI_NAMEREQD);
319
0
  if (retval == 0)
320
0
    g_task_return_pointer (task, g_strdup (name), g_free);
321
0
  else
322
0
    {
323
0
      gchar *phys;
324
325
#ifdef G_OS_WIN32
326
      gchar *error_message = g_win32_error_message (WSAGetLastError ());
327
#else
328
0
      gchar *error_message = g_locale_to_utf8 (gai_strerror (retval), -1, NULL, NULL, NULL);
329
0
      if (error_message == NULL)
330
0
        error_message = g_strdup ("[Invalid UTF-8]");
331
0
#endif
332
333
0
      phys = g_inet_address_to_string (address);
334
0
      g_task_return_new_error (task,
335
0
                               G_RESOLVER_ERROR,
336
0
                               g_resolver_error_from_addrinfo_error (retval),
337
0
                               _("Error reverse-resolving “%s”: %s"),
338
0
                               phys ? phys : "(unknown)",
339
0
                               error_message);
340
0
      g_free (phys);
341
0
      g_free (error_message);
342
0
    }
343
0
}
344
345
static gchar *
346
lookup_by_address (GResolver        *resolver,
347
                   GInetAddress     *address,
348
                   GCancellable     *cancellable,
349
                   GError          **error)
350
0
{
351
0
  GTask *task;
352
0
  gchar *name;
353
354
0
  task = g_task_new (resolver, cancellable, NULL, NULL);
355
0
  g_task_set_source_tag (task, lookup_by_address);
356
0
  g_task_set_name (task, "[gio] resolver lookup");
357
0
  g_task_set_task_data (task, g_object_ref (address), g_object_unref);
358
0
  g_task_set_return_on_cancel (task, TRUE);
359
0
  g_task_run_in_thread_sync (task, do_lookup_by_address);
360
0
  name = g_task_propagate_pointer (task, error);
361
0
  g_object_unref (task);
362
363
0
  return name;
364
0
}
365
366
static void
367
lookup_by_address_async (GResolver           *resolver,
368
                         GInetAddress        *address,
369
                         GCancellable        *cancellable,
370
                         GAsyncReadyCallback  callback,
371
                         gpointer             user_data)
372
0
{
373
0
  GTask *task;
374
375
0
  task = g_task_new (resolver, cancellable, callback, user_data);
376
0
  g_task_set_source_tag (task, lookup_by_address_async);
377
0
  g_task_set_name (task, "[gio] resolver lookup");
378
0
  g_task_set_task_data (task, g_object_ref (address), g_object_unref);
379
0
  g_task_set_return_on_cancel (task, TRUE);
380
0
  g_task_run_in_thread (task, do_lookup_by_address);
381
0
  g_object_unref (task);
382
0
}
383
384
static gchar *
385
lookup_by_address_finish (GResolver     *resolver,
386
                          GAsyncResult  *result,
387
                          GError       **error)
388
0
{
389
0
  g_return_val_if_fail (g_task_is_valid (result, resolver), NULL);
390
391
0
  return g_task_propagate_pointer (G_TASK (result), error);
392
0
}
393
394
395
#if defined(G_OS_UNIX)
396
397
#if defined __BIONIC__ && !defined BIND_4_COMPAT
398
/* Copy from bionic/libc/private/arpa_nameser_compat.h
399
 * and bionic/libc/private/arpa_nameser.h */
400
typedef struct {
401
  unsigned  id :16;   /* query identification number */
402
#if BYTE_ORDER == BIG_ENDIAN
403
      /* fields in third byte */
404
  unsigned  qr: 1;    /* response flag */
405
  unsigned  opcode: 4;  /* purpose of message */
406
  unsigned  aa: 1;    /* authoritative answer */
407
  unsigned  tc: 1;    /* truncated message */
408
  unsigned  rd: 1;    /* recursion desired */
409
      /* fields in fourth byte */
410
  unsigned  ra: 1;    /* recursion available */
411
  unsigned  unused :1;  /* unused bits (MBZ as of 4.9.3a3) */
412
  unsigned  ad: 1;    /* authentic data from named */
413
  unsigned  cd: 1;    /* checking disabled by resolver */
414
  unsigned  rcode :4; /* response code */
415
#endif
416
#if BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN
417
      /* fields in third byte */
418
  unsigned  rd :1;    /* recursion desired */
419
  unsigned  tc :1;    /* truncated message */
420
  unsigned  aa :1;    /* authoritative answer */
421
  unsigned  opcode :4;  /* purpose of message */
422
  unsigned  qr :1;    /* response flag */
423
      /* fields in fourth byte */
424
  unsigned  rcode :4; /* response code */
425
  unsigned  cd: 1;    /* checking disabled by resolver */
426
  unsigned  ad: 1;    /* authentic data from named */
427
  unsigned  unused :1;  /* unused bits (MBZ as of 4.9.3a3) */
428
  unsigned  ra :1;    /* recursion available */
429
#endif
430
      /* remaining bytes */
431
  unsigned  qdcount :16;  /* number of question entries */
432
  unsigned  ancount :16;  /* number of answer entries */
433
  unsigned  nscount :16;  /* number of authority entries */
434
  unsigned  arcount :16;  /* number of resource entries */
435
} HEADER;
436
437
#define NS_INT32SZ  4 /* #/bytes of data in a uint32_t */
438
#define NS_INT16SZ  2 /* #/bytes of data in a uint16_t */
439
440
#define NS_GET16(s, cp) do { \
441
  const u_char *t_cp = (const u_char *)(cp); \
442
  (s) = ((uint16_t)t_cp[0] << 8) \
443
      | ((uint16_t)t_cp[1]) \
444
      ; \
445
  (cp) += NS_INT16SZ; \
446
} while (/*CONSTCOND*/0)
447
448
#define NS_GET32(l, cp) do { \
449
  const u_char *t_cp = (const u_char *)(cp); \
450
  (l) = ((uint32_t)t_cp[0] << 24) \
451
      | ((uint32_t)t_cp[1] << 16) \
452
      | ((uint32_t)t_cp[2] << 8) \
453
      | ((uint32_t)t_cp[3]) \
454
      ; \
455
  (cp) += NS_INT32SZ; \
456
} while (/*CONSTCOND*/0)
457
458
#define GETSHORT    NS_GET16
459
#define GETLONG     NS_GET32
460
461
#define C_IN 1
462
463
/* From bionic/libc/private/resolv_private.h */
464
int dn_expand(const u_char *, const u_char *, const u_char *, char *, int);
465
#define dn_skipname __dn_skipname
466
int dn_skipname(const u_char *, const u_char *);
467
468
/* From bionic/libc/private/arpa_nameser_compat.h */
469
#define T_MX    ns_t_mx
470
#define T_TXT   ns_t_txt
471
#define T_SOA   ns_t_soa
472
#define T_NS    ns_t_ns
473
474
/* From bionic/libc/private/arpa_nameser.h */
475
typedef enum __ns_type {
476
  ns_t_invalid = 0, /* Cookie. */
477
  ns_t_a = 1,   /* Host address. */
478
  ns_t_ns = 2,    /* Authoritative server. */
479
  ns_t_md = 3,    /* Mail destination. */
480
  ns_t_mf = 4,    /* Mail forwarder. */
481
  ns_t_cname = 5,   /* Canonical name. */
482
  ns_t_soa = 6,   /* Start of authority zone. */
483
  ns_t_mb = 7,    /* Mailbox domain name. */
484
  ns_t_mg = 8,    /* Mail group member. */
485
  ns_t_mr = 9,    /* Mail rename name. */
486
  ns_t_null = 10,   /* Null resource record. */
487
  ns_t_wks = 11,    /* Well known service. */
488
  ns_t_ptr = 12,    /* Domain name pointer. */
489
  ns_t_hinfo = 13,  /* Host information. */
490
  ns_t_minfo = 14,  /* Mailbox information. */
491
  ns_t_mx = 15,   /* Mail routing information. */
492
  ns_t_txt = 16,    /* Text strings. */
493
  ns_t_rp = 17,   /* Responsible person. */
494
  ns_t_afsdb = 18,  /* AFS cell database. */
495
  ns_t_x25 = 19,    /* X_25 calling address. */
496
  ns_t_isdn = 20,   /* ISDN calling address. */
497
  ns_t_rt = 21,   /* Router. */
498
  ns_t_nsap = 22,   /* NSAP address. */
499
  ns_t_nsap_ptr = 23, /* Reverse NSAP lookup (deprecated). */
500
  ns_t_sig = 24,    /* Security signature. */
501
  ns_t_key = 25,    /* Security key. */
502
  ns_t_px = 26,   /* X.400 mail mapping. */
503
  ns_t_gpos = 27,   /* Geographical position (withdrawn). */
504
  ns_t_aaaa = 28,   /* Ip6 Address. */
505
  ns_t_loc = 29,    /* Location Information. */
506
  ns_t_nxt = 30,    /* Next domain (security). */
507
  ns_t_eid = 31,    /* Endpoint identifier. */
508
  ns_t_nimloc = 32, /* Nimrod Locator. */
509
  ns_t_srv = 33,    /* Server Selection. */
510
  ns_t_atma = 34,   /* ATM Address */
511
  ns_t_naptr = 35,  /* Naming Authority PoinTeR */
512
  ns_t_kx = 36,   /* Key Exchange */
513
  ns_t_cert = 37,   /* Certification record */
514
  ns_t_a6 = 38,   /* IPv6 address (deprecates AAAA) */
515
  ns_t_dname = 39,  /* Non-terminal DNAME (for IPv6) */
516
  ns_t_sink = 40,   /* Kitchen sink (experimental) */
517
  ns_t_opt = 41,    /* EDNS0 option (meta-RR) */
518
  ns_t_apl = 42,    /* Address prefix list (RFC 3123) */
519
  ns_t_tkey = 249,  /* Transaction key */
520
  ns_t_tsig = 250,  /* Transaction signature. */
521
  ns_t_ixfr = 251,  /* Incremental zone transfer. */
522
  ns_t_axfr = 252,  /* Transfer zone of authority. */
523
  ns_t_mailb = 253, /* Transfer mailbox records. */
524
  ns_t_maila = 254, /* Transfer mail agent records. */
525
  ns_t_any = 255,   /* Wildcard match. */
526
  ns_t_zxfr = 256,  /* BIND-specific, nonstandard. */
527
  ns_t_max = 65536
528
} ns_type;
529
530
#endif /* __BIONIC__ */
531
532
static GVariant *
533
parse_res_srv (guchar  *answer,
534
               guchar  *end,
535
               guchar **p)
536
0
{
537
0
  gchar namebuf[1024];
538
0
  guint16 priority, weight, port;
539
540
0
  GETSHORT (priority, *p);
541
0
  GETSHORT (weight, *p);
542
0
  GETSHORT (port, *p);
543
0
  *p += dn_expand (answer, end, *p, namebuf, sizeof (namebuf));
544
545
0
  return g_variant_new ("(qqqs)",
546
0
                        priority,
547
0
                        weight,
548
0
                        port,
549
0
                        namebuf);
550
0
}
551
552
static GVariant *
553
parse_res_soa (guchar  *answer,
554
               guchar  *end,
555
               guchar **p)
556
0
{
557
0
  gchar mnamebuf[1024];
558
0
  gchar rnamebuf[1024];
559
0
  guint32 serial, refresh, retry, expire, ttl;
560
561
0
  *p += dn_expand (answer, end, *p, mnamebuf, sizeof (mnamebuf));
562
0
  *p += dn_expand (answer, end, *p, rnamebuf, sizeof (rnamebuf));
563
564
0
  GETLONG (serial, *p);
565
0
  GETLONG (refresh, *p);
566
0
  GETLONG (retry, *p);
567
0
  GETLONG (expire, *p);
568
0
  GETLONG (ttl, *p);
569
570
0
  return g_variant_new ("(ssuuuuu)",
571
0
                        mnamebuf,
572
0
                        rnamebuf,
573
0
                        serial,
574
0
                        refresh,
575
0
                        retry,
576
0
                        expire,
577
0
                        ttl);
578
0
}
579
580
static GVariant *
581
parse_res_ns (guchar  *answer,
582
              guchar  *end,
583
              guchar **p)
584
0
{
585
0
  gchar namebuf[1024];
586
587
0
  *p += dn_expand (answer, end, *p, namebuf, sizeof (namebuf));
588
589
0
  return g_variant_new ("(s)", namebuf);
590
0
}
591
592
static GVariant *
593
parse_res_mx (guchar  *answer,
594
              guchar  *end,
595
              guchar **p)
596
0
{
597
0
  gchar namebuf[1024];
598
0
  guint16 preference;
599
600
0
  GETSHORT (preference, *p);
601
602
0
  *p += dn_expand (answer, end, *p, namebuf, sizeof (namebuf));
603
604
0
  return g_variant_new ("(qs)",
605
0
                        preference,
606
0
                        namebuf);
607
0
}
608
609
static GVariant *
610
parse_res_txt (guchar  *answer,
611
               guchar  *end,
612
               guchar **p)
613
0
{
614
0
  GVariant *record;
615
0
  GPtrArray *array;
616
0
  guchar *at = *p;
617
0
  gsize len;
618
619
0
  array = g_ptr_array_new_with_free_func (g_free);
620
0
  while (at < end)
621
0
    {
622
0
      len = *(at++);
623
0
      if (len > (gsize) (end - at))
624
0
        break;
625
0
      g_ptr_array_add (array, g_strndup ((gchar *)at, len));
626
0
      at += len;
627
0
    }
628
629
0
  *p = at;
630
0
  record = g_variant_new ("(@as)",
631
0
                          g_variant_new_strv ((const gchar **)array->pdata, array->len));
632
0
  g_ptr_array_free (array, TRUE);
633
0
  return record;
634
0
}
635
636
static gint
637
g_resolver_record_type_to_rrtype (GResolverRecordType type)
638
0
{
639
0
  switch (type)
640
0
  {
641
0
    case G_RESOLVER_RECORD_SRV:
642
0
      return T_SRV;
643
0
    case G_RESOLVER_RECORD_TXT:
644
0
      return T_TXT;
645
0
    case G_RESOLVER_RECORD_SOA:
646
0
      return T_SOA;
647
0
    case G_RESOLVER_RECORD_NS:
648
0
      return T_NS;
649
0
    case G_RESOLVER_RECORD_MX:
650
0
      return T_MX;
651
0
  }
652
0
  g_return_val_if_reached (-1);
653
0
}
654
655
static GList *
656
g_resolver_records_from_res_query (const gchar      *rrname,
657
                                   gint              rrtype,
658
                                   guchar           *answer,
659
                                   gint              len,
660
                                   gint              herr,
661
                                   GError          **error)
662
0
{
663
0
  gint count;
664
0
  gchar namebuf[1024];
665
0
  guchar *end, *p;
666
0
  guint16 type, qclass, rdlength;
667
0
  HEADER *header;
668
0
  GList *records;
669
0
  GVariant *record;
670
671
0
  if (len <= 0)
672
0
    {
673
0
      if (len == 0 || herr == HOST_NOT_FOUND || herr == NO_DATA)
674
0
        {
675
0
          g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND,
676
0
                       _("No DNS record of the requested type for “%s”"), rrname);
677
0
        }
678
0
      else if (herr == TRY_AGAIN)
679
0
        {
680
0
          g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_TEMPORARY_FAILURE,
681
0
                       _("Temporarily unable to resolve “%s”"), rrname);
682
0
        }
683
0
      else
684
0
        {
685
0
          g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_INTERNAL,
686
0
                       _("Error resolving “%s”"), rrname);
687
0
        }
688
689
0
      return NULL;
690
0
    }
691
692
0
  records = NULL;
693
694
0
  header = (HEADER *)answer;
695
0
  p = answer + sizeof (HEADER);
696
0
  end = answer + len;
697
698
  /* Skip query */
699
0
  count = ntohs (header->qdcount);
700
0
  while (count-- && p < end)
701
0
    {
702
0
      p += dn_expand (answer, end, p, namebuf, sizeof (namebuf));
703
0
      p += 4;
704
705
      /* To silence gcc warnings */
706
0
      namebuf[0] = namebuf[1];
707
0
    }
708
709
  /* Read answers */
710
0
  count = ntohs (header->ancount);
711
0
  while (count-- && p < end)
712
0
    {
713
0
      p += dn_expand (answer, end, p, namebuf, sizeof (namebuf));
714
0
      GETSHORT (type, p);
715
0
      GETSHORT (qclass, p);
716
0
      p += 4; /* ignore the ttl (type=long) value */
717
0
      GETSHORT (rdlength, p);
718
719
0
      if (type != rrtype || qclass != C_IN)
720
0
        {
721
0
          p += rdlength;
722
0
          continue;
723
0
        }
724
725
0
      switch (rrtype)
726
0
        {
727
0
        case T_SRV:
728
0
          record = parse_res_srv (answer, end, &p);
729
0
          break;
730
0
        case T_MX:
731
0
          record = parse_res_mx (answer, end, &p);
732
0
          break;
733
0
        case T_SOA:
734
0
          record = parse_res_soa (answer, end, &p);
735
0
          break;
736
0
        case T_NS:
737
0
          record = parse_res_ns (answer, end, &p);
738
0
          break;
739
0
        case T_TXT:
740
0
          record = parse_res_txt (answer, p + rdlength, &p);
741
0
          break;
742
0
        default:
743
0
          g_warn_if_reached ();
744
0
          record = NULL;
745
0
          break;
746
0
        }
747
748
0
      if (record != NULL)
749
0
        records = g_list_prepend (records, record);
750
0
    }
751
752
0
  if (records == NULL)
753
0
    {
754
0
      g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND,
755
0
                   _("No DNS record of the requested type for “%s”"), rrname);
756
757
0
      return NULL;
758
0
    }
759
0
  else
760
0
    return records;
761
0
}
762
763
#elif defined(G_OS_WIN32)
764
765
static GVariant *
766
parse_dns_srv (DNS_RECORD *rec)
767
{
768
  return g_variant_new ("(qqqs)",
769
                        (guint16)rec->Data.SRV.wPriority,
770
                        (guint16)rec->Data.SRV.wWeight,
771
                        (guint16)rec->Data.SRV.wPort,
772
                        rec->Data.SRV.pNameTarget);
773
}
774
775
static GVariant *
776
parse_dns_soa (DNS_RECORD *rec)
777
{
778
  return g_variant_new ("(ssuuuuu)",
779
                        rec->Data.SOA.pNamePrimaryServer,
780
                        rec->Data.SOA.pNameAdministrator,
781
                        (guint32)rec->Data.SOA.dwSerialNo,
782
                        (guint32)rec->Data.SOA.dwRefresh,
783
                        (guint32)rec->Data.SOA.dwRetry,
784
                        (guint32)rec->Data.SOA.dwExpire,
785
                        (guint32)rec->Data.SOA.dwDefaultTtl);
786
}
787
788
static GVariant *
789
parse_dns_ns (DNS_RECORD *rec)
790
{
791
  return g_variant_new ("(s)", rec->Data.NS.pNameHost);
792
}
793
794
static GVariant *
795
parse_dns_mx (DNS_RECORD *rec)
796
{
797
  return g_variant_new ("(qs)",
798
                        (guint16)rec->Data.MX.wPreference,
799
                        rec->Data.MX.pNameExchange);
800
}
801
802
static GVariant *
803
parse_dns_txt (DNS_RECORD *rec)
804
{
805
  GVariant *record;
806
  GPtrArray *array;
807
  DWORD i;
808
809
  array = g_ptr_array_new ();
810
  for (i = 0; i < rec->Data.TXT.dwStringCount; i++)
811
    g_ptr_array_add (array, rec->Data.TXT.pStringArray[i]);
812
  record = g_variant_new ("(@as)",
813
                          g_variant_new_strv ((const gchar **)array->pdata, array->len));
814
  g_ptr_array_free (array, TRUE);
815
  return record;
816
}
817
818
static WORD
819
g_resolver_record_type_to_dnstype (GResolverRecordType type)
820
{
821
  switch (type)
822
  {
823
    case G_RESOLVER_RECORD_SRV:
824
      return DNS_TYPE_SRV;
825
    case G_RESOLVER_RECORD_TXT:
826
      return DNS_TYPE_TEXT;
827
    case G_RESOLVER_RECORD_SOA:
828
      return DNS_TYPE_SOA;
829
    case G_RESOLVER_RECORD_NS:
830
      return DNS_TYPE_NS;
831
    case G_RESOLVER_RECORD_MX:
832
      return DNS_TYPE_MX;
833
  }
834
  g_return_val_if_reached (-1);
835
}
836
837
static GList *
838
g_resolver_records_from_DnsQuery (const gchar  *rrname,
839
                                  WORD          dnstype,
840
                                  DNS_STATUS    status,
841
                                  DNS_RECORD   *results,
842
                                  GError      **error)
843
{
844
  DNS_RECORD *rec;
845
  gpointer record;
846
  GList *records;
847
848
  if (status != ERROR_SUCCESS)
849
    {
850
      if (status == DNS_ERROR_RCODE_NAME_ERROR)
851
        {
852
          g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND,
853
                       _("No DNS record of the requested type for “%s”"), rrname);
854
        }
855
      else if (status == DNS_ERROR_RCODE_SERVER_FAILURE)
856
        {
857
          g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_TEMPORARY_FAILURE,
858
                       _("Temporarily unable to resolve “%s”"), rrname);
859
        }
860
      else
861
        {
862
          g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_INTERNAL,
863
                       _("Error resolving “%s”"), rrname);
864
        }
865
866
      return NULL;
867
    }
868
869
  records = NULL;
870
  for (rec = results; rec; rec = rec->pNext)
871
    {
872
      if (rec->wType != dnstype)
873
        continue;
874
      switch (dnstype)
875
        {
876
        case DNS_TYPE_SRV:
877
          record = parse_dns_srv (rec);
878
          break;
879
        case DNS_TYPE_SOA:
880
          record = parse_dns_soa (rec);
881
          break;
882
        case DNS_TYPE_NS:
883
          record = parse_dns_ns (rec);
884
          break;
885
        case DNS_TYPE_MX:
886
          record = parse_dns_mx (rec);
887
          break;
888
        case DNS_TYPE_TEXT:
889
          record = parse_dns_txt (rec);
890
          break;
891
        default:
892
          g_warn_if_reached ();
893
          record = NULL;
894
          break;
895
        }
896
      if (record != NULL)
897
        records = g_list_prepend (records, g_variant_ref_sink (record));
898
    }
899
900
  if (records == NULL)
901
    {
902
      g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND,
903
                   _("No DNS record of the requested type for “%s”"), rrname);
904
905
      return NULL;
906
    }
907
  else
908
    return records;
909
}
910
911
#endif
912
913
typedef struct {
914
  char *rrname;
915
  GResolverRecordType record_type;
916
} LookupRecordsData;
917
918
static void
919
free_lookup_records_data (LookupRecordsData *lrd)
920
0
{
921
0
  g_free (lrd->rrname);
922
0
  g_slice_free (LookupRecordsData, lrd);
923
0
}
924
925
static void
926
free_records (GList *records)
927
0
{
928
0
  g_list_free_full (records, (GDestroyNotify) g_variant_unref);
929
0
}
930
931
#if defined(G_OS_UNIX)
932
#ifdef __BIONIC__
933
#ifndef C_IN
934
#define C_IN 1
935
#endif
936
int res_query(const char *, int, int, u_char *, int);
937
#endif
938
#endif
939
940
static void
941
do_lookup_records (GTask         *task,
942
                   gpointer       source_object,
943
                   gpointer       task_data,
944
                   GCancellable  *cancellable)
945
0
{
946
0
  LookupRecordsData *lrd = task_data;
947
0
  GList *records;
948
0
  GError *error = NULL;
949
950
0
#if defined(G_OS_UNIX)
951
0
  gint len = 512;
952
0
  gint herr;
953
0
  GByteArray *answer;
954
0
  gint rrtype;
955
956
0
#ifdef HAVE_RES_NQUERY
957
  /* Load the resolver state. This is done once per worker thread, and the
958
   * #GResolver::reload signal is ignored (since we always reload). This could
959
   * be improved by having an explicit worker thread pool, with each thread
960
   * containing some state which is initialised at thread creation time and
961
   * updated in response to #GResolver::reload.
962
   *
963
   * What we have currently is not particularly worse than using res_query() in
964
   * worker threads, since it would transparently call res_init() for each new
965
   * worker thread. (Although the workers would get reused by the
966
   * #GThreadPool.)
967
   *
968
   * FreeBSD requires the state to be zero-filled before calling res_ninit(). */
969
0
  struct __res_state res = { 0, };
970
0
  if (res_ninit (&res) != 0)
971
0
    {
972
0
      g_task_return_new_error (task, G_RESOLVER_ERROR, G_RESOLVER_ERROR_INTERNAL,
973
0
                               _("Error resolving “%s”"), lrd->rrname);
974
0
      return;
975
0
    }
976
0
#endif
977
978
0
  rrtype = g_resolver_record_type_to_rrtype (lrd->record_type);
979
0
  answer = g_byte_array_new ();
980
0
  for (;;)
981
0
    {
982
0
      g_byte_array_set_size (answer, len * 2);
983
0
#if defined(HAVE_RES_NQUERY)
984
0
      len = res_nquery (&res, lrd->rrname, C_IN, rrtype, answer->data, answer->len);
985
#else
986
      len = res_query (lrd->rrname, C_IN, rrtype, answer->data, answer->len);
987
#endif
988
989
      /* If answer fit in the buffer then we're done */
990
0
      if (len < 0 || len < (gint)answer->len)
991
0
        break;
992
993
      /*
994
       * On overflow some res_query's return the length needed, others
995
       * return the full length entered. This code works in either case.
996
       */
997
0
    }
998
999
0
  herr = h_errno;
1000
0
  records = g_resolver_records_from_res_query (lrd->rrname, rrtype, answer->data, len, herr, &error);
1001
0
  g_byte_array_free (answer, TRUE);
1002
1003
0
#ifdef HAVE_RES_NQUERY
1004
1005
#if defined(HAVE_RES_NDESTROY)
1006
  res_ndestroy (&res);
1007
#elif defined(HAVE_RES_NCLOSE)
1008
  res_nclose (&res);
1009
#elif defined(HAVE_RES_NINIT)
1010
#error "Your platform has res_ninit() but not res_nclose() or res_ndestroy(). Please file a bug at https://gitlab.gnome.org/GNOME/glib/issues/new"
1011
#endif
1012
1013
0
#endif  /* HAVE_RES_NQUERY */
1014
1015
#else
1016
1017
  DNS_STATUS status;
1018
  DNS_RECORD *results = NULL;
1019
  WORD dnstype;
1020
1021
  dnstype = g_resolver_record_type_to_dnstype (lrd->record_type);
1022
  status = DnsQuery_A (lrd->rrname, dnstype, DNS_QUERY_STANDARD, NULL, &results, NULL);
1023
  records = g_resolver_records_from_DnsQuery (lrd->rrname, dnstype, status, results, &error);
1024
  if (results != NULL)
1025
    DnsRecordListFree (results, DnsFreeRecordList);
1026
1027
#endif
1028
1029
0
  if (records)
1030
0
    g_task_return_pointer (task, records, (GDestroyNotify) free_records);
1031
0
  else
1032
0
    g_task_return_error (task, error);
1033
0
}
1034
1035
static GList *
1036
lookup_records (GResolver              *resolver,
1037
                const gchar            *rrname,
1038
                GResolverRecordType     record_type,
1039
                GCancellable           *cancellable,
1040
                GError                **error)
1041
0
{
1042
0
  GTask *task;
1043
0
  GList *records;
1044
0
  LookupRecordsData *lrd;
1045
1046
0
  task = g_task_new (resolver, cancellable, NULL, NULL);
1047
0
  g_task_set_source_tag (task, lookup_records);
1048
0
  g_task_set_name (task, "[gio] resolver lookup records");
1049
1050
0
  lrd = g_slice_new (LookupRecordsData);
1051
0
  lrd->rrname = g_strdup (rrname);
1052
0
  lrd->record_type = record_type;
1053
0
  g_task_set_task_data (task, lrd, (GDestroyNotify) free_lookup_records_data);
1054
1055
0
  g_task_set_return_on_cancel (task, TRUE);
1056
0
  g_task_run_in_thread_sync (task, do_lookup_records);
1057
0
  records = g_task_propagate_pointer (task, error);
1058
0
  g_object_unref (task);
1059
1060
0
  return records;
1061
0
}
1062
1063
static void
1064
lookup_records_async (GResolver           *resolver,
1065
                      const char          *rrname,
1066
                      GResolverRecordType  record_type,
1067
                      GCancellable        *cancellable,
1068
                      GAsyncReadyCallback  callback,
1069
                      gpointer             user_data)
1070
0
{
1071
0
  GTask *task;
1072
0
  LookupRecordsData *lrd;
1073
1074
0
  task = g_task_new (resolver, cancellable, callback, user_data);
1075
0
  g_task_set_source_tag (task, lookup_records_async);
1076
0
  g_task_set_name (task, "[gio] resolver lookup records");
1077
1078
0
  lrd = g_slice_new (LookupRecordsData);
1079
0
  lrd->rrname = g_strdup (rrname);
1080
0
  lrd->record_type = record_type;
1081
0
  g_task_set_task_data (task, lrd, (GDestroyNotify) free_lookup_records_data);
1082
1083
0
  g_task_set_return_on_cancel (task, TRUE);
1084
0
  g_task_run_in_thread (task, do_lookup_records);
1085
0
  g_object_unref (task);
1086
0
}
1087
1088
static GList *
1089
lookup_records_finish (GResolver     *resolver,
1090
                       GAsyncResult  *result,
1091
                       GError       **error)
1092
0
{
1093
0
  g_return_val_if_fail (g_task_is_valid (result, resolver), NULL);
1094
1095
0
  return g_task_propagate_pointer (G_TASK (result), error);
1096
0
}
1097
1098
1099
static void
1100
g_threaded_resolver_class_init (GThreadedResolverClass *threaded_class)
1101
0
{
1102
0
  GResolverClass *resolver_class = G_RESOLVER_CLASS (threaded_class);
1103
1104
0
  resolver_class->lookup_by_name                   = lookup_by_name;
1105
0
  resolver_class->lookup_by_name_async             = lookup_by_name_async;
1106
0
  resolver_class->lookup_by_name_finish            = lookup_by_name_finish;
1107
0
  resolver_class->lookup_by_name_with_flags        = lookup_by_name_with_flags;
1108
0
  resolver_class->lookup_by_name_with_flags_async  = lookup_by_name_with_flags_async;
1109
0
  resolver_class->lookup_by_name_with_flags_finish = lookup_by_name_with_flags_finish;
1110
0
  resolver_class->lookup_by_address                = lookup_by_address;
1111
0
  resolver_class->lookup_by_address_async          = lookup_by_address_async;
1112
0
  resolver_class->lookup_by_address_finish         = lookup_by_address_finish;
1113
0
  resolver_class->lookup_records                   = lookup_records;
1114
0
  resolver_class->lookup_records_async             = lookup_records_async;
1115
0
  resolver_class->lookup_records_finish            = lookup_records_finish;
1116
0
}