~ubuntu-branches/ubuntu/dapper/wget/dapper-updates

« back to all changes in this revision

Viewing changes to src/host.c

  • Committer: Bazaar Package Importer
  • Author(s): Noèl Köthe
  • Date: 2004-02-13 20:26:44 UTC
  • Revision ID: james.westby@ubuntu.com-20040213202644-skxj93qs15sskqfy
Tags: upstream-1.9.1
Import upstream version 1.9.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Host name resolution and matching.
 
2
   Copyright (C) 1995, 1996, 1997, 2000, 2001 Free Software Foundation, Inc.
 
3
 
 
4
This file is part of GNU Wget.
 
5
 
 
6
GNU Wget is free software; you can redistribute it and/or modify
 
7
it under the terms of the GNU General Public License as published by
 
8
the Free Software Foundation; either version 2 of the License, or
 
9
(at your option) any later version.
 
10
 
 
11
GNU Wget 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
 
14
GNU General Public License for more details.
 
15
 
 
16
You should have received a copy of the GNU General Public License
 
17
along with Wget; if not, write to the Free Software
 
18
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
19
 
 
20
In addition, as a special exception, the Free Software Foundation
 
21
gives permission to link the code of its release of Wget with the
 
22
OpenSSL project's "OpenSSL" library (or with modified versions of it
 
23
that use the same license as the "OpenSSL" library), and distribute
 
24
the linked executables.  You must obey the GNU General Public License
 
25
in all respects for all of the code used other than "OpenSSL".  If you
 
26
modify this file, you may extend this exception to your version of the
 
27
file, but you are not obligated to do so.  If you do not wish to do
 
28
so, delete this exception statement from your version.  */
 
29
 
 
30
#include <config.h>
 
31
 
 
32
#ifndef WINDOWS
 
33
#include <netdb.h>
 
34
#endif
 
35
 
 
36
#include <stdio.h>
 
37
#include <stdlib.h>
 
38
#ifdef HAVE_STRING_H
 
39
# include <string.h>
 
40
#else
 
41
# include <strings.h>
 
42
#endif
 
43
#include <assert.h>
 
44
#include <sys/types.h>
 
45
 
 
46
#ifdef WINDOWS
 
47
# include <winsock.h>
 
48
# define SET_H_ERRNO(err) WSASetLastError(err)
 
49
#else
 
50
# include <sys/socket.h>
 
51
# include <netinet/in.h>
 
52
# ifndef __BEOS__
 
53
#  include <arpa/inet.h>
 
54
# endif
 
55
# include <netdb.h>
 
56
# define SET_H_ERRNO(err) ((void)(h_errno = (err)))
 
57
#endif /* WINDOWS */
 
58
 
 
59
#ifndef NO_ADDRESS
 
60
#define NO_ADDRESS NO_DATA
 
61
#endif
 
62
 
 
63
#ifdef HAVE_SYS_UTSNAME_H
 
64
# include <sys/utsname.h>
 
65
#endif
 
66
#include <errno.h>
 
67
 
 
68
#include "wget.h"
 
69
#include "utils.h"
 
70
#include "host.h"
 
71
#include "url.h"
 
72
#include "hash.h"
 
73
 
 
74
#ifndef errno
 
75
extern int errno;
 
76
#endif
 
77
 
 
78
#ifndef h_errno
 
79
# ifndef __CYGWIN__
 
80
extern int h_errno;
 
81
# endif
 
82
#endif
 
83
 
 
84
#ifdef ENABLE_IPV6
 
85
int     ip_default_family = AF_INET6;
 
86
#else
 
87
int     ip_default_family = AF_INET;
 
88
#endif
 
89
 
 
90
/* Mapping between known hosts and to lists of their addresses. */
 
91
 
 
92
static struct hash_table *host_name_addresses_map;
 
93
 
 
94
/* Lists of addresses.  This should eventually be extended to handle
 
95
   IPv6.  */
 
