129432Sbloom /* 229432Sbloom ** Sendmail 329432Sbloom ** Copyright (c) 1986 Eric P. Allman 429432Sbloom ** Berkeley, California 529432Sbloom ** 629432Sbloom ** Copyright (c) 1986 Regents of the University of California. 729432Sbloom ** All rights reserved. The Berkeley software License Agreement 829432Sbloom ** specifies the terms and conditions for redistribution. 929432Sbloom */ 1029432Sbloom 11*29660Sbloom #include "sendmail.h" 12*29660Sbloom 1329551Sbloom #ifndef MXDOMAIN 1429432Sbloom #ifndef lint 15*29660Sbloom static char SccsId[] = "@(#)domain.c 5.4 (Berkeley) 07/25/86 (no MXDOMAIN)"; 1629432Sbloom #endif not lint 1729551Sbloom #else MXDOMAIN 1829432Sbloom 1929551Sbloom #ifndef lint 20*29660Sbloom static char SccsId[] = "@(#)domain.c 5.4 (Berkeley) 07/25/86"; 2129551Sbloom #endif not lint 2229551Sbloom 2329432Sbloom # include <sys/param.h> 2429432Sbloom # include <arpa/nameser.h> 2529432Sbloom # include <resolv.h> 2629432Sbloom # include <netdb.h> 2729432Sbloom 2829432Sbloom typedef union { 2929432Sbloom HEADER qb1; 3029432Sbloom char qb2[PACKETSZ]; 3129432Sbloom } querybuf; 3229432Sbloom 3329432Sbloom static char hostbuf[BUFSIZ]; 3429432Sbloom 3529432Sbloom int h_errno; 3629432Sbloom 3729551Sbloom getmxrr(host, mxhosts, maxmx, localhost) 3829432Sbloom char *host, **mxhosts; 3929432Sbloom int maxmx; 4029551Sbloom char *localhost; 4129432Sbloom { 4229432Sbloom 4329432Sbloom HEADER *hp; 4429432Sbloom char *eom, *bp, *cp; 4529432Sbloom querybuf buf, answer; 4629432Sbloom int n, n1, i, j, nmx, ancount, qdcount, buflen; 4729551Sbloom int seenlocal; 4829432Sbloom u_short prefer[BUFSIZ]; 4929551Sbloom u_short pref, localpref, type, class; 5029432Sbloom 5129432Sbloom n = res_mkquery(QUERY, host, C_IN, T_MX, (char *)NULL, 0, NULL, 5229432Sbloom (char *)&buf, sizeof(buf)); 5329432Sbloom if (n < 0) { 5429432Sbloom #ifdef DEBUG 5529432Sbloom if (tTd(8, 1) || _res.options & RES_DEBUG) 5629432Sbloom printf("res_mkquery failed\n"); 5729432Sbloom #endif 5829551Sbloom h_errno = NO_RECOVERY; 5929551Sbloom return(-2); 6029432Sbloom } 6129432Sbloom n = res_send((char *)&buf, n, (char *)&answer, sizeof(answer)); 6229432Sbloom if (n < 0) { 6329432Sbloom #ifdef DEBUG 6429432Sbloom if (tTd(8, 1) || _res.options & RES_DEBUG) 6529432Sbloom printf("res_send failed\n"); 6629432Sbloom #endif 6729432Sbloom h_errno = TRY_AGAIN; 6829432Sbloom return (-1); 6929432Sbloom } 7029432Sbloom eom = (char *)&answer + n; 7129432Sbloom /* 7229432Sbloom * find first satisfactory answer 7329432Sbloom */ 7429432Sbloom hp = (HEADER *) &answer; 7529432Sbloom ancount = ntohs(hp->ancount); 7629432Sbloom qdcount = ntohs(hp->qdcount); 7729432Sbloom if (hp->rcode != NOERROR || ancount == 0) { 7829432Sbloom #ifdef DEBUG 7929432Sbloom if (tTd(8, 1) || _res.options & RES_DEBUG) 8029432Sbloom printf("rcode = %d, ancount=%d\n", hp->rcode, ancount); 8129432Sbloom #endif 8229432Sbloom switch (hp->rcode) { 8329432Sbloom case NXDOMAIN: 8429432Sbloom /* Check if it's an authoritive answer */ 8529551Sbloom if (hp->aa) { 8629432Sbloom h_errno = HOST_NOT_FOUND; 8729551Sbloom return(-3); 8829551Sbloom } else { 8929432Sbloom h_errno = TRY_AGAIN; 9029551Sbloom return(-1); 9129551Sbloom } 9229432Sbloom case SERVFAIL: 9329432Sbloom h_errno = TRY_AGAIN; 9429551Sbloom return(-1); 9529653Sbloom #ifdef OLDJEEVES 9629653Sbloom /* 9729653Sbloom * Jeeves (TOPS-20 server) still does not 9829653Sbloom * support MX records. For the time being, 9929653Sbloom * we must accept FORMERRs as the same as 10029653Sbloom * NOERROR. 10129653Sbloom */ 10229653Sbloom case FORMERR: 10329653Sbloom #endif OLDJEEVES 10429432Sbloom case NOERROR: 10529551Sbloom (void) strcpy(hostbuf, host); 10629551Sbloom mxhosts[0] = hostbuf; 10729551Sbloom return(1); 10829653Sbloom #ifndef OLDJEEVES 10929432Sbloom case FORMERR: 11029653Sbloom #endif OLDJEEVES 11129432Sbloom case NOTIMP: 11229432Sbloom case REFUSED: 11329432Sbloom h_errno = NO_RECOVERY; 11429551Sbloom return(-2); 11529432Sbloom } 11629432Sbloom return (-1); 11729432Sbloom } 11829432Sbloom bp = hostbuf; 11929432Sbloom nmx = 0; 12029551Sbloom seenlocal = 0; 12129432Sbloom buflen = sizeof(hostbuf); 12229432Sbloom cp = (char *)&answer + sizeof(HEADER); 12329432Sbloom if (qdcount) { 12429432Sbloom cp += dn_skip(cp) + QFIXEDSZ; 12529432Sbloom while (--qdcount > 0) 12629432Sbloom cp += dn_skip(cp) + QFIXEDSZ; 12729432Sbloom } 12829432Sbloom while (--ancount >= 0 && cp < eom && nmx < maxmx) { 12929432Sbloom if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0) 13029432Sbloom break; 13129432Sbloom cp += n; 13229432Sbloom type = getshort(cp); 13329432Sbloom cp += sizeof(u_short); 13429551Sbloom /* 13529432Sbloom class = getshort(cp); 13629551Sbloom */ 13729432Sbloom cp += sizeof(u_short) + sizeof(u_long); 13829432Sbloom n = getshort(cp); 13929432Sbloom cp += sizeof(u_short); 14029432Sbloom if (type != T_MX) { 14129432Sbloom #ifdef DEBUG 14229432Sbloom if (tTd(8, 1) || _res.options & RES_DEBUG) 14329432Sbloom printf("unexpected answer type %d, size %d\n", 14429432Sbloom type, n); 14529432Sbloom #endif 14629432Sbloom cp += n; 14729432Sbloom continue; 14829432Sbloom } 14929432Sbloom pref = getshort(cp); 15029432Sbloom cp += sizeof(u_short); 15129432Sbloom if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0) 15229432Sbloom break; 15329551Sbloom cp += n; 15429551Sbloom if (sameword(bp, localhost)) 15529551Sbloom { 15629551Sbloom seenlocal = 1; 15729551Sbloom localpref = pref; 15829551Sbloom continue; 15929551Sbloom } 16029432Sbloom prefer[nmx] = pref; 16129432Sbloom mxhosts[nmx++] = bp; 16229432Sbloom n1 = strlen(bp)+1; 16329432Sbloom bp += n1; 16429432Sbloom buflen -= n1; 16529432Sbloom } 16629551Sbloom if (nmx == 0) { 16729551Sbloom (void) strcpy(hostbuf, host); 16829551Sbloom mxhosts[0] = hostbuf; 16929551Sbloom return(1); 17029551Sbloom } 17129432Sbloom /* sort the records */ 17229432Sbloom for (i = 0; i < nmx; i++) { 17329432Sbloom for (j = i + 1; j < nmx; j++) { 17429432Sbloom if (prefer[i] > prefer[j]) { 17529432Sbloom int temp; 17629432Sbloom char *temp1; 17729432Sbloom 17829432Sbloom temp = prefer[i]; 17929432Sbloom prefer[i] = prefer[j]; 18029432Sbloom prefer[j] = temp; 18129432Sbloom temp1 = mxhosts[i]; 18229432Sbloom mxhosts[i] = mxhosts[j]; 18329432Sbloom mxhosts[j] = temp1; 18429432Sbloom } 18529432Sbloom } 18629551Sbloom if (seenlocal && (prefer[i] >= localpref)) 18729551Sbloom { 18829551Sbloom nmx = i; 18929551Sbloom /* 19029551Sbloom * We are the first MX, might as well try delivering 19129551Sbloom * since nobody is supposed to have more info. 19229551Sbloom */ 19329551Sbloom if (nmx == 0) 19429551Sbloom { 19529551Sbloom (void) strcpy(hostbuf, host); 19629551Sbloom mxhosts[0] = hostbuf; 19729551Sbloom return(1); 19829551Sbloom } 19929551Sbloom break; 20029551Sbloom } 20129432Sbloom } 20229432Sbloom return(nmx); 20329432Sbloom } 20429653Sbloom 20529653Sbloom 20629653Sbloom getcanonname(host, hbsize) 20729653Sbloom char *host; 20829653Sbloom int hbsize; 20929653Sbloom { 21029653Sbloom 21129653Sbloom HEADER *hp; 21229653Sbloom char *eom, *cp; 21329653Sbloom querybuf buf, answer; 21429653Sbloom int n, ancount, qdcount; 21529653Sbloom u_short type; 21629653Sbloom char nbuf[BUFSIZ]; 21729653Sbloom int first; 21829653Sbloom 21929653Sbloom n = res_mkquery(QUERY, host, C_IN, T_ANY, (char *)NULL, 0, NULL, 22029653Sbloom (char *)&buf, sizeof(buf)); 22129653Sbloom if (n < 0) { 22229653Sbloom #ifdef DEBUG 22329653Sbloom if (tTd(8, 1) || _res.options & RES_DEBUG) 22429653Sbloom printf("res_mkquery failed\n"); 22529653Sbloom #endif 22629653Sbloom h_errno = NO_RECOVERY; 22729653Sbloom return; 22829653Sbloom } 22929653Sbloom n = res_send((char *)&buf, n, (char *)&answer, sizeof(answer)); 23029653Sbloom if (n < 0) { 23129653Sbloom #ifdef DEBUG 23229653Sbloom if (tTd(8, 1) || _res.options & RES_DEBUG) 23329653Sbloom printf("res_send failed\n"); 23429653Sbloom #endif 23529653Sbloom h_errno = TRY_AGAIN; 23629653Sbloom return; 23729653Sbloom } 23829653Sbloom eom = (char *)&answer + n; 23929653Sbloom /* 24029653Sbloom * find first satisfactory answer 24129653Sbloom */ 24229653Sbloom hp = (HEADER *) &answer; 24329653Sbloom ancount = ntohs(hp->ancount); 24429653Sbloom qdcount = ntohs(hp->qdcount); 24529653Sbloom /* 24629653Sbloom * We don't care about errors here, only if we got an answer 24729653Sbloom */ 24829653Sbloom if (ancount == 0) { 24929653Sbloom #ifdef DEBUG 25029653Sbloom if (tTd(8, 1) || _res.options & RES_DEBUG) 25129653Sbloom printf("rcode = %d, ancount=%d\n", hp->rcode, ancount); 25229653Sbloom #endif 25329653Sbloom return; 25429653Sbloom } 25529653Sbloom cp = (char *)&answer + sizeof(HEADER); 25629653Sbloom if (qdcount) { 25729653Sbloom cp += dn_skip(cp) + QFIXEDSZ; 25829653Sbloom while (--qdcount > 0) 25929653Sbloom cp += dn_skip(cp) + QFIXEDSZ; 26029653Sbloom } 26129653Sbloom first = 1; 26229653Sbloom while (--ancount >= 0 && cp < eom) { 26329653Sbloom if ((n = dn_expand((char *)&answer, eom, cp, nbuf, 26429653Sbloom sizeof(nbuf))) < 0) 26529653Sbloom break; 26629653Sbloom if (first) { 26729653Sbloom (void)strncpy(host, nbuf, hbsize); 26829653Sbloom host[hbsize - 1] = '\0'; 26929653Sbloom first = 0; 27029653Sbloom } 27129653Sbloom cp += n; 27229653Sbloom type = getshort(cp); 27329653Sbloom cp += sizeof(u_short); 27429653Sbloom cp += sizeof(u_short) + sizeof(u_long); 27529653Sbloom n = getshort(cp); 27629653Sbloom cp += sizeof(u_short); 27729653Sbloom if (type == T_CNAME) { 27829653Sbloom /* 27929653Sbloom * Assume that only one cname will be found. More 28029653Sbloom * than one is undefined. 28129653Sbloom */ 28229653Sbloom if ((n = dn_expand((char *)&answer, eom, cp, nbuf, 28329653Sbloom sizeof(nbuf))) < 0) 28429653Sbloom break; 28529653Sbloom (void)strncpy(host, nbuf, hbsize); 28629653Sbloom host[hbsize - 1] = '\0'; 28729653Sbloom getcanonname(host, hbsize); 28829653Sbloom break; 28929653Sbloom } 29029653Sbloom cp += n; 29129653Sbloom } 29229653Sbloom return; 29329653Sbloom } 29429551Sbloom #endif MXDOMAIN 295