Commit | Line | Data |
---|---|---|
8c0f18d2 | 1 | /* |
dc45ba8c | 2 | * Copyright (c) 1986 Eric P. Allman |
1acb1197 KB |
3 | * Copyright (c) 1988 Regents of the University of California. |
4 | * All rights reserved. | |
5 | * | |
6 | * Redistribution and use in source and binary forms are permitted | |
dc45ba8c KB |
7 | * provided that the above copyright notice and this paragraph are |
8 | * duplicated in all such forms and that any documentation, | |
9 | * advertising materials, and other materials related to such | |
10 | * distribution and use acknowledge that the software was developed | |
11 | * by the University of California, Berkeley. The name of the | |
12 | * University may not be used to endorse or promote products derived | |
13 | * from this software without specific prior written permission. | |
14 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | |
15 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | |
16 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
1acb1197 | 17 | */ |
8c0f18d2 | 18 | |
a29056d8 EA |
19 | #include <sendmail.h> |
20 | ||
8c0f18d2 | 21 | #ifndef lint |
a29056d8 | 22 | #ifdef NAMED_BIND |
e3419641 | 23 | static char sccsid[] = "@(#)domain.c 5.19 (Berkeley) 1/1/89 (with name server)"; |
a29056d8 | 24 | #else |
e3419641 | 25 | static char sccsid[] = "@(#)domain.c 5.19 (Berkeley) 1/1/89 (without name server)"; |
a29056d8 | 26 | #endif |
1acb1197 KB |
27 | #endif /* not lint */ |
28 | ||
a29056d8 EA |
29 | #ifdef NAMED_BIND |
30 | ||
bece62ab | 31 | #include <sys/param.h> |
a29056d8 | 32 | #include <errno.h> |
bece62ab KB |
33 | #include <arpa/nameser.h> |
34 | #include <resolv.h> | |
35 | #include <netdb.h> | |
8c0f18d2 JB |
36 | |
37 | typedef union { | |
38 | HEADER qb1; | |
39 | char qb2[PACKETSZ]; | |
40 | } querybuf; | |
41 | ||
bece62ab | 42 | static char hostbuf[MAXMXHOSTS*PACKETSZ]; |
8c0f18d2 | 43 | |
bece62ab KB |
44 | getmxrr(host, mxhosts, localhost, rcode) |
45 | char *host, **mxhosts, *localhost; | |
46 | int *rcode; | |
8c0f18d2 | 47 | { |
bece62ab KB |
48 | extern int h_errno; |
49 | register u_char *eom, *cp; | |
50 | register int i, j, n, nmx; | |
51 | register char *bp; | |
8c0f18d2 | 52 | HEADER *hp; |
bece62ab KB |
53 | querybuf answer; |
54 | int ancount, qdcount, buflen, seenlocal; | |
55 | u_short pref, localpref, type, prefer[MAXMXHOSTS]; | |
8c0f18d2 | 56 | |
19c9e482 | 57 | errno = 0; |
bece62ab | 58 | n = res_search(host, C_IN, T_MX, (char *)&answer, sizeof(answer)); |
a29056d8 EA |
59 | if (n < 0) |
60 | { | |
bece62ab KB |
61 | if (tTd(8, 1)) |
62 | printf("getmxrr: res_search failed (errno=%d, h_errno=%d)\n", | |
63 | errno, h_errno); | |
a29056d8 EA |
64 | switch (h_errno) |
65 | { | |
66 | case NO_DATA: | |
67 | case NO_RECOVERY: | |
68 | /* no MX data on this host */ | |
bece62ab | 69 | goto punt; |
a29056d8 EA |
70 | |
71 | case HOST_NOT_FOUND: | |
72 | /* the host just doesn't exist */ | |
bece62ab KB |
73 | *rcode = EX_NOHOST; |
74 | break; | |
a29056d8 EA |
75 | |
76 | case TRY_AGAIN: | |
77 | /* couldn't connect to the name server */ | |
78 | if (!UseNameServer && errno == ECONNREFUSED) | |
79 | goto punt; | |
80 | ||
81 | /* it might come up later; better queue it up */ | |
bece62ab KB |
82 | *rcode = EX_TEMPFAIL; |
83 | break; | |
8c0f18d2 | 84 | } |
a29056d8 EA |
85 | |
86 | /* irreconcilable differences */ | |
87 | return (-1); | |
8c0f18d2 | 88 | } |
bece62ab KB |
89 | |
90 | /* find first satisfactory answer */ | |
91 | hp = (HEADER *)&answer; | |
92 | cp = (u_char *)&answer + sizeof(HEADER); | |
93 | eom = (u_char *)&answer + n; | |
94 | for (qdcount = ntohs(hp->qdcount); qdcount--; cp += n + QFIXEDSZ) | |
95 | if ((n = dn_skipname(cp, eom)) < 0) | |
96 | goto punt; | |
8c0f18d2 | 97 | nmx = 0; |
3fff2c44 | 98 | seenlocal = 0; |
8c0f18d2 | 99 | buflen = sizeof(hostbuf); |
bece62ab KB |
100 | bp = hostbuf; |
101 | ancount = ntohs(hp->ancount); | |
102 | while (--ancount >= 0 && cp < eom && nmx < MAXMXHOSTS) { | |
8c0f18d2 JB |
103 | if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0) |
104 | break; | |
105 | cp += n; | |
bece62ab | 106 | GETSHORT(type, cp); |
8c0f18d2 | 107 | cp += sizeof(u_short) + sizeof(u_long); |
bece62ab | 108 | GETSHORT(n, cp); |
8c0f18d2 | 109 | if (type != T_MX) { |
8c0f18d2 JB |
110 | if (tTd(8, 1) || _res.options & RES_DEBUG) |
111 | printf("unexpected answer type %d, size %d\n", | |
bece62ab | 112 | type, n); |
8c0f18d2 JB |
113 | cp += n; |
114 | continue; | |
115 | } | |
bece62ab | 116 | GETSHORT(pref, cp); |
8c0f18d2 JB |
117 | if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0) |
118 | break; | |
3fff2c44 | 119 | cp += n; |
bece62ab KB |
120 | if (!strcasecmp(bp, localhost)) { |
121 | if (seenlocal == 0 || pref < localpref) | |
122 | localpref = pref; | |
3fff2c44 | 123 | seenlocal = 1; |
3fff2c44 JB |
124 | continue; |
125 | } | |
8c0f18d2 JB |
126 | prefer[nmx] = pref; |
127 | mxhosts[nmx++] = bp; | |
bece62ab KB |
128 | n = strlen(bp) + 1; |
129 | bp += n; | |
130 | buflen -= n; | |
8c0f18d2 | 131 | } |
3fff2c44 | 132 | if (nmx == 0) { |
bece62ab | 133 | punt: mxhosts[0] = strcpy(hostbuf, host); |
3fff2c44 JB |
134 | return(1); |
135 | } | |
bece62ab | 136 | |
8c0f18d2 JB |
137 | /* sort the records */ |
138 | for (i = 0; i < nmx; i++) { | |
139 | for (j = i + 1; j < nmx; j++) { | |
19c9e482 KB |
140 | if (prefer[i] > prefer[j] || |
141 | (prefer[i] == prefer[j] && rand() % 1 == 0)) { | |
bece62ab KB |
142 | register int temp; |
143 | register char *temp1; | |
8c0f18d2 JB |
144 | |
145 | temp = prefer[i]; | |
146 | prefer[i] = prefer[j]; | |
147 | prefer[j] = temp; | |
148 | temp1 = mxhosts[i]; | |
149 | mxhosts[i] = mxhosts[j]; | |
150 | mxhosts[j] = temp1; | |
151 | } | |
152 | } | |
bece62ab | 153 | if (seenlocal && prefer[i] >= localpref) { |
3fff2c44 | 154 | /* |
bece62ab KB |
155 | * truncate higher pref part of list; if we're |
156 | * the best choice left, we should have realized | |
157 | * awhile ago that this was a local delivery. | |
3fff2c44 | 158 | */ |
bece62ab KB |
159 | if (i == 0) { |
160 | *rcode = EX_CONFIG; | |
161 | return(-1); | |
3fff2c44 | 162 | } |
bece62ab | 163 | nmx = i; |
3fff2c44 JB |
164 | break; |
165 | } | |
8c0f18d2 JB |
166 | } |
167 | return(nmx); | |
168 | } | |
b22f87a1 | 169 | |
b22f87a1 JB |
170 | getcanonname(host, hbsize) |
171 | char *host; | |
172 | int hbsize; | |
173 | { | |
bece62ab KB |
174 | register u_char *eom, *cp; |
175 | register int n; | |
b22f87a1 | 176 | HEADER *hp; |
bece62ab | 177 | querybuf answer; |
b22f87a1 | 178 | u_short type; |
bece62ab KB |
179 | int first, ancount, qdcount, loopcnt; |
180 | char nbuf[PACKETSZ]; | |
b22f87a1 | 181 | |
bece62ab KB |
182 | loopcnt = 0; |
183 | loop: | |
19c9e482 KB |
184 | /* |
185 | * Use query type of ANY if possible (NO_WILDCARD_MX), which will | |
186 | * find types CNAME, A, and MX, and will cause all existing records | |
187 | * to be cached by our local server. If there is (might be) a | |
188 | * wildcard MX record in the local domain or its parents that are | |
189 | * searched, we can't use ANY; it would cause fully-qualified names | |
190 | * to match as names in a local domain. | |
191 | */ | |
192 | # ifdef NO_WILDCARD_MX | |
193 | n = res_search(host, C_IN, T_ANY, (char *)&answer, sizeof(answer)); | |
194 | # else | |
6cb3bde1 | 195 | n = res_search(host, C_IN, T_CNAME, (char *)&answer, sizeof(answer)); |
19c9e482 | 196 | # endif |
b22f87a1 | 197 | if (n < 0) { |
bece62ab KB |
198 | if (tTd(8, 1)) |
199 | printf("getcanonname: res_search failed (errno=%d, h_errno=%d)\n", | |
200 | errno, h_errno); | |
b22f87a1 JB |
201 | return; |
202 | } | |
bece62ab KB |
203 | |
204 | /* find first satisfactory answer */ | |
205 | hp = (HEADER *)&answer; | |
b22f87a1 | 206 | ancount = ntohs(hp->ancount); |
bece62ab KB |
207 | |
208 | /* we don't care about errors here, only if we got an answer */ | |
b22f87a1 | 209 | if (ancount == 0) { |
bece62ab | 210 | if (tTd(8, 1)) |
b22f87a1 | 211 | printf("rcode = %d, ancount=%d\n", hp->rcode, ancount); |
b22f87a1 JB |
212 | return; |
213 | } | |
bece62ab KB |
214 | cp = (u_char *)&answer + sizeof(HEADER); |
215 | eom = (u_char *)&answer + n; | |
216 | for (qdcount = ntohs(hp->qdcount); qdcount--; cp += n + QFIXEDSZ) | |
217 | if ((n = dn_skipname(cp, eom)) < 0) | |
218 | return; | |
219 | ||
220 | /* | |
221 | * just in case someone puts a CNAME record after another record, | |
222 | * check all records for CNAME; otherwise, just take the first | |
223 | * name found. | |
224 | */ | |
225 | for (first = 1; --ancount >= 0 && cp < eom; cp += n) { | |
b22f87a1 JB |
226 | if ((n = dn_expand((char *)&answer, eom, cp, nbuf, |
227 | sizeof(nbuf))) < 0) | |
228 | break; | |
bece62ab | 229 | if (first) { /* XXX */ |
b22f87a1 JB |
230 | (void)strncpy(host, nbuf, hbsize); |
231 | host[hbsize - 1] = '\0'; | |
232 | first = 0; | |
233 | } | |
234 | cp += n; | |
bece62ab | 235 | GETSHORT(type, cp); |
b22f87a1 | 236 | cp += sizeof(u_short) + sizeof(u_long); |
bece62ab | 237 | GETSHORT(n, cp); |
b22f87a1 JB |
238 | if (type == T_CNAME) { |
239 | /* | |
bece62ab KB |
240 | * assume that only one cname will be found. More |
241 | * than one is undefined. Copy so that if dn_expand | |
242 | * fails, `host' is still okay. | |
b22f87a1 JB |
243 | */ |
244 | if ((n = dn_expand((char *)&answer, eom, cp, nbuf, | |
245 | sizeof(nbuf))) < 0) | |
246 | break; | |
bece62ab | 247 | (void)strncpy(host, nbuf, hbsize); /* XXX */ |
b22f87a1 | 248 | host[hbsize - 1] = '\0'; |
bece62ab KB |
249 | if (++loopcnt > 8) /* never be more than 1 */ |
250 | return; | |
251 | goto loop; | |
b22f87a1 | 252 | } |
b22f87a1 | 253 | } |
b22f87a1 | 254 | } |
a29056d8 | 255 | |
e3419641 C |
256 | #else /* not NAMED_BIND */ |
257 | ||
258 | #include <netdb.h> | |
259 | ||
260 | getcanonname(host, hbsize) | |
261 | char *host; | |
262 | int hbsize; | |
263 | { | |
264 | struct hostent *hp; | |
265 | ||
266 | hp = gethostbyname(host); | |
267 | if (hp == NULL) | |
268 | return; | |
269 | ||
270 | if (strlen(hp->h_name) >= hbsize) | |
271 | return; | |
272 | ||
273 | (void) strcpy(host, hp->h_name); | |
274 | } | |
275 | ||
276 | #endif /* not NAMED_BIND */ |