xref: /csrg-svn/usr.sbin/sendmail/src/domain.c (revision 29551)
1 /*
2 **  Sendmail
3 **  Copyright (c) 1986  Eric P. Allman
4 **  Berkeley, California
5 **
6 **  Copyright (c) 1986 Regents of the University of California.
7 **  All rights reserved.  The Berkeley software License Agreement
8 **  specifies the terms and conditions for redistribution.
9 */
10 
11 #ifndef MXDOMAIN
12 #ifndef lint
13 static char	SccsId[] = "@(#)domain.c	5.2 (Berkeley) 07/10/86 (no MXDOMAIN)";
14 #endif not lint
15 #else MXDOMAIN
16 
17 #ifndef lint
18 static char	SccsId[] = "@(#)domain.c	5.2 (Berkeley) 07/10/86";
19 #endif not lint
20 
21 # include <sys/param.h>
22 # include "sendmail.h"
23 # include <arpa/nameser.h>
24 # include <resolv.h>
25 # include <netdb.h>
26 
27 typedef union {
28 	HEADER qb1;
29 	char qb2[PACKETSZ];
30 } querybuf;
31 
32 static char hostbuf[BUFSIZ];
33 
34 int h_errno;
35 
36 getmxrr(host, mxhosts, maxmx, localhost)
37 	char *host, **mxhosts;
38 	int maxmx;
39 	char *localhost;
40 {
41 
42 	HEADER *hp;
43 	char *eom, *bp, *cp;
44 	querybuf buf, answer;
45 	int n, n1, i, j, nmx, ancount, qdcount, buflen;
46 	int seenlocal;
47 	u_short prefer[BUFSIZ];
48 	u_short pref, localpref, type, class;
49 
50 	n = res_mkquery(QUERY, host, C_IN, T_MX, (char *)NULL, 0, NULL,
51 		(char *)&buf, sizeof(buf));
52 	if (n < 0) {
53 #ifdef DEBUG
54 		if (tTd(8, 1) || _res.options & RES_DEBUG)
55 			printf("res_mkquery failed\n");
56 #endif
57 		h_errno = NO_RECOVERY;
58 		return(-2);
59 	}
60 	n = res_send((char *)&buf, n, (char *)&answer, sizeof(answer));
61 	if (n < 0) {
62 #ifdef DEBUG
63 		if (tTd(8, 1) || _res.options & RES_DEBUG)
64 			printf("res_send failed\n");
65 #endif
66 		h_errno = TRY_AGAIN;
67 		return (-1);
68 	}
69 	eom = (char *)&answer + n;
70 	/*
71 	 * find first satisfactory answer
72 	 */
73 	hp = (HEADER *) &answer;
74 	ancount = ntohs(hp->ancount);
75 	qdcount = ntohs(hp->qdcount);
76 	if (hp->rcode != NOERROR || ancount == 0) {
77 #ifdef DEBUG
78 		if (tTd(8, 1) || _res.options & RES_DEBUG)
79 			printf("rcode = %d, ancount=%d\n", hp->rcode, ancount);
80 #endif
81 		switch (hp->rcode) {
82 			case NXDOMAIN:
83 				/* Check if it's an authoritive answer */
84 				if (hp->aa) {
85 					h_errno = HOST_NOT_FOUND;
86 					return(-3);
87 				} else {
88 					h_errno = TRY_AGAIN;
89 					return(-1);
90 				}
91 			case SERVFAIL:
92 				h_errno = TRY_AGAIN;
93 				return(-1);
94 			case NOERROR:
95 				(void) strcpy(hostbuf, host);
96 				mxhosts[0] = hostbuf;
97 				return(1);
98 			case FORMERR:
99 			case NOTIMP:
100 			case REFUSED:
101 				h_errno = NO_RECOVERY;
102 				return(-2);
103 		}
104 		return (-1);
105 	}
106 	bp = hostbuf;
107 	nmx = 0;
108 	seenlocal = 0;
109 	buflen = sizeof(hostbuf);
110 	cp = (char *)&answer + sizeof(HEADER);
111 	if (qdcount) {
112 		cp += dn_skip(cp) + QFIXEDSZ;
113 		while (--qdcount > 0)
114 			cp += dn_skip(cp) + QFIXEDSZ;
115 	}
116 	while (--ancount >= 0 && cp < eom && nmx < maxmx) {
117 		if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0)
118 			break;
119 		cp += n;
120 		type = getshort(cp);
121  		cp += sizeof(u_short);
122 		/*
123 		class = getshort(cp);
124 		*/
125  		cp += sizeof(u_short) + sizeof(u_long);
126 		n = getshort(cp);
127 		cp += sizeof(u_short);
128 		if (type != T_MX)  {
129 #ifdef DEBUG
130 			if (tTd(8, 1) || _res.options & RES_DEBUG)
131 				printf("unexpected answer type %d, size %d\n",
132 					type, n);
133 #endif
134 			cp += n;
135 			continue;
136 		}
137 		pref = getshort(cp);
138 		cp += sizeof(u_short);
139 		if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0)
140 			break;
141 		cp += n;
142 		if (sameword(bp, localhost))
143 		{
144 			seenlocal = 1;
145 			localpref = pref;
146 			continue;
147 		}
148 		prefer[nmx] = pref;
149 		mxhosts[nmx++] = bp;
150 		n1 = strlen(bp)+1;
151 		bp += n1;
152 		buflen -= n1;
153 	}
154 	if (nmx == 0) {
155 		(void) strcpy(hostbuf, host);
156 		mxhosts[0] = hostbuf;
157 		return(1);
158 	}
159 	/* sort the records */
160 	for (i = 0; i < nmx; i++) {
161 		for (j = i + 1; j < nmx; j++) {
162 			if (prefer[i] > prefer[j]) {
163 				int temp;
164 				char *temp1;
165 
166 				temp = prefer[i];
167 				prefer[i] = prefer[j];
168 				prefer[j] = temp;
169 				temp1 = mxhosts[i];
170 				mxhosts[i] = mxhosts[j];
171 				mxhosts[j] = temp1;
172 			}
173 		}
174 		if (seenlocal && (prefer[i] >= localpref))
175 		{
176 			nmx = i;
177 			/*
178 			 * We are the first MX, might as well try delivering
179 			 * since nobody is supposed to have more info.
180 			 */
181 			if (nmx == 0)
182 			{
183 				(void) strcpy(hostbuf, host);
184 				mxhosts[0] = hostbuf;
185 				return(1);
186 			}
187 			break;
188 		}
189 	}
190 	return(nmx);
191 }
192 #endif MXDOMAIN
193