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