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