1 /* 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 */ 16 17 #include <sendmail.h> 18 19 #ifndef lint 20 static char sccsid[] = "@(#)domain.c 5.14 (Berkeley) 05/03/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[MAXMXHOSTS*PACKETSZ]; 34 35 getmxrr(host, mxhosts, localhost, rcode) 36 char *host, **mxhosts, *localhost; 37 int *rcode; 38 { 39 extern int h_errno; 40 register u_char *eom, *cp; 41 register int i, j, n, nmx; 42 register char *bp; 43 HEADER *hp; 44 querybuf answer; 45 int ancount, qdcount, buflen, seenlocal; 46 u_short pref, localpref, type, prefer[MAXMXHOSTS]; 47 48 n = res_search(host, C_IN, T_MX, (char *)&answer, sizeof(answer)); 49 if (n < 0) { 50 #ifdef DEBUG 51 if (tTd(8, 1)) 52 printf("getmxrr: res_search failed (errno=%d, h_errno=%d)\n", 53 errno, h_errno); 54 #endif 55 switch(h_errno) { 56 case NO_DATA: 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; 65 } 66 return(-1); 67 } 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; 76 nmx = 0; 77 seenlocal = 0; 78 buflen = sizeof(hostbuf); 79 bp = hostbuf; 80 ancount = ntohs(hp->ancount); 81 while (--ancount >= 0 && cp < eom && nmx < MAXMXHOSTS) { 82 if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0) 83 break; 84 cp += n; 85 GETSHORT(type, cp); 86 cp += sizeof(u_short) + sizeof(u_long); 87 GETSHORT(n, cp); 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", 92 type, n); 93 #endif 94 cp += n; 95 continue; 96 } 97 GETSHORT(pref, cp); 98 if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0) 99 break; 100 cp += n; 101 if (!strcasecmp(bp, localhost)) { 102 if (seenlocal == 0 || pref < localpref) 103 localpref = pref; 104 seenlocal = 1; 105 continue; 106 } 107 prefer[nmx] = pref; 108 mxhosts[nmx++] = bp; 109 n = strlen(bp) + 1; 110 bp += n; 111 buflen -= n; 112 } 113 if (nmx == 0) { 114 punt: mxhosts[0] = strcpy(hostbuf, host); 115 return(1); 116 } 117 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]) { 122 register int temp; 123 register char *temp1; 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 } 133 if (seenlocal && prefer[i] >= localpref) { 134 /* 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. 138 */ 139 if (i == 0) { 140 *rcode = EX_CONFIG; 141 return(-1); 142 } 143 nmx = i; 144 break; 145 } 146 } 147 return(nmx); 148 } 149 150 getcanonname(host, hbsize) 151 char *host; 152 int hbsize; 153 { 154 register u_char *eom, *cp; 155 register int n; 156 HEADER *hp; 157 querybuf answer; 158 u_short type; 159 int first, ancount, qdcount, loopcnt; 160 char nbuf[PACKETSZ]; 161 162 loopcnt = 0; 163 loop: 164 n = res_search(host, C_IN, T_CNAME, (char *)&answer, sizeof(answer)); 165 if (n < 0) { 166 #ifdef DEBUG 167 if (tTd(8, 1)) 168 printf("getcanonname: res_search failed (errno=%d, h_errno=%d)\n", 169 errno, h_errno); 170 #endif 171 return; 172 } 173 174 /* find first satisfactory answer */ 175 hp = (HEADER *)&answer; 176 ancount = ntohs(hp->ancount); 177 178 /* we don't care about errors here, only if we got an answer */ 179 if (ancount == 0) { 180 #ifdef DEBUG 181 if (tTd(8, 1)) 182 printf("rcode = %d, ancount=%d\n", hp->rcode, ancount); 183 #endif 184 return; 185 } 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) { 198 if ((n = dn_expand((char *)&answer, eom, cp, nbuf, 199 sizeof(nbuf))) < 0) 200 break; 201 if (first) { /* XXX */ 202 (void)strncpy(host, nbuf, hbsize); 203 host[hbsize - 1] = '\0'; 204 first = 0; 205 } 206 cp += n; 207 GETSHORT(type, cp); 208 cp += sizeof(u_short) + sizeof(u_long); 209 GETSHORT(n, cp); 210 if (type == T_CNAME) { 211 /* 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. 215 */ 216 if ((n = dn_expand((char *)&answer, eom, cp, nbuf, 217 sizeof(nbuf))) < 0) 218 break; 219 (void)strncpy(host, nbuf, hbsize); /* XXX */ 220 host[hbsize - 1] = '\0'; 221 if (++loopcnt > 8) /* never be more than 1 */ 222 return; 223 goto loop; 224 } 225 } 226 } 227