/*
**
** 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 <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>
#include <sys/socket.h>
#include <netdb.h>
#include <errno.h>
#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
syntax highlighted by Code2HTML, v. 0.9.1