96
 
 
97
struct address_list {
 
98
  int count;                    /* number of adrresses */
 
99
  ip_address *addresses;        /* pointer to the string of addresses */
 
100
 
 
101
  int faulty;                   /* number of addresses known not to work. */
 
102
  int refcount;                 /* so we know whether to free it or not. */
 
103
};
 
104
 
 
105
/* Get the bounds of the address list.  */
 
106
 
 
107
void
 
108
address_list_get_bounds (struct address_list *al, int *start, int *end)
 
109
{
 
110
  *start = al->faulty;
 
111
  *end   = al->count;
 
112
}
 
113
 
 
114
/* Copy address number INDEX to IP_STORE.  */
 
115
 
 
116
void
 
117
address_list_copy_one (struct address_list *al, int index, ip_address *ip_store)
 
118
{
 
119
  assert (index >= al->faulty && index < al->count);
 
120
  memcpy (ip_store, al->addresses + index, sizeof (ip_address));
 
121
}
 
122
 
 
123
/* Check whether two address lists have all their IPs in common.  */
 
124
 
 
125
int
 
126
address_list_match_all (struct address_list *al1, struct address_list *al2)
 
127
{
 
128
  if (al1 == al2)
 
129
    return 1;
 
130
  if (al1->count != al2->count)
 
131
    return 0;
 
132
  return 0 == memcmp (al1->addresses, al2->addresses,
 
133
                      al1->count * sizeof (ip_address));
 
134
}
 
135
 
 
136
/* Mark the INDEXth element of AL as faulty, so that the next time
 
137
   this address list is used, the faulty element will be skipped.  */
 
138
 
 
139
void
 
140
address_list_set_faulty (struct address_list *al, int index)
 
141
{
 
142
  /* We assume that the address list is traversed in order, so that a
 
143
     "faulty" attempt is always preceded with all-faulty addresses,
 
144
     and this is how Wget uses it.  */
 
145
  assert (index == al->faulty);
 
146
 
 
147
  ++al->faulty;
 
148
  if (al->faulty >= al->count)
 
149
    /* All addresses have been proven faulty.  Since there's not much
 
150
       sense in returning the user an empty address list the next
 
151
       time, we'll rather make them all clean, so that they can be
 
152
       retried anew.  */
 
153
    al->faulty = 0;
 
154
}
 
155
 
 
156
#ifdef HAVE_GETADDRINFO
 
157
/**
 
158
  * address_list_from_addrinfo
 
159
  *
 
160
  * This function transform an addrinfo links list in and address_list.
 
161
  *
 
162
  * Input:
 
163
  * addrinfo*           Linkt list of addrinfo
 
164
  *
 
165
  * Output:
 
166
  * address_list*       New allocated address_list
 
167
  */
 
168
static struct address_list *
 
169
address_list_from_addrinfo (struct addrinfo *ai)
 
170
{
 
171
  struct address_list *al;
 
172
  struct addrinfo *ai_head = ai;
 
173
  int cnt = 0;
 
174
  int i;
 
175
 
 
176
  for (ai = ai_head; ai; ai = ai->ai_next)
 
177
    if (ai->ai_family == AF_INET || ai->ai_family == AF_INET6)
 
178
      ++cnt;
 
179
  if (cnt == 0)
 
180
    return NULL;
 
181
 
 
182
  al = xmalloc (sizeof (struct address_list));
 
183
  al->addresses = xmalloc (cnt * sizeof (ip_address));
 
184
  al->count     = cnt;
 
185
  al->faulty    = 0;
 
186
  al->refcount  = 1;
 
187
 
 
188
  for (i = 0, ai = ai_head; ai; ai = ai->ai_next)
 
189
    if (ai->ai_family == AF_INET6) 
 
190
      {
 
191
        struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ai->ai_addr;
 
192
        memcpy (al->addresses + i, &sin6->sin6_addr, 16);
 
193
        ++i;
 
194
      } 
 
195
    else if (ai->ai_family == AF_INET)
 
196
      {
 
197
        struct sockaddr_in *sin = (struct sockaddr_in *)ai->ai_addr;
 
198
        map_ipv4_to_ip ((ip4_address *)&sin->sin_addr, al->addresses + i);
 
199
        ++i;
 
200
      }
 
201
  assert (i == cnt);
 
202
  return al;
 
203
}
 
