Commit | Line | Data |
---|---|---|
8c0f18d2 | 1 | /* |
1acb1197 KB |
2 | * Copyright (c) 1988 Regents of the University of California. |
3 | * All rights reserved. | |
4 | * | |
5 | * Redistribution and use in source and binary forms are permitted | |
6 | * provided that this notice is preserved and that due credit is given | |
7 | * to the University of California at Berkeley. The name of the University | |
8 | * may not be used to endorse or promote products derived from this | |
9 | * software without specific prior written permission. This software | |
10 | * is provided ``as is'' without express or implied warranty. | |
11 | * | |
12 | * Sendmail | |
13 | * Copyright (c) 1986 Eric P. Allman | |
14 | * Berkeley, California | |
15 | */ | |
8c0f18d2 | 16 | |
bece62ab | 17 | #include <sendmail.h> |
578710da | 18 | |
8c0f18d2 | 19 | #ifndef lint |
c9677644 | 20 | static char sccsid[] = "@(#)domain.c 5.13 (Berkeley) %G%"; |
1acb1197 KB |
21 | #endif /* not lint */ |
22 | ||
bece62ab KB |
23 | #include <sys/param.h> |
24 | #include <arpa/nameser.h> | |
25 | #include <resolv.h> | |
26 | #include <netdb.h> | |
8c0f18d2 JB |
27 | |
28 | typedef union { | |
29 | HEADER qb1; | |
30 | char qb2[PACKETSZ]; | |
31 | } querybuf; | |
32 | ||
bece62ab | 33 | static char hostbuf[MAXMXHOSTS*PACKETSZ]; |
8c0f18d2 | 34 | |
bece62ab KB |
35 | getmxrr(host, mxhosts, localhost, rcode) |
36 | char *host, **mxhosts, *localhost; | |
37 | int *rcode; | |
8c0f18d2 | 38 | { |
bece62ab KB |
39 | extern int h_errno; |
40 | register u_char *eom, *cp; | |
41 | register int i, j, n, nmx; | |
42 | register char *bp; | |
8c0f18d2 | 43 | HEADER *hp; |
bece62ab KB |
44 | querybuf answer; |
45 | int ancount, qdcount, buflen, seenlocal; | |
46 | u_short pref, localpref, type, prefer[MAXMXHOSTS]; | |
8c0f18d2 | 47 | |
bece62ab | 48 | n = res_search(host, C_IN, T_MX, (char *)&answer, sizeof(answer)); |
8c0f18d2 JB |
49 | if (n < 0) { |
50 | #ifdef DEBUG | |
bece62ab KB |
51 | if (tTd(8, 1)) |
52 | printf("getmxrr: res_search failed (errno=%d, h_errno=%d)\n", | |
53 | errno, h_errno); | |
8c0f18d2 | 54 | #endif |
bece62ab | 55 | switch(h_errno) { |
c9677644 | 56 | case NO_DATA: |
bece62ab KB |
57 | case NO_RECOVERY: |
58 | goto punt; | |
59 | case HOST_NOT_FOUND: | |
60 | *rcode = EX_NOHOST; | |
61 | break; | |
62 | case TRY_AGAIN: | |
63 | *rcode = EX_TEMPFAIL; | |
64 | break; | |
8c0f18d2 | 65 | } |
bece62ab | 66 | return(-1); |
8c0f18d2 | 67 | } |
bece62ab KB |
68 | |
69 | /* find first satisfactory answer */ | |
70 | hp = (HEADER *)&answer; | |
71 | cp = (u_char *)&answer + sizeof(HEADER); | |
72 | eom = (u_char *)&answer + n; | |
73 | for (qdcount = ntohs(hp->qdcount); qdcount--; cp += n + QFIXEDSZ) | |
74 | if ((n = dn_skipname(cp, eom)) < 0) | |
75 | goto punt; | |
8c0f18d2 | 76 | nmx = 0; |
3fff2c44 | 77 | seenlocal = 0; |
8c0f18d2 | 78 | buflen = sizeof(hostbuf); |
bece62ab KB |
79 | bp = hostbuf; |
80 | ancount = ntohs(hp->ancount); | |
81 | while (--ancount >= 0 && cp < eom && nmx < MAXMXHOSTS) { | |
8c0f18d2 JB |
82 | if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0) |
83 | break; | |
84 | cp += n; | |
bece62ab | 85 | GETSHORT(type, cp); |
8c0f18d2 | 86 | cp += sizeof(u_short) + sizeof(u_long); |
bece62ab | 87 | GETSHORT(n, cp); |
8c0f18d2 JB |
88 | if (type != T_MX) { |
89 | #ifdef DEBUG | |
90 | if (tTd(8, 1) || _res.options & RES_DEBUG) | |
91 | printf("unexpected answer type %d, size %d\n", | |
bece62ab | 92 | type, n); |
8c0f18d2 JB |
93 | #endif |
94 | cp += n; | |
95 | continue; | |
96 | } | |
bece62ab | 97 | GETSHORT(pref, cp); |
8c0f18d2 JB |
98 | if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0) |
99 | break; | |
3fff2c44 | 100 | cp += n; |
bece62ab KB |
101 | if (!strcasecmp(bp, localhost)) { |
102 | if (seenlocal == 0 || pref < localpref) | |
103 | localpref = pref; | |
3fff2c44 | 104 | seenlocal = 1; |
3fff2c44 JB |
105 | continue; |
106 | } | |
8c0f18d2 JB |
107 | prefer[nmx] = pref; |
108 | mxhosts[nmx++] = bp; | |
bece62ab KB |
109 | n = strlen(bp) + 1; |
110 | bp += n; | |
111 | buflen -= n; | |
8c0f18d2 | 112 | } |
3fff2c44 | 113 | if (nmx == 0) { |
bece62ab | 114 | punt: mxhosts[0] = strcpy(hostbuf, host); |
3fff2c44 JB |
115 | return(1); |
116 | } | |
bece62ab | 117 | |
8c0f18d2 JB |
118 | /* sort the records */ |
119 | for (i = 0; i < nmx; i++) { | |
120 | for (j = i + 1; j < nmx; j++) { | |
121 | if (prefer[i] > prefer[j]) { | |
bece62ab KB |
122 | register int temp; |
123 | register char *temp1; | |
8c0f18d2 JB |
124 | |
125 | temp = prefer[i]; | |
126 | prefer[i] = prefer[j]; | |
127 | prefer[j] = temp; | |
128 | temp1 = mxhosts[i]; | |
129 | mxhosts[i] = mxhosts[j]; | |
130 | mxhosts[j] = temp1; | |
131 | } | |
132 | } | |
bece62ab | 133 | if (seenlocal && prefer[i] >= localpref) { |
3fff2c44 | 134 | /* |
bece62ab KB |
135 | * truncate higher pref part of list; if we're |
136 | * the best choice left, we should have realized | |
137 | * awhile ago that this was a local delivery. | |
3fff2c44 | 138 | */ |
bece62ab KB |
139 | if (i == 0) { |
140 | *rcode = EX_CONFIG; | |
141 | return(-1); | |
3fff2c44 | 142 | } |
bece62ab | 143 | nmx = i; |
3fff2c44 JB |
144 | break; |
145 | } | |
8c0f18d2 JB |
146 | } |
147 | return(nmx); | |
148 | } | |
b22f87a1 | 149 | |
b22f87a1 JB |
150 | getcanonname(host, hbsize) |
151 | char *host; | |
152 | int hbsize; | |
153 | { | |
bece62ab KB |
154 | register u_char *eom, *cp; |
155 | register int n; | |
b22f87a1 | 156 | HEADER *hp; |
bece62ab | 157 | querybuf answer; |
b22f87a1 | 158 | u_short type; |
bece62ab KB |
159 | int first, ancount, qdcount, loopcnt; |
160 | char nbuf[PACKETSZ]; | |
b22f87a1 | 161 | |
bece62ab KB |
162 | loopcnt = 0; |
163 | loop: | |
164 | n = res_search(host, C_IN, T_ANY, (char *)&answer, sizeof(answer)); | |
b22f87a1 JB |
165 | if (n < 0) { |
166 | #ifdef DEBUG | |
bece62ab KB |
167 | if (tTd(8, 1)) |
168 | printf("getcanonname: res_search failed (errno=%d, h_errno=%d)\n", | |
169 | errno, h_errno); | |
b22f87a1 | 170 | #endif |
b22f87a1 JB |
171 | return; |
172 | } | |
bece62ab KB |
173 | |
174 | /* find first satisfactory answer */ | |
175 | hp = (HEADER *)&answer; | |
b22f87a1 | 176 | ancount = ntohs(hp->ancount); |
bece62ab KB |
177 | |
178 | /* we don't care about errors here, only if we got an answer */ | |
b22f87a1 JB |
179 | if (ancount == 0) { |
180 | #ifdef DEBUG | |
bece62ab | 181 | if (tTd(8, 1)) |
b22f87a1 JB |
182 | printf("rcode = %d, ancount=%d\n", hp->rcode, ancount); |
183 | #endif | |
184 | return; | |
185 | } | |
bece62ab KB |
186 | cp = (u_char *)&answer + sizeof(HEADER); |
187 | eom = (u_char *)&answer + n; | |
188 | for (qdcount = ntohs(hp->qdcount); qdcount--; cp += n + QFIXEDSZ) | |
189 | if ((n = dn_skipname(cp, eom)) < 0) | |
190 | return; | |
191 | ||
192 | /* | |
193 | * just in case someone puts a CNAME record after another record, | |
194 | * check all records for CNAME; otherwise, just take the first | |
195 | * name found. | |
196 | */ | |
197 | for (first = 1; --ancount >= 0 && cp < eom; cp += n) { | |
b22f87a1 JB |
198 | if ((n = dn_expand((char *)&answer, eom, cp, nbuf, |
199 | sizeof(nbuf))) < 0) | |
200 | break; | |
bece62ab | 201 | if (first) { /* XXX */ |
b22f87a1 JB |
202 | (void)strncpy(host, nbuf, hbsize); |
203 | host[hbsize - 1] = '\0'; | |
204 | first = 0; | |
205 | } | |
206 | cp += n; | |
bece62ab | 207 | GETSHORT(type, cp); |
b22f87a1 | 208 | cp += sizeof(u_short) + sizeof(u_long); |
bece62ab | 209 | GETSHORT(n, cp); |
b22f87a1 JB |
210 | if (type == T_CNAME) { |
211 | /* | |
bece62ab KB |
212 | * assume that only one cname will be found. More |
213 | * than one is undefined. Copy so that if dn_expand | |
214 | * fails, `host' is still okay. | |
b22f87a1 JB |
215 | */ |
216 | if ((n = dn_expand((char *)&answer, eom, cp, nbuf, | |
217 | sizeof(nbuf))) < 0) | |
218 | break; | |
bece62ab | 219 | (void)strncpy(host, nbuf, hbsize); /* XXX */ |
b22f87a1 | 220 | host[hbsize - 1] = '\0'; |
bece62ab KB |
221 | if (++loopcnt > 8) /* never be more than 1 */ |
222 | return; | |
223 | goto loop; | |
b22f87a1 | 224 | } |
b22f87a1 | 225 | } |
b22f87a1 | 226 | } |