/* ** ** Copyright (C) 1993 Swedish University Network (SUNET) ** ** ** This program is developed by UDAC, Uppsala University by commission ** of the Swedish University Network (SUNET). ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITTNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** ** ** Martin.Wendel@its.uu.se ** Torbjorn.Wictorin@its.uu.se ** ** ITS ** P.O. Box 887 ** S-751 08 Uppsala ** Sweden ** */ #include "emil.h" #include #include #include #include #include #include #ifdef PACKETSZ #define MAXPACKET PACKETSZ #else #define MAXPACKET 1024 #endif #ifdef NAMED_BIND #ifdef HAVE_RES_SEARCH typedef union { HEADER hdr; u_char buf[MAXPACKET]; } querybuf; struct mxlist * get_mx(char *dname) { querybuf answer; register HEADER *hp; register u_char *cp; register int n; u_char *eom; char *bp; char hostbuf[BUFSIZ + 1]; int type, class, buflen, ancount, qdcount; int lpreference, preference; int anslen; struct mxlist *list, *tlist, *wlist; type = T_MX; list = NULL; if ((_res.options & RES_INIT) == 0 && res_init() == -1) { fprintf(stderr, "Emil SMTP: res_init(): Check /etc/resolv.conf"); return(NULL); } if ((anslen = res_search(dname, C_IN, type, answer.buf, sizeof(answer))) < 0) { switch (errno) { case TRY_AGAIN: exit(EX_TEMPFAIL); break; default: /* MX lookup failed */ return(NULL); break; } } eom = answer.buf + anslen; lpreference = -1; /* Set lowest preference unset */ /* * find satisfactory answer */ hp = &answer.hdr; ancount = ntohs(hp->ancount); qdcount = ntohs(hp->qdcount); bp = hostbuf; buflen = sizeof(hostbuf); cp = answer.buf + sizeof(HEADER); /* * Skipping over question entries */ if (qdcount) { cp += dn_skipname(cp, eom) + QFIXEDSZ; while ( --qdcount > 0) cp += dn_skipname(cp, eom) + QFIXEDSZ; } /* * Extracting hostnames from answer entries */ while (--ancount >= 0 && cp < eom) { if ((n = dn_expand((char *)answer.buf, eom, cp, bp, buflen)) < 0) { break; } cp += n; type = _getshort(cp); if (type == T_MX) { cp += sizeof(u_short); class = _getshort(cp); cp += sizeof(u_short) + sizeof(u_long); cp += sizeof(u_short); /* MX RDATA */ preference = _getshort(cp); cp += sizeof(u_short); if ((n = dn_expand((char *)answer.buf, eom, cp, bp, buflen)) < 0) { break; } tlist = (struct mxlist *)Yalloc(sizeof(struct mxlist)); tlist->host = NEWSTR(bp); tlist->preference = preference; if (list == NULL || preference < lpreference) { lpreference = preference; tlist->next = list; list = tlist; } else { /* Sort by preference */ for (wlist = list; wlist->next != NULL; wlist = wlist->next) if (wlist->next->preference > preference) break; tlist->next = wlist->next; wlist->next = tlist; } cp += n; } } if (list == NULL) return(NULL); #ifdef DEBUG if (edebug) for (wlist = list; wlist != NULL; wlist = wlist->next) fprintf(stderr, "Emil MX: %s preference %d\n", wlist->host, wlist->preference); #endif /* Removing localhost and lower preferences */ if (cmatch(list->host, SMTPHOSTNAME)) list = NULL; else for (wlist = list; wlist->next != NULL; wlist = wlist->next) if (cmatch(wlist->next->host, SMTPHOSTNAME)) { wlist->next = NULL; break; } return(list); } #endif #endif