204
#else
 
205
/* Create an address_list out of a NULL-terminated vector of
 
206
   addresses, as returned by gethostbyname.  */
 
207
static struct address_list *
 
208
address_list_from_vector (char **h_addr_list)
 
209
{
 
210
  int count = 0, i;
 
211
 
 
212
  struct address_list *al = xmalloc (sizeof (struct address_list));
 
213
 
 
214
  while (h_addr_list[count])
 
215
    ++count;
 
216
  assert (count > 0);
 
217
  al->count     = count;
 
218
  al->faulty    = 0;
 
219
  al->addresses = xmalloc (count * sizeof (ip_address));
 
220
  al->refcount  = 1;
 
221
 
 
222
  for (i = 0; i < count; i++)
 
223
    map_ipv4_to_ip ((ip4_address *)h_addr_list[i], al->addresses + i);
 
224
 
 
225
  return al;
 
226
}
 
227
#endif
 
228
 
 
229
/* Like address_list_from_vector, but initialized with a single
 
230
   address. */
 
231
 
 
232
static struct address_list *
 
233
address_list_from_single (ip_address *addr)
 
234
{
 
235
  struct address_list *al = xmalloc (sizeof (struct address_list));
 
236
  al->count     = 1;
 
237
  al->faulty    = 0;
 
238
  al->addresses = xmalloc (sizeof (ip_address));
 
239
  al->refcount  = 1;
 
240
  memcpy (al->addresses, addr, sizeof (ip_address));
 
241
 
 
242
  return al;
 
243
}
 
244
 
 
245
static void
 
246
address_list_delete (struct address_list *al)
 
247
{
 
248
  xfree (al->addresses);
 
249
  xfree (al);
 
250
}
 
251
 
 
252
void
 
253
address_list_release (struct address_list *al)
 
254
{
 
255
  --al->refcount;
 
256
  DEBUGP (("Releasing %p (new refcount %d).\n", al, al->refcount));
 
257
  if (al->refcount <= 0)
 
258
    {
 
259
      DEBUGP (("Deleting unused %p.\n", al));
 
260
      address_list_delete (al);
 
261
    }
 
262
}
 
263
 
 
264
/**
 
265
  * wget_sockaddr_set_address
 
266
  *
 
267
  * This function takes an wget_sockaddr and fill in the protocol type,
 
268
  * the port number and the address, there NULL in address means wildcard.
 
269
  * Unsuported adress family will abort the whole programm.
 
270
  *
 
271
  * Input:
 
272
  * wget_sockaddr*      The space to be filled
 
273
  * int                 The wished protocol
 
274
  * unsigned short      The port
 
275
  * const ip_address    The Binary IP adress
 
276
  *
 
277
  * Return:
 
278
  * -                   Only modify 1. param
 
279
  */
 
280
void
 
281
wget_sockaddr_set_address (wget_sockaddr *sa, 
 
282
                           int ip_family, unsigned short port, ip_address *addr)
 
