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