129432Sbloom /* 2*33778Sbostic * Copyright (c) 1988 Regents of the University of California. 3*33778Sbostic * All rights reserved. 4*33778Sbostic * 5*33778Sbostic * Redistribution and use in source and binary forms are permitted 6*33778Sbostic * provided that this notice is preserved and that due credit is given 7*33778Sbostic * to the University of California at Berkeley. The name of the University 8*33778Sbostic * may not be used to endorse or promote products derived from this 9*33778Sbostic * software without specific prior written permission. This software 10*33778Sbostic * is provided ``as is'' without express or implied warranty. 11*33778Sbostic * 12*33778Sbostic * Sendmail 13*33778Sbostic * Copyright (c) 1986 Eric P. Allman 14*33778Sbostic * Berkeley, California 15*33778Sbostic */ 1629432Sbloom 1729660Sbloom #include "sendmail.h" 1829660Sbloom 1929432Sbloom #ifndef lint 20*33778Sbostic #ifdef MXDOMAIN 21*33778Sbostic static char sccsid[] = "@(#)domain.c 5.10 (Berkeley) 03/24/88 (with MXDOMAIN)"; 22*33778Sbostic #else 23*33778Sbostic static char sccsid[] = "@(#)domain.c 5.10 (Berkeley) 03/24/88 (without MXDOMAIN)"; 24*33778Sbostic #endif 25*33778Sbostic #endif /* not lint */ 2629432Sbloom 27*33778Sbostic #ifdef MXDOMAIN 2829432Sbloom # include <sys/param.h> 2929432Sbloom # include <arpa/nameser.h> 3029432Sbloom # include <resolv.h> 3129432Sbloom # include <netdb.h> 3229432Sbloom 3329432Sbloom typedef union { 3429432Sbloom HEADER qb1; 3529432Sbloom char qb2[PACKETSZ]; 3629432Sbloom } querybuf; 3729432Sbloom 3830448Seric static char hostbuf[BUFSIZ]; 3930448Seric int h_errno; 4033777Sbostic extern u_short _getshort(); 4129432Sbloom 4229551Sbloom getmxrr(host, mxhosts, maxmx, localhost) 4329432Sbloom char *host, **mxhosts; 4429432Sbloom int maxmx; 4529551Sbloom char *localhost; 4629432Sbloom { 4729432Sbloom 4829432Sbloom HEADER *hp; 4929432Sbloom char *eom, *bp, *cp; 5029432Sbloom querybuf buf, answer; 5129432Sbloom int n, n1, i, j, nmx, ancount, qdcount, buflen; 5229551Sbloom int seenlocal; 5329432Sbloom u_short prefer[BUFSIZ]; 5429551Sbloom u_short pref, localpref, type, class; 5529432Sbloom 5629432Sbloom n = res_mkquery(QUERY, host, C_IN, T_MX, (char *)NULL, 0, NULL, 5729432Sbloom (char *)&buf, sizeof(buf)); 5829432Sbloom if (n < 0) { 5929432Sbloom #ifdef DEBUG 6029432Sbloom if (tTd(8, 1) || _res.options & RES_DEBUG) 6129432Sbloom printf("res_mkquery failed\n"); 6229432Sbloom #endif 6329551Sbloom h_errno = NO_RECOVERY; 6429551Sbloom return(-2); 6529432Sbloom } 6629432Sbloom n = res_send((char *)&buf, n, (char *)&answer, sizeof(answer)); 6729432Sbloom if (n < 0) { 6829432Sbloom #ifdef DEBUG 6929432Sbloom if (tTd(8, 1) || _res.options & RES_DEBUG) 7029432Sbloom printf("res_send failed\n"); 7129432Sbloom #endif 7229432Sbloom h_errno = TRY_AGAIN; 7329432Sbloom return (-1); 7429432Sbloom } 7529432Sbloom eom = (char *)&answer + n; 7629432Sbloom /* 7729432Sbloom * find first satisfactory answer 7829432Sbloom */ 7929432Sbloom hp = (HEADER *) &answer; 8029432Sbloom ancount = ntohs(hp->ancount); 8129432Sbloom qdcount = ntohs(hp->qdcount); 8229432Sbloom if (hp->rcode != NOERROR || ancount == 0) { 8329432Sbloom #ifdef DEBUG 8429432Sbloom if (tTd(8, 1) || _res.options & RES_DEBUG) 8529432Sbloom printf("rcode = %d, ancount=%d\n", hp->rcode, ancount); 8629432Sbloom #endif 8729432Sbloom switch (hp->rcode) { 8829432Sbloom case NXDOMAIN: 8929432Sbloom /* Check if it's an authoritive answer */ 9029551Sbloom if (hp->aa) { 9129432Sbloom h_errno = HOST_NOT_FOUND; 9229551Sbloom return(-3); 9329551Sbloom } else { 9429432Sbloom h_errno = TRY_AGAIN; 9529551Sbloom return(-1); 9629551Sbloom } 9729432Sbloom case SERVFAIL: 9829432Sbloom h_errno = TRY_AGAIN; 9929551Sbloom return(-1); 10029653Sbloom #ifdef OLDJEEVES 10129653Sbloom /* 10229653Sbloom * Jeeves (TOPS-20 server) still does not 10329653Sbloom * support MX records. For the time being, 10429653Sbloom * we must accept FORMERRs as the same as 10529653Sbloom * NOERROR. 10629653Sbloom */ 10729653Sbloom case FORMERR: 10829653Sbloom #endif OLDJEEVES 10929432Sbloom case NOERROR: 11029551Sbloom (void) strcpy(hostbuf, host); 11129551Sbloom mxhosts[0] = hostbuf; 11229551Sbloom return(1); 11329653Sbloom #ifndef OLDJEEVES 11429432Sbloom case FORMERR: 11529653Sbloom #endif OLDJEEVES 11629432Sbloom case NOTIMP: 11729432Sbloom case REFUSED: 11829432Sbloom h_errno = NO_RECOVERY; 11929551Sbloom return(-2); 12029432Sbloom } 12129432Sbloom return (-1); 12229432Sbloom } 12329432Sbloom bp = hostbuf; 12429432Sbloom nmx = 0; 12529551Sbloom seenlocal = 0; 12629432Sbloom buflen = sizeof(hostbuf); 12729432Sbloom cp = (char *)&answer + sizeof(HEADER); 12829432Sbloom if (qdcount) { 12932988Sbostic cp += dn_skipname(cp, eom) + QFIXEDSZ; 13029432Sbloom while (--qdcount > 0) 13132988Sbostic cp += dn_skipname(cp, eom) + QFIXEDSZ; 13229432Sbloom } 13329432Sbloom while (--ancount >= 0 && cp < eom && nmx < maxmx) { 13429432Sbloom if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0) 13529432Sbloom break; 13629432Sbloom cp += n; 13733777Sbostic type = _getshort(cp); 13829432Sbloom cp += sizeof(u_short); 13929551Sbloom /* 14033777Sbostic class = _getshort(cp); 14129551Sbloom */ 14229432Sbloom cp += sizeof(u_short) + sizeof(u_long); 14333777Sbostic n = _getshort(cp); 14429432Sbloom cp += sizeof(u_short); 14529432Sbloom if (type != T_MX) { 14629432Sbloom #ifdef DEBUG 14729432Sbloom if (tTd(8, 1) || _res.options & RES_DEBUG) 14829432Sbloom printf("unexpected answer type %d, size %d\n", 14929432Sbloom type, n); 15029432Sbloom #endif 15129432Sbloom cp += n; 15229432Sbloom continue; 15329432Sbloom } 15433777Sbostic pref = _getshort(cp); 15529432Sbloom cp += sizeof(u_short); 15629432Sbloom if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0) 15729432Sbloom break; 15829551Sbloom cp += n; 15933725Sbostic if (!strcasecmp(bp, localhost)) 16029551Sbloom { 16129551Sbloom seenlocal = 1; 16229551Sbloom localpref = pref; 16329551Sbloom continue; 16429551Sbloom } 16529432Sbloom prefer[nmx] = pref; 16629432Sbloom mxhosts[nmx++] = bp; 16729432Sbloom n1 = strlen(bp)+1; 16829432Sbloom bp += n1; 16929432Sbloom buflen -= n1; 17029432Sbloom } 17129551Sbloom if (nmx == 0) { 17229551Sbloom (void) strcpy(hostbuf, host); 17329551Sbloom mxhosts[0] = hostbuf; 17429551Sbloom return(1); 17529551Sbloom } 17629432Sbloom /* sort the records */ 17729432Sbloom for (i = 0; i < nmx; i++) { 17829432Sbloom for (j = i + 1; j < nmx; j++) { 17929432Sbloom if (prefer[i] > prefer[j]) { 18029432Sbloom int temp; 18129432Sbloom char *temp1; 18229432Sbloom 18329432Sbloom temp = prefer[i]; 18429432Sbloom prefer[i] = prefer[j]; 18529432Sbloom prefer[j] = temp; 18629432Sbloom temp1 = mxhosts[i]; 18729432Sbloom mxhosts[i] = mxhosts[j]; 18829432Sbloom mxhosts[j] = temp1; 18929432Sbloom } 19029432Sbloom } 19129551Sbloom if (seenlocal && (prefer[i] >= localpref)) 19229551Sbloom { 19329551Sbloom nmx = i; 19429551Sbloom /* 19529551Sbloom * We are the first MX, might as well try delivering 19629551Sbloom * since nobody is supposed to have more info. 19729551Sbloom */ 19829551Sbloom if (nmx == 0) 19929551Sbloom { 20029551Sbloom (void) strcpy(hostbuf, host); 20129551Sbloom mxhosts[0] = hostbuf; 20229551Sbloom return(1); 20329551Sbloom } 20429551Sbloom break; 20529551Sbloom } 20629432Sbloom } 20729432Sbloom return(nmx); 20829432Sbloom } 20929653Sbloom 21029653Sbloom 21129653Sbloom getcanonname(host, hbsize) 21229653Sbloom char *host; 21329653Sbloom int hbsize; 21429653Sbloom { 21529653Sbloom 21629653Sbloom HEADER *hp; 21729653Sbloom char *eom, *cp; 21829653Sbloom querybuf buf, answer; 21929653Sbloom int n, ancount, qdcount; 22029653Sbloom u_short type; 22129653Sbloom char nbuf[BUFSIZ]; 22229653Sbloom int first; 22329653Sbloom 22429653Sbloom n = res_mkquery(QUERY, host, C_IN, T_ANY, (char *)NULL, 0, NULL, 22529653Sbloom (char *)&buf, sizeof(buf)); 22629653Sbloom if (n < 0) { 22729653Sbloom #ifdef DEBUG 22829653Sbloom if (tTd(8, 1) || _res.options & RES_DEBUG) 22929653Sbloom printf("res_mkquery failed\n"); 23029653Sbloom #endif 23129653Sbloom h_errno = NO_RECOVERY; 23229653Sbloom return; 23329653Sbloom } 23429653Sbloom n = res_send((char *)&buf, n, (char *)&answer, sizeof(answer)); 23529653Sbloom if (n < 0) { 23629653Sbloom #ifdef DEBUG 23729653Sbloom if (tTd(8, 1) || _res.options & RES_DEBUG) 23829653Sbloom printf("res_send failed\n"); 23929653Sbloom #endif 24029653Sbloom h_errno = TRY_AGAIN; 24129653Sbloom return; 24229653Sbloom } 24329653Sbloom eom = (char *)&answer + n; 24429653Sbloom /* 24529653Sbloom * find first satisfactory answer 24629653Sbloom */ 24729653Sbloom hp = (HEADER *) &answer; 24829653Sbloom ancount = ntohs(hp->ancount); 24929653Sbloom qdcount = ntohs(hp->qdcount); 25029653Sbloom /* 25129653Sbloom * We don't care about errors here, only if we got an answer 25229653Sbloom */ 25329653Sbloom if (ancount == 0) { 25429653Sbloom #ifdef DEBUG 25529653Sbloom if (tTd(8, 1) || _res.options & RES_DEBUG) 25629653Sbloom printf("rcode = %d, ancount=%d\n", hp->rcode, ancount); 25729653Sbloom #endif 25829653Sbloom return; 25929653Sbloom } 26029653Sbloom cp = (char *)&answer + sizeof(HEADER); 26129653Sbloom if (qdcount) { 26232988Sbostic cp += dn_skipname(cp, eom) + QFIXEDSZ; 26329653Sbloom while (--qdcount > 0) 26432988Sbostic cp += dn_skipname(cp, eom) + QFIXEDSZ; 26529653Sbloom } 26629653Sbloom first = 1; 26729653Sbloom while (--ancount >= 0 && cp < eom) { 26829653Sbloom if ((n = dn_expand((char *)&answer, eom, cp, nbuf, 26929653Sbloom sizeof(nbuf))) < 0) 27029653Sbloom break; 27129653Sbloom if (first) { 27229653Sbloom (void)strncpy(host, nbuf, hbsize); 27329653Sbloom host[hbsize - 1] = '\0'; 27429653Sbloom first = 0; 27529653Sbloom } 27629653Sbloom cp += n; 27733777Sbostic type = _getshort(cp); 27829653Sbloom cp += sizeof(u_short); 27929653Sbloom cp += sizeof(u_short) + sizeof(u_long); 28033777Sbostic n = _getshort(cp); 28129653Sbloom cp += sizeof(u_short); 28229653Sbloom if (type == T_CNAME) { 28329653Sbloom /* 28429653Sbloom * Assume that only one cname will be found. More 28529653Sbloom * than one is undefined. 28629653Sbloom */ 28729653Sbloom if ((n = dn_expand((char *)&answer, eom, cp, nbuf, 28829653Sbloom sizeof(nbuf))) < 0) 28929653Sbloom break; 29029653Sbloom (void)strncpy(host, nbuf, hbsize); 29129653Sbloom host[hbsize - 1] = '\0'; 29229653Sbloom getcanonname(host, hbsize); 29329653Sbloom break; 29429653Sbloom } 29529653Sbloom cp += n; 29629653Sbloom } 29729653Sbloom return; 29829653Sbloom } 29929551Sbloom #endif MXDOMAIN 300