]> Pileus Git - ~andy/fetchmail/blob - checkalias.c
64-bit cleanness.
[~andy/fetchmail] / checkalias.c
1 /*
2  * checkalias.c -- check to see if two hostnames or IP addresses are equivalent
3  *
4  * Copyright 1997 by Eric S. Raymond
5  * For license terms, see the file COPYING in this directory.
6  */
7 #include "config.h"
8 #ifdef HAVE_GETHOSTBYNAME
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <sys/types.h>
13 #include <sys/socket.h>
14 #include <netinet/in.h>
15 #include <arpa/inet.h>
16 #include <netdb.h>
17 #include "mx.h"
18 #include "fetchmail.h"
19
20 #define MX_RETRIES      3
21
22 static int is_ip_alias(const char *name1,const char *name2)
23 /*
24  * Given two hostnames as arguments, returns TRUE if they
25  * have at least one IP address in common.
26  * No check is done on errors returned by gethostbyname,
27  * the calling function does them.
28  */
29 {
30     typedef unsigned char address_t[sizeof (struct in_addr)]; 
31     typedef struct _address_e
32     {
33         struct _address_e *next;
34         address_t address;
35     } 
36     address_e;
37     address_e *host_a_addr=0, *host_b_addr=0;   /* assignments pacify -Wall */
38     address_e *dummy_addr;
39
40     int i;
41     struct hostent *hp;
42     char **p;
43  
44     hp = gethostbyname(name1);
45  
46     dummy_addr = (address_e *)NULL;
47
48     for (i=0,p = hp->h_addr_list; *p != 0; i++,p++)
49     {
50         struct in_addr in;
51         (void) memcpy(&in.s_addr, *p, sizeof (in.s_addr));
52         xalloca(host_a_addr, address_e *, sizeof (address_e));
53         memset (host_a_addr,0, sizeof (address_e));
54         host_a_addr->next = dummy_addr;
55         (void) memcpy(&host_a_addr->address, *p, sizeof (in.s_addr));
56         dummy_addr = host_a_addr;
57     }
58
59     hp = gethostbyname(name2);
60
61     dummy_addr = (address_e *)NULL;
62     for (i=0,p = hp->h_addr_list; *p != 0; i++,p++)
63     {
64         struct in_addr in;
65         (void) memcpy(&in.s_addr, *p, sizeof (in.s_addr));
66         xalloca(host_b_addr, address_e *, sizeof (address_e));
67         memset (host_b_addr,0, sizeof (address_e));
68         host_b_addr->next = dummy_addr;
69         (void) memcpy(&host_b_addr->address, *p, sizeof (in.s_addr));
70         dummy_addr = host_b_addr;
71     }
72
73     while (host_a_addr)
74     {
75         while (host_b_addr)
76         {
77             if (!memcmp(host_b_addr->address,host_a_addr->address, sizeof (address_t)))
78                 return (TRUE);
79
80             host_b_addr = host_b_addr->next;
81         }
82         host_a_addr = host_a_addr->next;
83     }
84     return (FALSE);
85 }
86
87 int is_host_alias(const char *name, struct query *ctl)
88 /* determine whether name is a DNS alias of the mailserver for this query */
89 {
90     struct hostent      *he,*he_st;
91     struct mxentry      *mxp, *mxrecords;
92
93     struct hostdata *lead_server = 
94         ctl->server.lead_server ? ctl->server.lead_server : &ctl->server;
95
96     /*
97      * The first two checks are optimizations that will catch a good
98      * many cases.
99      *
100      * (1) check against the `true name' deduced from the poll label
101      * and the via option (if present) at the beginning of the poll cycle.  
102      * Odds are good this will either be the mailserver's FQDN or a suffix of
103      * it with the mailserver's domain's default host name omitted.
104      *
105      * (2) Then check the rest of the `also known as'
106      * cache accumulated by previous DNS checks.  This cache is primed
107      * by the aka list option.
108      *
109      * Any of these on a mail address is definitive.  Only if the
110      * name doesn't match any is it time to call the bind library.
111      * If this happens odds are good we're looking at an MX name.
112      */
113     if (strcasecmp(lead_server->truename, name) == 0)
114         return(TRUE);
115     else if (str_in_list(&lead_server->akalist, name, TRUE))
116         return(TRUE);
117     else if (!ctl->server.dns)
118         return(FALSE);
119
120 #ifndef HAVE_RES_SEARCH
121     return(FALSE);
122 #else
123     /*
124      * The only code that calls the BIND library is here and in the
125      * start-of-run probe with gethostbyname(3) under ETRN/Kerberos.
126      *
127      * We know DNS service was up at the beginning of the run.
128      * If it's down, our nameserver has crashed.  We don't want to try
129      * delivering the current message or anything else from the
130      * current server until it's back up.
131      */
132     else if ((he = gethostbyname(name)) != (struct hostent *)NULL)
133     {
134         if (strcasecmp(ctl->server.truename, he->h_name) == 0)
135             goto match;
136         else if (((he_st = gethostbyname(ctl->server.truename)) != (struct hostent *)NULL) && ctl->server.checkalias)
137         {
138             if (outlevel >= O_DEBUG)
139                 error(0, 0, "Checking if %s is really the same node as %s",ctl->server.truename,name);
140             if (is_ip_alias(ctl->server.truename,name) == TRUE)
141             {
142                 if (outlevel >= O_DEBUG)
143                     error(0, 0, "Yes, their IP addresses match");
144                 goto match;
145             }
146             if (outlevel >= O_DEBUG)
147                 error(0, 0, "No, their IP addresses don't match");
148         }
149         else
150             return(FALSE);
151     }
152     else
153         switch (h_errno)
154         {
155         case HOST_NOT_FOUND:    /* specified host is unknown */
156         case NO_ADDRESS:        /* valid, but does not have an IP address */
157             break;
158
159         case NO_RECOVERY:       /* non-recoverable name server error */
160         case TRY_AGAIN:         /* temporary error on authoritative server */
161         default:
162             if (outlevel != O_SILENT)
163                 putchar('\n');  /* terminate the progress message */
164             error(0, 0,
165                 "nameserver failure while looking for `%s' during poll of %s.",
166                 name, ctl->server.pollname);
167             ctl->errcount++;
168             break;
169         }
170
171     /*
172      * We're only here if DNS was OK but the gethostbyname() failed
173      * with a HOST_NOT_FOUND or NO_ADDRESS error.
174      * Search for a name match on MX records pointing to the server.
175      */
176     h_errno = 0;
177     if ((mxrecords = getmxrecords(name)) == (struct mxentry *)NULL)
178     {
179         switch (h_errno)
180         {
181         case HOST_NOT_FOUND:    /* specified host is unknown */
182         case NO_ADDRESS:        /* valid, but does not have an IP address */
183             return(FALSE);
184             break;
185
186         case NO_RECOVERY:       /* non-recoverable name server error */
187         case TRY_AGAIN:         /* temporary error on authoritative server */
188         default:
189             error(0, -1,
190                 "nameserver failure while looking for `%s' during poll of %s.",
191                 name, ctl->server.pollname);
192             ctl->errcount++;
193             break;
194         }
195     }
196     else
197     {
198         for (mxp = mxrecords; mxp->name; mxp++)
199             if (strcasecmp(ctl->server.truename, mxp->name) == 0)
200                 goto match;
201         return(FALSE);
202     match:;
203     }
204
205     /* add this name to relevant server's `also known as' list */
206     save_str(&lead_server->akalist, name, 0);
207     return(TRUE);
208 #endif /* HAVE_RES_SEARCH */
209 }
210 #endif /* HAVE_GETHOSTBYNAME */
211
212 /* checkalias.c ends here */