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.2 (Berkeley) 07/10/86 (no MXDOMAIN)"; 14 #endif not lint 15 #else MXDOMAIN 16 17 #ifndef lint 18 static char SccsId[] = "@(#)domain.c 5.2 (Berkeley) 07/10/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 case NOERROR: 95 (void) strcpy(hostbuf, host); 96 mxhosts[0] = hostbuf; 97 return(1); 98 case FORMERR: 99 case NOTIMP: 100 case REFUSED: 101 h_errno = NO_RECOVERY; 102 return(-2); 103 } 104 return (-1); 105 } 106 bp = hostbuf; 107 nmx = 0; 108 seenlocal = 0; 109 buflen = sizeof(hostbuf); 110 cp = (char *)&answer + sizeof(HEADER); 111 if (qdcount) { 112 cp += dn_skip(cp) + QFIXEDSZ; 113 while (--qdcount > 0) 114 cp += dn_skip(cp) + QFIXEDSZ; 115 } 116 while (--ancount >= 0 && cp < eom && nmx < maxmx) { 117 if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0) 118 break; 119 cp += n; 120 type = getshort(cp); 121 cp += sizeof(u_short); 122 /* 123 class = getshort(cp); 124 */ 125 cp += sizeof(u_short) + sizeof(u_long); 126 n = getshort(cp); 127 cp += sizeof(u_short); 128 if (type != T_MX) { 129 #ifdef DEBUG 130 if (tTd(8, 1) || _res.options & RES_DEBUG) 131 printf("unexpected answer type %d, size %d\n", 132 type, n); 133 #endif 134 cp += n; 135 continue; 136 } 137 pref = getshort(cp); 138 cp += sizeof(u_short); 139 if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0) 140 break; 141 cp += n; 142 if (sameword(bp, localhost)) 143 { 144 seenlocal = 1; 145 localpref = pref; 146 continue; 147 } 148 prefer[nmx] = pref; 149 mxhosts[nmx++] = bp; 150 n1 = strlen(bp)+1; 151 bp += n1; 152 buflen -= n1; 153 } 154 if (nmx == 0) { 155 (void) strcpy(hostbuf, host); 156 mxhosts[0] = hostbuf; 157 return(1); 158 } 159 /* sort the records */ 160 for (i = 0; i < nmx; i++) { 161 for (j = i + 1; j < nmx; j++) { 162 if (prefer[i] > prefer[j]) { 163 int temp; 164 char *temp1; 165 166 temp = prefer[i]; 167 prefer[i] = prefer[j]; 168 prefer[j] = temp; 169 temp1 = mxhosts[i]; 170 mxhosts[i] = mxhosts[j]; 171 mxhosts[j] = temp1; 172 } 173 } 174 if (seenlocal && (prefer[i] >= localpref)) 175 { 176 nmx = i; 177 /* 178 * We are the first MX, might as well try delivering 179 * since nobody is supposed to have more info. 180 */ 181 if (nmx == 0) 182 { 183 (void) strcpy(hostbuf, host); 184 mxhosts[0] = hostbuf; 185 return(1); 186 } 187 break; 188 } 189 } 190 return(nmx); 191 } 192 #endif MXDOMAIN 193