]> sjero.net Git - wget/blob - src/host.c
[svn] Initial revision
[wget] / src / host.c
1 /* Dealing with host names.
2    Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
3
4 This file is part of Wget.
5
6 This program 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 This program 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 this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
19
20 #include <config.h>
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <ctype.h>
25 #ifdef HAVE_STRING_H
26 # include <string.h>
27 #else
28 # include <strings.h>
29 #endif
30 #include <assert.h>
31 #include <sys/types.h>
32
33 #ifdef WINDOWS
34 # include <winsock.h>
35 #else
36 # include <sys/socket.h>
37 # include <netinet/in.h>
38 # include <arpa/inet.h>
39 # include <netdb.h>
40 #endif /* WINDOWS */
41
42 #ifdef HAVE_SYS_UTSNAME_H
43 # include <sys/utsname.h>
44 #endif
45 #include <errno.h>
46
47 #include "wget.h"
48 #include "utils.h"
49 #include "host.h"
50 #include "url.h"
51
52 #ifndef errno
53 extern int errno;
54 #endif
55
56 /* Host list entry */
57 struct host
58 {
59   /* Host's symbolical name, as encountered at the time of first
60      inclusion, e.g. "fly.cc.fer.hr".  */
61   char *hostname;
62   /* Host's "real" name, i.e. its IP address, written out in ASCII
63      form of N.N.N.N, e.g. "161.53.70.130".  */
64   char *realname;
65   /* More than one HOSTNAME can correspond to the same REALNAME.  For
66      our purposes, the canonical name of the host is its HOSTNAME when
67      it was first encountered.  This entry is said to have QUALITY.  */
68   int quality;
69   /* Next entry in the list.  */
70   struct host *next;
71 };
72
73 static struct host *hlist;
74
75 static struct host *add_hlist PARAMS ((struct host *, const char *,
76                                        const char *, int));
77
78 /* The same as gethostbyname, but supports internet addresses of the
79    form `N.N.N.N'.  */
80 struct hostent *
81 ngethostbyname (const char *name)
82 {
83   struct hostent *hp;
84   unsigned long addr;
85
86   addr = (unsigned long)inet_addr (name);
87   if ((int)addr != -1)
88     hp = gethostbyaddr ((char *)&addr, sizeof (addr), AF_INET);
89   else
90     hp = gethostbyname (name);
91   return hp;
92 }
93
94 /* Search for HOST in the linked list L, by hostname.  Return the
95    entry, if found, or NULL.  The search is case-insensitive.  */
96 static struct host *
97 search_host (struct host *l, const char *host)
98 {
99   for (; l; l = l->next)
100     if (strcasecmp (l->hostname, host) == 0)
101       return l;
102   return NULL;
103 }
104
105 /* Like search_host, but searches by address.  */
106 static struct host *
107 search_address (struct host *l, const char *address)
108 {
109   for (; l; l = l->next)
110     {
111       int cmp = strcmp (l->realname, address);
112       if (cmp == 0)
113         return l;
114       else if (cmp > 0)
115         return NULL;
116     }
117   return NULL;
118 }
119
120 /* Store the address of HOSTNAME, internet-style, to WHERE.  First
121    check for it in the host list, and (if not found), use
122    ngethostbyname to get it.
123
124    Return 1 on successful finding of the hostname, 0 otherwise.  */
125 int
126 store_hostaddress (unsigned char *where, const char *hostname)
127 {
128   struct host *t;
129   unsigned long addr;
130   struct hostent *hptr;
131   struct in_addr in;
132   char *inet_s;
133
134   /* If the address is of the form d.d.d.d, there will be no trouble
135      with it.  */
136   addr = (unsigned long)inet_addr (hostname);
137   if ((int)addr == -1)
138     {
139       /* If it is not of that form, try to find it in the cache.  */
140       t = search_host (hlist, hostname);
141       if (t)
142         addr = (unsigned long)inet_addr (t->realname);
143     }
144   /* If we have the numeric address, just store it.  */
145   if ((int)addr != -1)
146     {
147       /* This works on both little and big endian architecture, as
148          inet_addr returns the address in the proper order.  It
149          appears to work on 64-bit machines too.  */
150       memcpy (where, &addr, 4);
151       return 1;
152     }
153   /* Since all else has failed, let's try gethostbyname().  Note that
154      we use gethostbyname() rather than ngethostbyname(), because we
155      *know* the address is not numerical.  */
156   hptr = gethostbyname (hostname);
157   if (!hptr)
158     return 0;
159   /* Copy the address of the host to socket description.  */
160   memcpy (where, hptr->h_addr_list[0], hptr->h_length);
161   /* Now that we're here, we could as well cache the hostname for
162      future use, as in realhost().  First, we have to look for it by
163      address to know if it's already in the cache by another name.  */
164
165   /* Originally, we copied to in.s_addr, but it appears to be missing
166      on some systems.  */
167   memcpy (&in, *hptr->h_addr_list, sizeof (in));
168   STRDUP_ALLOCA (inet_s, inet_ntoa (in));
169   t = search_address (hlist, inet_s);
170   if (t) /* Found in the list, as realname.  */
171     {
172       /* Set the default, 0 quality.  */
173       hlist = add_hlist (hlist, hostname, inet_s, 0);
174       return 1;
175     }
176   /* Since this is really the first time this host is encountered,
177      set quality to 1.  */
178   hlist = add_hlist (hlist, hostname, inet_s, 1);
179   return 1;
180 }
181
182 /* Add a host to the host list.  The list is sorted by addresses.  For
183    equal addresses, the entries with quality should bubble towards the
184    beginning of the list.  */
185 static struct host *
186 add_hlist (struct host *l, const char *nhost, const char *nreal, int quality)
187 {
188   struct host *t, *old, *beg;
189
190   /* The entry goes to the beginning of the list if the list is empty
191      or the order requires it.  */
192   if (!l || (strcmp (nreal, l->realname) < 0))
193     {
194       t = (struct host *)xmalloc (sizeof (struct host));
195       t->hostname = xstrdup (nhost);
196       t->realname = xstrdup (nreal);
197       t->quality = quality;
198       t->next = l;
199       return t;
200     }
201
202   beg = l;
203   /* Second two one-before-the-last element.  */
204   while (l->next)
205     {
206       int cmp;
207       old = l;
208       l = l->next;
209       cmp = strcmp (nreal, l->realname);
210       if (cmp >= 0)
211         continue;
212       /* If the next list element is greater than s, put s between the
213          current and the next list element.  */
214       t = (struct host *)xmalloc (sizeof (struct host));
215       old->next = t;
216       t->next = l;
217       t->hostname = xstrdup (nhost);
218       t->realname = xstrdup (nreal);
219       t->quality = quality;
220       return beg;
221     }
222   t = (struct host *)xmalloc (sizeof (struct host));
223   t->hostname = xstrdup (nhost);
224   t->realname = xstrdup (nreal);
225   t->quality = quality;
226   /* Insert the new element after the last element.  */
227   l->next = t;
228   t->next = NULL;
229   return beg;
230 }
231
232 /* Determine the "real" name of HOST, as perceived by Wget.  If HOST
233    is referenced by more than one name, "real" name is considered to
234    be the first one encountered in the past.
235
236    If the host cannot be found in the list of already dealt-with
237    hosts, try with its INET address.  If this fails too, add it to the
238    list.  The routine does not call gethostbyname twice for the same
239    host if it can possibly avoid it.  */
240 char *
241 realhost (const char *host)
242 {
243   struct host *l;
244   struct in_addr in;
245   struct hostent *hptr;
246   char *inet_s;
247
248   DEBUGP (("Checking for %s.\n", host));
249   /* Look for the host, looking by the host name.  */
250   l = search_host (hlist, host);
251   if (l && l->quality)              /* Found it with quality */
252     {
253       DEBUGP (("%s was already used, by that name.\n", host));
254       /* Here we return l->hostname, not host, because of the possible
255          case differences (e.g. jaGOR.srce.hr and jagor.srce.hr are
256          the same, but we want the one that was first.  */
257       return xstrdup (l->hostname);
258     }
259   else if (!l)                      /* Not found, with or without quality */
260     {
261       /* The fact that gethostbyname will get called makes it
262          necessary to store it to the list, to ensure that
263          gethostbyname will not be called twice for the same string.
264          However, the quality argument must be set appropriately.
265
266          Note that add_hlist must be called *after* the realname
267          search, or the quality would be always set to 0 */
268       DEBUGP (("This is the first time I hear about host %s by that name.\n",
269                host));
270       hptr = ngethostbyname (host);
271       if (!hptr)
272         return xstrdup (host);
273       /* Originally, we copied to in.s_addr, but it appears to be
274          missing on some systems.  */
275       memcpy (&in, *hptr->h_addr_list, sizeof (in));
276       STRDUP_ALLOCA (inet_s, inet_ntoa (in));
277     }
278   else /* Found, without quality */
279     {
280       /* This case happens when host is on the list,
281          but not as first entry (the one with quality).
282          Then we just get its INET address and pick
283          up the first entry with quality.  */
284       DEBUGP (("We've dealt with host %s, but under the name %s.\n",
285                host, l->realname));
286       STRDUP_ALLOCA (inet_s, l->realname);
287     }
288
289   /* Now we certainly have the INET address.  The following loop is
290      guaranteed to pick either an entry with quality (because it is
291      the first one), or none at all.  */
292   l = search_address (hlist, inet_s);
293   if (l) /* Found in the list, as realname.  */
294     {
295       /* Set the default, 0 quality.  */
296       hlist = add_hlist (hlist, host, inet_s, 0);
297       return xstrdup (l->hostname);
298     }
299   /* Since this is really the first time this host is encountered,
300      set quality to 1.  */
301   hlist = add_hlist (hlist, host, inet_s, 1);
302   return xstrdup (host);
303 }
304
305 /* Compare two hostnames (out of URL-s if the arguments are URL-s),
306    taking care of aliases.  It uses realhost() to determine a unique
307    hostname for each of two hosts.  If simple_check is non-zero, only
308    strcmp() is used for comparison.  */
309 int
310 same_host (const char *u1, const char *u2)
311 {
312   const char *s;
313   char *p1, *p2;
314   char *real1, *real2;
315
316   /* Skip protocol, if present.  */
317   u1 += skip_url (u1);
318   u2 += skip_url (u2);
319   u1 += skip_proto (u1);
320   u2 += skip_proto (u2);
321
322   /* Skip username ans password, if present.  */
323   u1 += skip_uname (u1);
324   u2 += skip_uname (u2);
325
326   for (s = u1; *u1 && *u1 != '/' && *u1 != ':'; u1++);
327   p1 = strdupdelim (s, u1);
328   for (s = u2; *u2 && *u2 != '/' && *u2 != ':'; u2++);
329   p2 = strdupdelim (s, u2);
330   DEBUGP (("Comparing hosts %s and %s...\n", p1, p2));
331   if (strcasecmp (p1, p2) == 0)
332     {
333       free (p1);
334       free (p2);
335       DEBUGP (("They are quite alike.\n"));
336       return 1;
337     }
338   else if (opt.simple_check)
339     {
340       free (p1);
341       free (p2);
342       DEBUGP (("Since checking is simple, I'd say they are not the same.\n"));
343       return 0;
344     }
345   real1 = realhost (p1);
346   real2 = realhost (p2);
347   free (p1);
348   free (p2);
349   if (strcasecmp (real1, real2) == 0)
350     {
351       DEBUGP (("They are alike, after realhost()->%s.\n", real1));
352       free (real1);
353       free (real2);
354       return 1;
355     }
356   else
357     {
358       DEBUGP (("They are not the same (%s, %s).\n", real1, real2));
359       free (real1);
360       free (real2);
361       return 0;
362     }
363 }
364
365 /* Determine whether a URL is acceptable to be followed, according to
366    a list of domains to accept.  */
367 int
368 accept_domain (struct urlinfo *u)
369 {
370   assert (u->host != NULL);
371   if (opt.domains)
372     {
373       if (!sufmatch ((const char **)opt.domains, u->host))
374         return 0;
375     }
376   if (opt.exclude_domains)
377     {
378       if (sufmatch ((const char **)opt.exclude_domains, u->host))
379         return 0;
380     }
381   return 1;
382 }
383
384 /* Check whether WHAT is matched in LIST, each element of LIST being a
385    pattern to match WHAT against, using backward matching (see
386    match_backwards() in utils.c).
387
388    If an element of LIST matched, 1 is returned, 0 otherwise.  */
389 int
390 sufmatch (const char **list, const char *what)
391 {
392   int i, j, k, lw;
393
394   lw = strlen (what);
395   for (i = 0; list[i]; i++)
396     {
397       for (j = strlen (list[i]), k = lw; j >= 0 && k >= 0; j--, k--)
398         if (tolower (list[i][j]) != tolower (what[k]))
399           break;
400       /* The domain must be first to reach to beginning.  */
401       if (j == -1)
402         return 1;
403     }
404   return 0;
405 }
406
407 /* Return email address of the form username@FQDN suitable for
408    anonymous FTP passwords.  This process is error-prone, and the
409    escape hatch is the MY_HOST preprocessor constant, which can be
410    used to hard-code either your hostname or FQDN at compile-time.
411
412    If the FQDN cannot be determined, a warning is printed, and the
413    function returns a short `username@' form, accepted by most
414    anonymous servers.
415
416    If not even the username cannot be divined, it means things are
417    seriously fucked up, and Wget exits.  */
418 char *
419 ftp_getaddress (void)
420 {
421   static char *address;
422
423   /* Do the drill only the first time, as it won't change.  */
424   if (!address)
425     {
426       char userid[32];          /* 9 should be enough for Unix, but
427                                    I'd rather be on the safe side.  */
428       char *host, *fqdn;
429
430       if (!pwd_cuserid (userid))
431         {
432           logprintf (LOG_ALWAYS, _("%s: Cannot determine user-id.\n"),
433                      exec_name);
434           exit (1);
435         }
436 #ifdef MY_HOST
437       STRDUP_ALLOCA (host, MY_HOST);
438 #else /* not MY_HOST */
439 #ifdef HAVE_UNAME
440       {
441         struct utsname ubuf;
442         if (uname (&ubuf) < 0)
443           {
444             logprintf (LOG_ALWAYS, _("%s: Warning: uname failed: %s\n"),
445                        exec_name, strerror (errno));
446             fqdn = "";
447             goto giveup;
448           }
449         STRDUP_ALLOCA (host, ubuf.nodename);
450       }
451 #else /* not HAVE_UNAME */
452 #ifdef HAVE_GETHOSTNAME
453       host = alloca (256);
454       if (gethostname (host, 256) < 0)
455         {
456           logprintf (LOG_ALWAYS, _("%s: Warning: gethostname failed\n"),
457                      exec_name);
458           fqdn = "";
459           goto giveup;
460         }
461 #else /* not HAVE_GETHOSTNAME */
462  #error Cannot determine host name.
463 #endif /* not HAVE_GETHOSTNAME */
464 #endif /* not HAVE_UNAME */
465 #endif /* not MY_HOST */
466       /* If the address we got so far contains a period, don't bother
467          anymore.  */
468       if (strchr (host, '.'))
469         fqdn = host;
470       else
471         {
472           /* #### I've seen the following scheme fail on at least one
473              system!  Do we care?  */
474           char *tmpstore;
475           /* According to Richard Stevens, the correct way to find the
476              FQDN is to (1) find the host name, (2) find its IP
477              address using gethostbyname(), and (3) get the FQDN using
478              gethostbyaddr().  So that's what we'll do.  Step one has
479              been done above.  */
480           /* (2) */
481           struct hostent *hp = gethostbyname (host);
482           if (!hp || !hp->h_addr_list)
483             {
484               logprintf (LOG_ALWAYS, _("\
485 %s: Warning: cannot determine local IP address.\n"),
486                          exec_name);
487               fqdn = "";
488               goto giveup;
489             }
490           /* Copy the argument, so the call to gethostbyaddr doesn't
491              clobber it -- just in case.  */
492           tmpstore = (char *)alloca (hp->h_length);
493           memcpy (tmpstore, *hp->h_addr_list, hp->h_length);
494           /* (3) */
495           hp = gethostbyaddr (tmpstore, hp->h_length, hp->h_addrtype);
496           if (!hp || !hp->h_name)
497             {
498               logprintf (LOG_ALWAYS, _("\
499 %s: Warning: cannot reverse-lookup local IP address.\n"),
500                          exec_name);
501               fqdn = "";
502               goto giveup;
503             }
504           if (!strchr (hp->h_name, '.'))
505             {
506 #if 0
507               /* This gets ticked pretty often.  Karl Berry reports
508                  that there can be valid reasons for the local host
509                  name not to be an FQDN, so I've decided to remove the
510                  annoying warning.  */
511               logprintf (LOG_ALWAYS, _("\
512 %s: Warning: reverse-lookup of local address did not yield FQDN!\n"),
513                        exec_name);
514 #endif
515               fqdn = "";
516               goto giveup;
517             }
518           /* Once we're here, hp->h_name contains the correct FQDN.  */
519           STRDUP_ALLOCA (fqdn, hp->h_name);
520         }
521     giveup:
522       address = (char *)xmalloc (strlen (userid) + 1 + strlen (fqdn) + 1);
523       sprintf (address, "%s@%s", userid, fqdn);
524     }
525   return address;
526 }
527
528 /* Print error messages for host errors.  */
529 char *
530 herrmsg (int error)
531 {
532   /* Can't use switch since some constants are equal (at least on my
533      system), and the compiler signals "duplicate case value".  */
534   if (error == HOST_NOT_FOUND
535       || error == NO_RECOVERY
536       || error == NO_DATA
537       || error == NO_ADDRESS
538       || error == TRY_AGAIN)
539     return _("Host not found");
540   else
541     return _("Unknown error");
542 }
543
544 /* Clean the host list.  This is a separate function, so we needn't
545    export HLIST and its implementation.  Ha!  */
546 void
547 clean_hosts (void)
548 {
549   struct host *l = hlist;
550
551   while (l)
552     {
553       struct host *p = l->next;
554       free (l->hostname);
555       free (l->realname);
556       free (l);
557       l = p;
558     }
559   hlist = NULL;
560 }