283
{
 
284
  if (ip_family == AF_INET) 
 
285
    {
 
286
      sa->sin.sin_family = ip_family;
 
287
      sa->sin.sin_port = htons (port);
 
288
      if (addr == NULL) 
 
289
        memset (&sa->sin.sin_addr, 0,      sizeof(ip4_address));
 
290
      else
 
291
        {
 
292
          ip4_address addr4;
 
293
          if (!map_ip_to_ipv4 (addr, &addr4))
 
294
            /* should the callers have prevented this? */
 
295
            abort ();
 
296
          memcpy (&sa->sin.sin_addr, &addr4, sizeof(ip4_address));
 
297
        }
 
298
      return;
 
299
    }
 
300
#ifdef ENABLE_IPV6
 
301
  if (ip_family == AF_INET6) 
 
302
    {
 
303
      sa->sin6.sin6_family = ip_family;
 
304
      sa->sin6.sin6_port = htons (port);
 
305
      if (addr == NULL) 
 
306
        memset (&sa->sin6.sin6_addr, 0   , 16);
 
307
      else           
 
308
        memcpy (&sa->sin6.sin6_addr, addr, 16);
 
309
      return;
 
310
    }
 
311
#endif  
 
312
  abort();
 
313
}
 
314
 
 
315
/**
 
316
  * wget_sockaddr_set_port
 
317
  *
 
318
  * This funtion only fill the port of the socket information.
 
319
  * If the protocol is not supported nothing is done.
 
320
  * Unsuported adress family will abort the whole programm.
 
321
  * 
 
322
  * Require:
 
323
  * that the IP-Protocol already is set.
 
324
  *
 
325
  * Input:
 
326
  * wget_sockaddr*      The space there port should be entered
 
327
  * unsigned int        The port that should be entered in host order
 
328
  *
 
329
  * Return:
 
330
  * -                   Only modify 1. param
 
331
  */
 
332
void 
 
333
wget_sockaddr_set_port (wget_sockaddr *sa, unsigned short port)
 
334
{
 
335
  if (sa->sa.sa_family == AF_INET)
 
336
    {
 
337
      sa->sin.sin_port = htons (port);
 
338
      return;
 
339
    }  
 
340
#ifdef ENABLE_IPV6
 
341
  if (sa->sa.sa_family == AF_INET6)
 
342
    {
 
343
      sa->sin6.sin6_port = htons (port);
 
344
      return;
 
345
    }
 
346
#endif
 
347
  abort();
 
348
}
 
349
 
 
350
/**
 
351
  * wget_sockaddr_get_addr
 
352
  *
 
353
  * This function return the adress from an sockaddr as byte string.
 
354
  * Unsuported adress family will abort the whole programm.
 
355
  * 
 
356
  * Require:
 
357
  * that the IP-Protocol already is set.
 
358
  *
 
359
  * Input:
 
360
  * wget_sockaddr*      Socket Information
 
361
  *
 
362
  * Output:
 
363
  * unsigned char *     IP address as byte string.
 
364
  */
 
365
void *
 
366
wget_sockaddr_get_addr (wget_sockaddr *sa)
 
367
 
368
  if (sa->sa.sa_family == AF_INET)
 
369
    return &sa->sin.sin_addr;
 
370
#ifdef ENABLE_IPV6
 
371
  if (sa->sa.sa_family == AF_INET6)
 
372
    return &sa->sin6.sin6_addr;
 
373
#endif
 
374
  abort();
 
375
  /* unreached */
 
376
  return NULL;
 
377
}
 
378
 
 
379
/**
 
380
  * wget_sockaddr_get_port
 
381
  *
 
382
  * This function only return the port from the input structure
 
383
  * Unsuported adress family will abort the whole programm.
 
384
  * 
 
385
  * Require:
 
386
  * that the IP-Protocol already is set.
 
387
  *
 
388
  * Input:
 
389
  * wget_sockaddr*      Information where to get the port
 
390
  *
 
391
  * Output:
 
392
  * unsigned short      Port Number in host order.
 
393
  */
 
394
unsigned short 
 
395
wget_sockaddr_get_port (const wget_sockaddr *sa)
 
