1 /*
2 * Copyright (c) 1983 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 #ifndef lint
22 static char Version[] = "@(#)mxrr.c e07@nikhef.nl (Eric Wassenaar) 990522";
23 #endif
24
25 #include "vrfy.h"
26
27 extern int verbose;
28 extern int debug;
29
30 #if PACKETSZ > 8192
31 #define MAXPACKET PACKETSZ /* PACKETSZ should be the max udp size (512) */
32 #else
33 #define MAXPACKET 8192 /* but tcp packets can be considerably larger */
34 #endif
35
36 typedef union {
37 HEADER hdr;
38 u_char buf[MAXPACKET];
39 } querybuf;
40
41 #ifndef HFIXEDSZ
42 #define HFIXEDSZ 12 /* actually sizeof(HEADER) */
43 #endif
44
45 #define MAXMXBUFSIZ (MAXMXHOSTS * (MAXHOST+1))
46
47 static char hostbuf[MAXMXBUFSIZ];
48
49 char *MxHosts[MAXMXHOSTS]; /* list of names of mx hosts found */
50
51 char *dbprefix = DBPREFIX; /* prefix for debug messages to stdout */
52
53 /*
54 ** GETMXBYNAME -- Fetch mx hosts for a domain
55 ** ------------------------------------------
56 **
57 ** Returns:
58 ** Number of mx hosts found.
59 **
60 ** Outputs:
61 ** The global array MxHosts contains the mx names.
62 */
63
64 int
getmxbyname(domain)65 getmxbyname(domain)
66 char *domain; /* domain to get mx hosts for */
67 {
68 querybuf answer; /* answer buffer from nameserver */
69 HEADER *hp; /* answer buffer header */
70 int ancount, qdcount; /* answer count and query count */
71 u_char *msg, *eom, *cp; /* answer buffer positions */
72 int type, class, dlen; /* record type, class and length */
73 u_short pref; /* mx preference value */
74 u_short prefer[MAXMXHOSTS]; /* saved preferences of mx records */
75 char *bp; /* hostbuf pointer */
76 int nmx; /* number of mx hosts found */
77 register int i;
78 register int j;
79 register int n;
80
81 /*
82 * Query the nameserver to retrieve mx records for the given domain.
83 */
84 errno = 0; /* reset before querying nameserver */
85 h_errno = 0;
86
87 n = res_search(domain, C_IN, T_MX, (u_char *)&answer, sizeof(answer));
88 if (n < 0)
89 {
90 if (_res.options & RES_DEBUG)
91 printf("%sres_search failed\n", dbprefix);
92 return(0);
93 }
94
95 errno = 0; /* reset after we got an answer */
96
97 if (n < HFIXEDSZ)
98 {
99 h_errno = NO_RECOVERY;
100 return(0);
101 }
102
103 /* avoid problems after truncation in tcp packets */
104 if (n > sizeof(answer))
105 n = sizeof(answer);
106
107 /*
108 * Valid answer received. Skip the query record.
109 */
110 hp = (HEADER *)&answer;
111 qdcount = ntohs((u_short)hp->qdcount);
112 ancount = ntohs((u_short)hp->ancount);
113
114 msg = (u_char *)&answer;
115 eom = (u_char *)&answer + n;
116 cp = (u_char *)&answer + HFIXEDSZ;
117
118 while (qdcount-- > 0 && cp < eom)
119 {
120 n = dn_skipname(cp, eom);
121 if (n < 0)
122 return(0);
123 cp += n;
124 cp += QFIXEDSZ;
125 }
126
127 /*
128 * Loop through the answer buffer and extract mx records.
129 */
130 nmx = 0;
131 bp = hostbuf;
132
133 while (ancount-- > 0 && cp < eom && nmx < MAXMXHOSTS)
134 {
135 #ifdef obsolete
136 if (verbose >= 4 || debug)
137 (void) p_rr((qbuf_t *)cp, (qbuf_t *)msg, stdout);
138 #endif /*obsolete*/
139
140 n = dn_expand(msg, eom, cp, (nbuf_t *)bp, MAXHOST);
141 if (n < 0)
142 break;
143 cp += n;
144
145 type = _getshort(cp);
146 cp += INT16SZ;
147
148 class = _getshort(cp);
149 cp += INT16SZ;
150
151 /* ttl = _getlong(cp); */
152 cp += INT32SZ;
153
154 dlen = _getshort(cp);
155 cp += INT16SZ;
156
157 if (type != T_MX || class != C_IN)
158 {
159 cp += dlen;
160 continue;
161 }
162
163 pref = _getshort(cp);
164 cp += INT16SZ;
165
166 n = dn_expand(msg, eom, cp, (nbuf_t *)bp, MAXHOST);
167 if (n < 0)
168 break;
169 cp += n;
170
171 prefer[nmx] = pref;
172 MxHosts[nmx] = bp;
173 nmx++;
174
175 n = strlength(bp) + 1;
176 bp += n;
177 }
178
179 /*
180 * Sort all records by preference.
181 */
182 for (i = 0; i < nmx; i++)
183 {
184 for (j = i + 1; j < nmx; j++)
185 {
186 if (prefer[i] > prefer[j])
187 {
188 register u_short tmppref;
189 register char *tmphost;
190
191 tmppref = prefer[i];
192 prefer[i] = prefer[j];
193 prefer[j] = tmppref;
194
195 tmphost = MxHosts[i];
196 MxHosts[i] = MxHosts[j];
197 MxHosts[j] = tmphost;
198 }
199 }
200 }
201
202 return(nmx);
203 }
204