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.3 (Berkeley) 07/21/86 (no MXDOMAIN)"; 14 #endif not lint 15 #else MXDOMAIN 16 17 #ifndef lint 18 static char SccsId[] = "@(#)domain.c 5.3 (Berkeley) 07/21/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 #ifdef OLDJEEVES 95 /* 96 * Jeeves (TOPS-20 server) still does not 97 * support MX records. For the time being, 98 * we must accept FORMERRs as the same as 99 * NOERROR. 100 */ 101 case FORMERR: 102 #endif OLDJEEVES 103 case NOERROR: 104 (void) strcpy(hostbuf, host); 105 mxhosts[0] = hostbuf; 106 return(1); 107 #ifndef OLDJEEVES 108 case FORMERR: 109 #endif OLDJEEVES 110 case NOTIMP: 111 case REFUSED: 112 h_errno = NO_RECOVERY; 113 return(-2); 114 } 115 return (-1); 116 } 117 bp = hostbuf; 118 nmx = 0; 119 seenlocal = 0; 120 buflen = sizeof(hostbuf); 121 cp = (char *)&answer + sizeof(HEADER); 122 if (qdcount) { 123 cp += dn_skip(cp) + QFIXEDSZ; 124 while (--qdcount > 0) 125 cp += dn_skip(cp) + QFIXEDSZ; 126 } 127 while (--ancount >= 0 && cp < eom && nmx < maxmx) { 128 if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0) 129 break; 130 cp += n; 131 type = getshort(cp); 132 cp += sizeof(u_short); 133 /* 134 class = getshort(cp); 135 */ 136 cp += sizeof(u_short) + sizeof(u_long); 137 n = getshort(cp); 138 cp += sizeof(u_short); 139 if (type != T_MX) { 140 #ifdef DEBUG 141 if (tTd(8, 1) || _res.options & RES_DEBUG) 142 printf("unexpected answer type %d, size %d\n", 143 type, n); 144 #endif 145 cp += n; 146 continue; 147 } 148 pref = getshort(cp); 149 cp += sizeof(u_short); 150 if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0) 151 break; 152 cp += n; 153 if (sameword(bp, localhost)) 154 { 155 seenlocal = 1; 156 localpref = pref; 157 continue; 158 } 159 prefer[nmx] = pref; 160 mxhosts[nmx++] = bp; 161 n1 = strlen(bp)+1; 162 bp += n1; 163 buflen -= n1; 164 } 165 if (nmx == 0) { 166 (void) strcpy(hostbuf, host); 167 mxhosts[0] = hostbuf; 168 return(1); 169 } 170 /* sort the records */ 171 for (i = 0; i < nmx; i++) { 172 for (j = i + 1; j < nmx; j++) { 173 if (prefer[i] > prefer[j]) { 174 int temp; 175 char *temp1; 176 177 temp = prefer[i]; 178 prefer[i] = prefer[j]; 179 prefer[j] = temp; 180 temp1 = mxhosts[i]; 181 mxhosts[i] = mxhosts[j]; 182 mxhosts[j] = temp1; 183 } 184 } 185 if (seenlocal && (prefer[i] >= localpref)) 186 { 187 nmx = i; 188 /* 189 * We are the first MX, might as well try delivering 190 * since nobody is supposed to have more info. 191 */ 192 if (nmx == 0) 193 { 194 (void) strcpy(hostbuf, host); 195 mxhosts[0] = hostbuf; 196 return(1); 197 } 198 break; 199 } 200 } 201 return(nmx); 202 } 203 204 205 getcanonname(host, hbsize) 206 char *host; 207 int hbsize; 208 { 209 210 HEADER *hp; 211 char *eom, *cp; 212 querybuf buf, answer; 213 int n, ancount, qdcount; 214 u_short type; 215 char nbuf[BUFSIZ]; 216 int first; 217 218 n = res_mkquery(QUERY, host, C_IN, T_ANY, (char *)NULL, 0, NULL, 219 (char *)&buf, sizeof(buf)); 220 if (n < 0) { 221 #ifdef DEBUG 222 if (tTd(8, 1) || _res.options & RES_DEBUG) 223 printf("res_mkquery failed\n"); 224 #endif 225 h_errno = NO_RECOVERY; 226 return; 227 } 228 n = res_send((char *)&buf, n, (char *)&answer, sizeof(answer)); 229 if (n < 0) { 230 #ifdef DEBUG 231 if (tTd(8, 1) || _res.options & RES_DEBUG) 232 printf("res_send failed\n"); 233 #endif 234 h_errno = TRY_AGAIN; 235 return; 236 } 237 eom = (char *)&answer + n; 238 /* 239 * find first satisfactory answer 240 */ 241 hp = (HEADER *) &answer; 242 ancount = ntohs(hp->ancount); 243 qdcount = ntohs(hp->qdcount); 244 /* 245 * We don't care about errors here, only if we got an answer 246 */ 247 if (ancount == 0) { 248 #ifdef DEBUG 249 if (tTd(8, 1) || _res.options & RES_DEBUG) 250 printf("rcode = %d, ancount=%d\n", hp->rcode, ancount); 251 #endif 252 return; 253 } 254 cp = (char *)&answer + sizeof(HEADER); 255 if (qdcount) { 256 cp += dn_skip(cp) + QFIXEDSZ; 257 while (--qdcount > 0) 258 cp += dn_skip(cp) + QFIXEDSZ; 259 } 260 first = 1; 261 while (--ancount >= 0 && cp < eom) { 262 if ((n = dn_expand((char *)&answer, eom, cp, nbuf, 263 sizeof(nbuf))) < 0) 264 break; 265 if (first) { 266 (void)strncpy(host, nbuf, hbsize); 267 host[hbsize - 1] = '\0'; 268 first = 0; 269 } 270 cp += n; 271 type = getshort(cp); 272 cp += sizeof(u_short); 273 cp += sizeof(u_short) + sizeof(u_long); 274 n = getshort(cp); 275 cp += sizeof(u_short); 276 if (type == T_CNAME) { 277 /* 278 * Assume that only one cname will be found. More 279 * than one is undefined. 280 */ 281 if ((n = dn_expand((char *)&answer, eom, cp, nbuf, 282 sizeof(nbuf))) < 0) 283 break; 284 (void)strncpy(host, nbuf, hbsize); 285 host[hbsize - 1] = '\0'; 286 getcanonname(host, hbsize); 287 break; 288 } 289 cp += n; 290 } 291 return; 292 } 293 #endif MXDOMAIN 294