396
{
 
397
  if (sa->sa.sa_family == AF_INET)
 
398
      return htons (sa->sin.sin_port);
 
399
#ifdef ENABLE_IPV6
 
400
  if (sa->sa.sa_family == AF_INET6)
 
401
      return htons (sa->sin6.sin6_port);
 
402
#endif
 
403
  abort();
 
404
  /* do not complain about return nothing */
 
405
  return -1;
 
406
}
 
407
 
 
408
/**
 
409
  * sockaddr_len
 
410
  *
 
411
  * This function return the length of the sockaddr corresponding to 
 
412
  * the acutall prefered protocol for (bind, connect etc...)
 
413
  * Unsuported adress family will abort the whole programm.
 
414
  * 
 
415
  * Require:
 
416
  * that the IP-Protocol already is set.
 
417
  *
 
418
  * Input:
 
419
  * -           Public IP-Family Information
 
420
  *
 
421
  * Output:
 
422
  * socklen_t   structure length for socket options
 
423
  */
 
424
socklen_t
 
425
sockaddr_len () 
 
426
{
 
427
  if (ip_default_family == AF_INET) 
 
428
    return sizeof (struct sockaddr_in);
 
429
#ifdef ENABLE_IPV6
 
430
  if (ip_default_family == AF_INET6) 
 
431
    return sizeof (struct sockaddr_in6);
 
432
#endif
 
433
  abort();
 
434
  /* do not complain about return nothing */
 
435
  return 0;
 
436
}
 
437
 
 
438
/**
 
439
  * Map an IPv4 adress to the internal adress format.
 
440
  */
 
441
void 
 
442
map_ipv4_to_ip (ip4_address *ipv4, ip_address *ip) 
 
443
{
 
444
#ifdef ENABLE_IPV6
 
445
  static unsigned char ipv64[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff};
 
446
  memcpy ((char *)ip + 12, ipv4 , 4);
 
447
  memcpy ((char *)ip + 0, ipv64, 12);
 
448
#else
 
449
  if ((char *)ip != (char *)ipv4)
 
450
    memcpy (ip, ipv4, 4);
 
451
#endif
 
452
}
 
453
 
 
454
/* Detect whether an IP adress represents an IPv4 address and, if so,
 
455
   copy it to IPV4.  0 is returned on failure.
 
456
   This operation always succeeds when Wget is compiled without IPv6.
 
457
   If IPV4 is NULL, don't copy, just detect.  */
 
458
 
 
459
int 
 
460
map_ip_to_ipv4 (ip_address *ip, ip4_address *ipv4) 
 
461
{
 
462
#ifdef ENABLE_IPV6
 
463
  static unsigned char ipv64[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff};
 
464
  if (0 != memcmp (ip, ipv64, 12))
 
465
    return 0;
 
466
  if (ipv4)
 
467
    memcpy (ipv4, (char *)ip + 12, 4);
 
468
#else
 
469
  if (ipv4)
 
470
    memcpy (ipv4, (char *)ip, 4);
 
471
#endif
 
472
  return 1;
 
473
}
 
474
 
 
475
/* Versions of gethostbyname and getaddrinfo that support timeout. */
 
476
 
 
477
#ifndef ENABLE_IPV6
 
478
 
 
479
struct ghbnwt_context {
 
480
  const char *host_name;
 
481
  struct hostent *hptr;
 
482
};
 
483
 
 
484
static void
 
485
gethostbyname_with_timeout_callback (void *arg)
 
486
{
 
487
  struct ghbnwt_context *ctx = (struct ghbnwt_context *)arg;
 
488
  ctx->hptr = gethostbyname (ctx->host_name);
 
489
}
 
490
 
 
491
/* Just like gethostbyname, except it times out after TIMEOUT seconds.
 
492
   In case of timeout, NULL is returned and errno is set to ETIMEDOUT.
 
493
   The function makes sure that when NULL is returned for reasons
 
494
   other than timeout, errno is reset.  */
 
495
 
 
496
static struct hostent *
 
