xref: /csrg-svn/usr.sbin/sendmail/src/domain.c (revision 29432)
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 lint
12 static char	SccsId[] = "@(#)domain.c	5.1 (Berkeley) 07/01/86";
13 #endif not lint
14 
15 # include <sys/param.h>
16 # include <netinet/in.h>
17 # include <arpa/nameser.h>
18 # include <resolv.h>
19 # include <stdio.h>
20 # include <netdb.h>
21 
22 typedef union {
23 	HEADER qb1;
24 	char qb2[PACKETSZ];
25 } querybuf;
26 
27 static char hostbuf[BUFSIZ];
28 
29 int h_errno;
30 
31 getmxrr(host, mxhosts, maxmx)
32 	char *host, **mxhosts;
33 	int maxmx;
34 {
35 
36 	HEADER *hp;
37 	char *eom, *bp, *cp;
38 	querybuf buf, answer;
39 	int n, n1, i, j, nmx, ancount, qdcount, buflen;
40 	u_short prefer[BUFSIZ];
41 	u_short pref, type, class;
42 
43 	n = res_mkquery(QUERY, host, C_IN, T_MX, (char *)NULL, 0, NULL,
44 		(char *)&buf, sizeof(buf));
45 	if (n < 0) {
46 #ifdef DEBUG
47 		if (tTd(8, 1) || _res.options & RES_DEBUG)
48 			printf("res_mkquery failed\n");
49 #endif
50 		return(-1);
51 	}
52 	n = res_send((char *)&buf, n, (char *)&answer, sizeof(answer));
53 	if (n < 0) {
54 #ifdef DEBUG
55 		if (tTd(8, 1) || _res.options & RES_DEBUG)
56 			printf("res_send failed\n");
57 #endif
58 		h_errno = TRY_AGAIN;
59 		return (-1);
60 	}
61 	eom = (char *)&answer + n;
62 	/*
63 	 * find first satisfactory answer
64 	 */
65 	hp = (HEADER *) &answer;
66 	ancount = ntohs(hp->ancount);
67 	qdcount = ntohs(hp->qdcount);
68 	if (hp->rcode != NOERROR || ancount == 0) {
69 #ifdef DEBUG
70 		if (tTd(8, 1) || _res.options & RES_DEBUG)
71 			printf("rcode = %d, ancount=%d\n", hp->rcode, ancount);
72 #endif
73 		switch (hp->rcode) {
74 			case NXDOMAIN:
75 				/* Check if it's an authoritive answer */
76 				if (hp->aa)
77 					h_errno = HOST_NOT_FOUND;
78 				else
79 					h_errno = TRY_AGAIN;
80 				break;
81 			case SERVFAIL:
82 				h_errno = TRY_AGAIN;
83 				break;
84 			case NOERROR:
85 				h_errno = NO_ADDRESS;
86 				break;
87 			case FORMERR:
88 			case NOTIMP:
89 			case REFUSED:
90 				h_errno = NO_RECOVERY;
91 		}
92 		return (-1);
93 	}
94 	bp = hostbuf;
95 	nmx = 0;
96 	buflen = sizeof(hostbuf);
97 	cp = (char *)&answer + sizeof(HEADER);
98 	if (qdcount) {
99 		cp += dn_skip(cp) + QFIXEDSZ;
100 		while (--qdcount > 0)
101 			cp += dn_skip(cp) + QFIXEDSZ;
102 	}
103 	while (--ancount >= 0 && cp < eom && nmx < maxmx) {
104 		if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0)
105 			break;
106 		cp += n;
107 		type = getshort(cp);
108  		cp += sizeof(u_short);
109 		class = getshort(cp);
110  		cp += sizeof(u_short) + sizeof(u_long);
111 		n = getshort(cp);
112 		cp += sizeof(u_short);
113 		if (type != T_MX)  {
114 #ifdef DEBUG
115 			if (tTd(8, 1) || _res.options & RES_DEBUG)
116 				printf("unexpected answer type %d, size %d\n",
117 					type, n);
118 #endif
119 			cp += n;
120 			continue;
121 		}
122 		pref = getshort(cp);
123 		cp += sizeof(u_short);
124 		if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0)
125 			break;
126 		prefer[nmx] = pref;
127 		mxhosts[nmx++] = bp;
128 		n1 = strlen(bp)+1;
129 		bp += n1;
130 		buflen -= n1;
131 		cp += n;
132 	}
133 	if (nmx == 0)
134 		return(-1);
135 	/* sort the records */
136 	for (i = 0; i < nmx; i++) {
137 		for (j = i + 1; j < nmx; j++) {
138 			if (prefer[i] > prefer[j]) {
139 				int temp;
140 				char *temp1;
141 
142 				temp = prefer[i];
143 				prefer[i] = prefer[j];
144 				prefer[j] = temp;
145 				temp1 = mxhosts[i];
146 				mxhosts[i] = mxhosts[j];
147 				mxhosts[j] = temp1;
148 			}
149 		}
150 	}
151 	return(nmx);
152 }
153