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: #if !defined(lint) && !defined(NOSCCS) 20: static char sccsid[] = "@(#)domain.c 5.14 (Berkeley) 5/3/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: #ifdef MXDOMAIN 34: static char hostbuf[MAXMXHOSTS*PACKETSZ]; 35: 36: getmxrr(host, mxhosts, localhost, rcode) 37: char *host, **mxhosts, *localhost; 38: int *rcode; 39: { 40: extern int h_errno; 41: register u_char *eom, *cp; 42: register int i, j, n, nmx; 43: register char *bp; 44: HEADER *hp; 45: querybuf answer; 46: int ancount, qdcount, buflen, seenlocal; 47: u_short pref, localpref, type, prefer[MAXMXHOSTS]; 48: 49: n = res_search(host, C_IN, T_MX, (char *)&answer, sizeof(answer)); 50: if (n < 0) { 51: #ifdef DEBUG 52: if (tTd(8, 1)) 53: printf("getmxrr: res_search failed (errno=%d, h_errno=%d)\n", 54: errno, h_errno); 55: #endif 56: switch(h_errno) { 57: case NO_DATA: 58: case NO_RECOVERY: 59: goto punt; 60: case HOST_NOT_FOUND: 61: *rcode = EX_NOHOST; 62: break; 63: case TRY_AGAIN: 64: *rcode = EX_TEMPFAIL; 65: break; 66: } 67: return(-1); 68: } 69: 70: /* find first satisfactory answer */ 71: hp = (HEADER *)&answer; 72: cp = (u_char *)&answer + sizeof(HEADER); 73: eom = (u_char *)&answer + n; 74: for (qdcount = ntohs(hp->qdcount); qdcount--; cp += n + QFIXEDSZ) 75: if ((n = dn_skipname(cp, eom)) < 0) 76: goto punt; 77: nmx = 0; 78: seenlocal = 0; 79: buflen = sizeof(hostbuf); 80: bp = hostbuf; 81: ancount = ntohs(hp->ancount); 82: while (--ancount >= 0 && cp < eom && nmx < MAXMXHOSTS) { 83: if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0) 84: break; 85: cp += n; 86: GETSHORT(type, cp); 87: cp += sizeof(u_short) + sizeof(u_long); 88: GETSHORT(n, cp); 89: if (type != T_MX) { 90: #ifdef DEBUG 91: if (tTd(8, 1) || _res.options & RES_DEBUG) 92: printf("unexpected answer type %d, size %d\n", 93: type, n); 94: #endif 95: cp += n; 96: continue; 97: } 98: GETSHORT(pref, cp); 99: if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0) 100: break; 101: cp += n; 102: if (!strcasecmp(bp, localhost)) { 103: if (seenlocal == 0 || pref < localpref) 104: localpref = pref; 105: seenlocal = 1; 106: continue; 107: } 108: prefer[nmx] = pref; 109: mxhosts[nmx++] = bp; 110: n = strlen(bp) + 1; 111: bp += n; 112: buflen -= n; 113: } 114: if (nmx == 0) { 115: punt: mxhosts[0] = strcpy(hostbuf, host); 116: return(1); 117: } 118: 119: /* sort the records */ 120: for (i = 0; i < nmx; i++) { 121: for (j = i + 1; j < nmx; j++) { 122: if (prefer[i] > prefer[j]) { 123: register int temp; 124: register char *temp1; 125: 126: temp = prefer[i]; 127: prefer[i] = prefer[j]; 128: prefer[j] = temp; 129: temp1 = mxhosts[i]; 130: mxhosts[i] = mxhosts[j]; 131: mxhosts[j] = temp1; 132: } 133: } 134: if (seenlocal && prefer[i] >= localpref) { 135: /* 136: * truncate higher pref part of list; if we're 137: * the best choice left, we should have realized 138: * awhile ago that this was a local delivery. 139: */ 140: if (i == 0) { 141: *rcode = EX_CONFIG; 142: return(-1); 143: } 144: nmx = i; 145: break; 146: } 147: } 148: return(nmx); 149: } 150: #endif MXDOMAIN 151: 152: getcanonname(host, hbsize) 153: char *host; 154: int hbsize; 155: { 156: register u_char *eom, *cp; 157: register int n; 158: HEADER *hp; 159: querybuf answer; 160: u_short type; 161: int first, ancount, qdcount, loopcnt; 162: extern int h_errno; 163: char nbuf[PACKETSZ]; 164: 165: loopcnt = 0; 166: loop: 167: n = res_search(host, C_IN, T_ANY, (char *)&answer, sizeof(answer)); 168: if (n < 0) { 169: #ifdef DEBUG 170: if (tTd(8, 1)) 171: printf("getcanonname: res_search failed (errno=%d, h_errno=%d)\n", 172: errno, h_errno); 173: #endif 174: return; 175: } 176: 177: /* find first satisfactory answer */ 178: hp = (HEADER *)&answer; 179: ancount = ntohs(hp->ancount); 180: 181: /* we don't care about errors here, only if we got an answer */ 182: if (ancount == 0) { 183: #ifdef DEBUG 184: if (tTd(8, 1)) 185: printf("rcode = %d, ancount=%d\n", hp->rcode, ancount); 186: #endif 187: return; 188: } 189: cp = (u_char *)&answer + sizeof(HEADER); 190: eom = (u_char *)&answer + n; 191: for (qdcount = ntohs(hp->qdcount); qdcount--; cp += n + QFIXEDSZ) 192: if ((n = dn_skipname(cp, eom)) < 0) 193: return; 194: 195: /* 196: * just in case someone puts a CNAME record after another record, 197: * check all records for CNAME; otherwise, just take the first 198: * name found. 199: */ 200: for (first = 1; --ancount >= 0 && cp < eom; cp += n) { 201: if ((n = dn_expand((char *)&answer, eom, cp, nbuf, 202: sizeof(nbuf))) < 0) 203: break; 204: if (first) { /* XXX */ 205: (void)strncpy(host, nbuf, hbsize); 206: host[hbsize - 1] = '\0'; 207: first = 0; 208: } 209: cp += n; 210: GETSHORT(type, cp); 211: cp += sizeof(u_short) + sizeof(u_long); 212: GETSHORT(n, cp); 213: if (type == T_CNAME) { 214: /* 215: * assume that only one cname will be found. More 216: * than one is undefined. Copy so that if dn_expand 217: * fails, `host' is still okay. 218: */ 219: if ((n = dn_expand((char *)&answer, eom, cp, nbuf, 220: sizeof(nbuf))) < 0) 221: break; 222: (void)strncpy(host, nbuf, hbsize); /* XXX */ 223: host[hbsize - 1] = '\0'; 224: if (++loopcnt > 8) /* never be more than 1 */ 225: return; 226: goto loop; 227: } 228: } 229: }