497
gethostbyname_with_timeout (const char *host_name, double timeout)
 
498
{
 
499
  struct ghbnwt_context ctx;
 
500
  ctx.host_name = host_name;
 
501
  if (run_with_timeout (timeout, gethostbyname_with_timeout_callback, &ctx))
 
502
    {
 
503
      SET_H_ERRNO (HOST_NOT_FOUND);
 
504
      errno = ETIMEDOUT;
 
505
      return NULL;
 
506
    }
 
507
  if (!ctx.hptr)
 
508
    errno = 0;
 
509
  return ctx.hptr;
 
510
}
 
511
 
 
512
#else  /* ENABLE_IPV6 */
 
513
 
 
514
struct gaiwt_context {
 
515
  const char *node;
 
516
  const char *service;
 
517
  const struct addrinfo *hints;
 
518
  struct addrinfo **res;
 
519
  int exit_code;
 
520
};
 
521
 
 
522
static void
 
523
getaddrinfo_with_timeout_callback (void *arg)
 
524
{
 
525
  struct gaiwt_context *ctx = (struct gaiwt_context *)arg;
 
526
  ctx->exit_code = getaddrinfo (ctx->node, ctx->service, ctx->hints, ctx->res);
 
527
}
 
528
 
 
529
/* Just like getaddrinfo, except it times out after TIMEOUT seconds.
 
530
   In case of timeout, the EAI_SYSTEM error code is returned and errno
 
531
   is set to ETIMEDOUT.  */
 
532
 
 
533
static int
 
534
getaddrinfo_with_timeout (const char *node, const char *service,
 
535
                          const struct addrinfo *hints, struct addrinfo **res,
 
536
                          double timeout)
 
537
{
 
538
  struct gaiwt_context ctx;
 
539
  ctx.node = node;
 
540
  ctx.service = service;
 
541
  ctx.hints = hints;
 
542
  ctx.res = res;
 
543
 
 
544
  if (run_with_timeout (timeout, getaddrinfo_with_timeout_callback, &ctx))
 
545
    {
 
546
      errno = ETIMEDOUT;
 
547
      return EAI_SYSTEM;
 
548
    }
 
549
  return ctx.exit_code;
 
550
}
 
551
 
 
552
#endif /* ENABLE_IPV6 */
 
553
 
 
554
/* Pretty-print ADDR.  When compiled without IPv6, this is the same as
 
555
   inet_ntoa.  With IPv6, it either prints an IPv6 address or an IPv4
 
556
   address.  */
 
557
 
 
558
char *
 
559
pretty_print_address (ip_address *addr)
 
560
{
 
561
#ifdef ENABLE_IPV6
 
562
  ip4_address addr4;
 
563
  static char buf[128];
 
564
 
 
565
  if (map_ip_to_ipv4 (addr, &addr4))
 
566
    return inet_ntoa (*(struct in_addr *)&addr4);
 
567
 
 
568
  if (!inet_ntop (AF_INET6, addr, buf, sizeof (buf)))
 
569
    return "<unknown>";
 
570
  return buf;
 
571
#endif
 
572
  return inet_ntoa (*(struct in_addr *)addr);
 
573
}
 
574
 
 
575
/* Add host name HOST with the address ADDR_TEXT to the cache.
 
576
   ADDR_LIST is a NULL-terminated list of addresses, as in struct
 
577
   hostent.  */
 
578
 
 
579
static void
 
580
cache_host_lookup (const char *host, struct address_list *al)
 
581
{
 
582
  if (!host_name_addresses_map)
 
583
    host_name_addresses_map = make_nocase_string_hash_table (0);
 
584
 
 
585
  ++al->refcount;
 
586
  hash_table_put (host_name_addresses_map, xstrdup_lower (host), al);
 
587
 
 
588
#ifdef ENABLE_DEBUG
 
589
  if (opt.debug)
 
590
    {
 
591
      int i;
 
592
      debug_logprintf ("Caching %s =>", host);
 
593
      for (i = 0; i < al->count; i++)
 
594
        debug_logprintf (" %s", pretty_print_address (al->addresses + i));
 
595
      debug_logprintf ("\n");
 
596
    }
 
597
#endif
 
598
}
 
