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 #include "sendmail.h" 12 13 #ifndef MXDOMAIN 14 #ifndef lint 15 static char SccsId[] = "@(#)domain.c 5.9 (Berkeley) 03/24/88 (no MXDOMAIN)"; 16 #endif not lint 17 #else MXDOMAIN 18 19 #ifndef lint 20 static char SccsId[] = "@(#)domain.c 5.9 (Berkeley) 03/24/88"; 21 #endif not lint 22 23 # include <sys/param.h> 24 # include <arpa/nameser.h> 25 # include <resolv.h> 26 # include <netdb.h> 27 28 typedef union { 29 HEADER qb1; 30 char qb2[PACKETSZ]; 31 } querybuf; 32 33 static char hostbuf[BUFSIZ]; 34 int h_errno; 35 extern u_short _getshort(); 36 37 getmxrr(host, mxhosts, maxmx, localhost) 38 char *host, **mxhosts; 39 int maxmx; 40 char *localhost; 41 { 42 43 HEADER *hp; 44 char *eom, *bp, *cp; 45 querybuf buf, answer; 46 int n, n1, i, j, nmx, ancount, qdcount, buflen; 47 int seenlocal; 48 u_short prefer[BUFSIZ]; 49 u_short pref, localpref, type, class; 50 51 n = res_mkquery(QUERY, host, C_IN, T_MX, (char *)NULL, 0, NULL, 52 (char *)&buf, sizeof(buf)); 53 if (n < 0) { 54 #ifdef DEBUG 55 if (tTd(8, 1) || _res.options & RES_DEBUG) 56 printf("res_mkquery failed\n"); 57 #endif 58 h_errno = NO_RECOVERY; 59 return(-2); 60 } 61 n = res_send((char *)&buf, n, (char *)&answer, sizeof(answer)); 62 if (n < 0) { 63 #ifdef DEBUG 64 if (tTd(8, 1) || _res.options & RES_DEBUG) 65 printf("res_send failed\n"); 66 #endif 67 h_errno = TRY_AGAIN; 68 return (-1); 69 } 70 eom = (char *)&answer + n; 71 /* 72 * find first satisfactory answer 73 */ 74 hp = (HEADER *) &answer; 75 ancount = ntohs(hp->ancount); 76 qdcount = ntohs(hp->qdcount); 77 if (hp->rcode != NOERROR || ancount == 0) { 78 #ifdef DEBUG 79 if (tTd(8, 1) || _res.options & RES_DEBUG) 80 printf("rcode = %d, ancount=%d\n", hp->rcode, ancount); 81 #endif 82 switch (hp->rcode) { 83 case NXDOMAIN: 84 /* Check if it's an authoritive answer */ 85 if (hp->aa) { 86 h_errno = HOST_NOT_FOUND; 87 return(-3); 88 } else { 89 h_errno = TRY_AGAIN; 90 return(-1); 91 } 92 case SERVFAIL: 93 h_errno = TRY_AGAIN; 94 return(-1); 95 #ifdef OLDJEEVES 96 /* 97 * Jeeves (TOPS-20 server) still does not 98 * support MX records. For the time being, 99 * we must accept FORMERRs as the same as 100 * NOERROR. 101 */ 102 case FORMERR: 103 #endif OLDJEEVES 104 case NOERROR: 105 (void) strcpy(hostbuf, host); 106 mxhosts[0] = hostbuf; 107 return(1); 108 #ifndef OLDJEEVES 109 case FORMERR: 110 #endif OLDJEEVES 111 case NOTIMP: 112 case REFUSED: 113 h_errno = NO_RECOVERY; 114 return(-2); 115 } 116 return (-1); 117 } 118 bp = hostbuf; 119 nmx = 0; 120 seenlocal = 0; 121 buflen = sizeof(hostbuf); 122 cp = (char *)&answer + sizeof(HEADER); 123 if (qdcount) { 124 cp += dn_skipname(cp, eom) + QFIXEDSZ; 125 while (--qdcount > 0) 126 cp += dn_skipname(cp, eom) + QFIXEDSZ; 127 } 128 while (--ancount >= 0 && cp < eom && nmx < maxmx) { 129 if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0) 130 break; 131 cp += n; 132 type = _getshort(cp); 133 cp += sizeof(u_short); 134 /* 135 class = _getshort(cp); 136 */ 137 cp += sizeof(u_short) + sizeof(u_long); 138 n = _getshort(cp); 139 cp += sizeof(u_short); 140 if (type != T_MX) { 141 #ifdef DEBUG 142 if (tTd(8, 1) || _res.options & RES_DEBUG) 143 printf("unexpected answer type %d, size %d\n", 144 type, n); 145 #endif 146 cp += n; 147 continue; 148 } 149 pref = _getshort(cp); 150 cp += sizeof(u_short); 151 if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0) 152 break; 153 cp += n; 154 if (!strcasecmp(bp, localhost)) 155 { 156 seenlocal = 1; 157 localpref = pref; 158 continue; 159 } 160 prefer[nmx] = pref; 161 mxhosts[nmx++] = bp; 162 n1 = strlen(bp)+1; 163 bp += n1; 164 buflen -= n1; 165 } 166 if (nmx == 0) { 167 (void) strcpy(hostbuf, host); 168 mxhosts[0] = hostbuf; 169 return(1); 170 } 171 /* sort the records */ 172 for (i = 0; i < nmx; i++) { 173 for (j = i + 1; j < nmx; j++) { 174 if (prefer[i] > prefer[j]) { 175 int temp; 176 char *temp1; 177 178 temp = prefer[i]; 179 prefer[i] = prefer[j]; 180 prefer[j] = temp; 181 temp1 = mxhosts[i]; 182 mxhosts[i] = mxhosts[j]; 183 mxhosts[j] = temp1; 184 } 185 } 186 if (seenlocal && (prefer[i] >= localpref)) 187 { 188 nmx = i; 189 /* 190 * We are the first MX, might as well try delivering 191 * since nobody is supposed to have more info. 192 */ 193 if (nmx == 0) 194 { 195 (void) strcpy(hostbuf, host); 196 mxhosts[0] = hostbuf; 197 return(1); 198 } 199 break; 200 } 201 } 202 return(nmx); 203 } 204 205 206 getcanonname(host, hbsize) 207 char *host; 208 int hbsize; 209 { 210 211 HEADER *hp; 212 char *eom, *cp; 213 querybuf buf, answer; 214 int n, ancount, qdcount; 215 u_short type; 216 char nbuf[BUFSIZ]; 217 int first; 218 219 n = res_mkquery(QUERY, host, C_IN, T_ANY, (char *)NULL, 0, NULL, 220 (char *)&buf, sizeof(buf)); 221 if (n < 0) { 222 #ifdef DEBUG 223 if (tTd(8, 1) || _res.options & RES_DEBUG) 224 printf("res_mkquery failed\n"); 225 #endif 226 h_errno = NO_RECOVERY; 227 return; 228 } 229 n = res_send((char *)&buf, n, (char *)&answer, sizeof(answer)); 230 if (n < 0) { 231 #ifdef DEBUG 232 if (tTd(8, 1) || _res.options & RES_DEBUG) 233 printf("res_send failed\n"); 234 #endif 235 h_errno = TRY_AGAIN; 236 return; 237 } 238 eom = (char *)&answer + n; 239 /* 240 * find first satisfactory answer 241 */ 242 hp = (HEADER *) &answer; 243 ancount = ntohs(hp->ancount); 244 qdcount = ntohs(hp->qdcount); 245 /* 246 * We don't care about errors here, only if we got an answer 247 */ 248 if (ancount == 0) { 249 #ifdef DEBUG 250 if (tTd(8, 1) || _res.options & RES_DEBUG) 251 printf("rcode = %d, ancount=%d\n", hp->rcode, ancount); 252 #endif 253 return; 254 } 255 cp = (char *)&answer + sizeof(HEADER); 256 if (qdcount) { 257 cp += dn_skipname(cp, eom) + QFIXEDSZ; 258 while (--qdcount > 0) 259 cp += dn_skipname(cp, eom) + QFIXEDSZ; 260 } 261 first = 1; 262 while (--ancount >= 0 && cp < eom) { 263 if ((n = dn_expand((char *)&answer, eom, cp, nbuf, 264 sizeof(nbuf))) < 0) 265 break; 266 if (first) { 267 (void)strncpy(host, nbuf, hbsize); 268 host[hbsize - 1] = '\0'; 269 first = 0; 270 } 271 cp += n; 272 type = _getshort(cp); 273 cp += sizeof(u_short); 274 cp += sizeof(u_short) + sizeof(u_long); 275 n = _getshort(cp); 276 cp += sizeof(u_short); 277 if (type == T_CNAME) { 278 /* 279 * Assume that only one cname will be found. More 280 * than one is undefined. 281 */ 282 if ((n = dn_expand((char *)&answer, eom, cp, nbuf, 283 sizeof(nbuf))) < 0) 284 break; 285 (void)strncpy(host, nbuf, hbsize); 286 host[hbsize - 1] = '\0'; 287 getcanonname(host, hbsize); 288 break; 289 } 290 cp += n; 291 } 292 return; 293 } 294 #endif MXDOMAIN 295