599
 
 
600
struct address_list *
 
601
lookup_host (const char *host, int silent)
 
602
{
 
603
  struct address_list *al = NULL;
 
604
  uint32_t addr_ipv4;
 
605
  ip_address addr;
 
606
 
 
607
  /* First, try to check whether the address is already a numeric
 
608
     address.  */
 
609
 
 
610
#ifdef ENABLE_IPV6
 
611
  if (inet_pton (AF_INET6, host, &addr) > 0)
 
612
    return address_list_from_single (&addr);
 
613
#endif
 
614
 
 
615
  addr_ipv4 = (uint32_t)inet_addr (host);
 
616
  if (addr_ipv4 != (uint32_t)-1)
 
617
    {
 
618
      /* ADDR is defined to be in network byte order, which is what
 
619
         this returns, so we can just copy it to STORE_IP.  */
 
620
      map_ipv4_to_ip ((ip4_address *)&addr_ipv4, &addr);
 
621
      return address_list_from_single (&addr);
 
622
    }
 
623
 
 
624
  if (host_name_addresses_map)
 
625
    {
 
626
      al = hash_table_get (host_name_addresses_map, host);
 
627
      if (al)
 
628
        {
 
629
          DEBUGP (("Found %s in host_name_addresses_map (%p)\n", host, al));
 
630
          ++al->refcount;
 
631
          return al;
 
632
        }
 
633
    }
 
634
 
 
635
  if (!silent)
 
636
    logprintf (LOG_VERBOSE, _("Resolving %s... "), host);
 
637
 
 
638
  /* Host name lookup goes on below. */
 
639
 
 
640
#ifdef HAVE_GETADDRINFO
 
641
  {
 
642
    struct addrinfo hints, *ai;
 
643
    int err;
 
644
 
 
645
    memset (&hints, 0, sizeof (hints));
 
646
    if (ip_default_family == AF_INET)
 
647
      hints.ai_family   = AF_INET;
 
648
    else
 
649
      hints.ai_family   = PF_UNSPEC;
 
650
    hints.ai_socktype = SOCK_STREAM;
 
651
    err = getaddrinfo_with_timeout (host, NULL, &hints, &ai, opt.dns_timeout);
 
652
 
 
653
    if (err != 0 || ai == NULL)
 
654
      {
 
655
        if (!silent)
 
656
          logprintf (LOG_VERBOSE, _("failed: %s.\n"),
 
657
                     err != EAI_SYSTEM ? gai_strerror (err) : strerror (errno));
 
658
        return NULL;
 
659
      }
 
660
    al = address_list_from_addrinfo (ai);
 
661
    freeaddrinfo (ai);
 
662
  }
 
663
#else
 
664
  {
 
665
    struct hostent *hptr;
 
666
    hptr = gethostbyname_with_timeout (host, opt.dns_timeout);
 
667
    if (!hptr)
 
668
      {
 
669
        if (!silent)
 
670
          {
 
671
            if (errno != ETIMEDOUT)
 
672
              logprintf (LOG_VERBOSE, _("failed: %s.\n"), herrmsg (h_errno));
 
673
            else
 
674
              logputs (LOG_VERBOSE, _("failed: timed out.\n"));
 
675
          }
 
676
        return NULL;
 
677
      }
 
678
    /* Do all systems have h_addr_list, or is it a newer thing?  If
 
679
       the latter, use address_list_from_single.  */
 
680
    al = address_list_from_vector (hptr->h_addr_list);
 
681
  }
 
682
#endif
 
683
 
 
684
  /* Print the addresses determined by DNS lookup, but no more than
 
685
     three.  */
 
686
  if (!silent)
 
687
    {
 
688
      int i;
 
689
      int printmax = al->count <= 3 ? al->count : 3;
 
690
      for (i = 0; i < printmax; i++)
 
691
        {
 
692
          logprintf (LOG_VERBOSE, "%s",
 
693
                     pretty_print_address (al->addresses + i));
 
694
          if (i < printmax - 1)
 
695
            logputs (LOG_VERBOSE, ", ");
 
696
        }
 
697
      if (printmax != al->count)
 
698
        logputs (LOG_VERBOSE, ", ...");
 
699
      logputs (LOG_VERBOSE, "\n");
 
700
    }
 
701
 
 
702
  /* Cache the lookup information. */
 
703
  if (opt.dns_cache)
 
704
    cache_host_lookup (host, al);
 
705
 
 
706
  return al;
 
707
}
 
708
 
 
709
/* Determine whether a URL is acceptable to be followed, according to
 
710
   a list of domains to accept.  */
 
711
int
 
712
accept_domain (struct url *u)
 
713
{
 
714
  assert (u->host != NULL);
 
715
  if (opt.domains)
 
716
    {
 
717
      if (!sufmatch ((const char **)opt.domains, u->host))
 
718
        return 0;
 
719
    }
 
720
  if (opt.exclude_domains)
 
721
    {
 
722
      if (sufmatch ((const char **)opt.exclude_domains, u->host))
 
723
        return 0;
 
724
    }
 
725
  return 1;
 
726
}
 
727
 
 
728
/* Check whether WHAT is matched in LIST, each element of LIST being a
 
729
   pattern to match WHAT against, using backward matching (see
 
730
   match_backwards() in utils.c).
 
731
 
 
732
   If an element of LIST matched, 1 is returned, 0 otherwise.  */
 
733
int
 
734
sufmatch (const char **list, const char *what)
 
735
{
 
736
  int i, j, k, lw;
 
737
 
 
738
  lw = strlen (what);
 
739
  for (i = 0; list[i]; i++)
 
740
    {
 
741
      for (j = strlen (list[i]), k = lw; j >= 0 && k >= 0; j--, k--)
 
742
        if (TOLOWER (list[i][j]) != TOLOWER (what[k]))
 
743
          break;
 
744
      /* The domain must be first to reach to beginning.  */
 
745
      if (j == -1)
 
746
        return 1;
 
747
    }
 
748
  return 0;
 
749
}
 
750
 
 
751
/* Print error messages for host errors.  */
 
752
char *
 
753
herrmsg (int error)
 
754
{
 
755
  /* Can't use switch since some constants are equal (at least on my
 
756
     system), and the compiler signals "duplicate case value".  */
 
757
  if (error == HOST_NOT_FOUND
 
758
      || error == NO_RECOVERY
 
759
      || error == NO_DATA
 
760
      || error == NO_ADDRESS
 
761
      || error == TRY_AGAIN)
 
762
    return _("Host not found");
 
763
  else
 
764
    return _("Unknown error");
 
765
}
 
766
 
 
767
static int
 
768
host_cleanup_mapper (void *key, void *value, void *arg_ignored)
 
769
{
 
770
  struct address_list *al;
 
771
 
 
772
  xfree (key);                  /* host */
 
773
 
 
774
  al = (struct address_list *)value;
 
775
  assert (al->refcount == 1);
 
776
  address_list_delete (al);
 
777
 
 
778
  return 0;
 
779
}
 
780
 
 
781
void
 
782
host_cleanup (void)
 
783
{
 
784
  if (host_name_addresses_map)
 
785
    {
 
786
      hash_table_map (host_name_addresses_map, host_cleanup_mapper, NULL);
 
787
      hash_table_destroy (host_name_addresses_map);
 
788
      host_name_addresses_map = NULL;
 
789
    }
 
790
}