/* This file is part of mailfromd.
Copyright (C) 2005, 2006, 2007 Sergey Poznyakoff
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 3, 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 FITNESS 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, see . */
#define MF_SOURCE_NAME MF_SOURCE_DNS
#ifdef HAVE_CONFIG_H
# include
#endif
#include
#include
#include
#include
#include
#include
#include
#include "mailfromd.h"
mf_status
dns_to_mf_status(dns_status stat)
{
return (mf_status) stat;
}
mf_status
getmx(char *host, mxbuf_t mxbuf)
{
mf_status rc = dns_cache_get(T_MX, host, mxbuf, MAXMXCOUNT);
if (!mf_resolved(rc)) {
dns_status status;
unsigned long ttl;
size_t mxcnt;
status = dns_get_mx_records(host, 1, mxbuf, &mxcnt, &ttl);
if (status == dns_success)
dns_cache_put(T_MX, host, ttl, mxbuf, mxcnt);
else
dns_cache_put(T_MX, host, 0, NULL, 0);
rc = dns_to_mf_status(status);
}
return rc;
}
static int
comp_ipbuf(const void *a, const void *b)
{
const GACOPYZ_UINT32_T *in_a = a;
const GACOPYZ_UINT32_T *in_b = b;
if (*in_a < *in_b)
return -1;
else if (*in_a > *in_b)
return 1;
return 0;
}
mf_status
getmxip(char *host, mxbuf_t mxbuf)
{
mf_status mxstat;
GACOPYZ_UINT32_T ipbuf[MAXMXCOUNT];
size_t ipcount;
size_t i;
mxstat = getmx(host, mxbuf);
if (mxstat != mf_success)
return mxstat;
ipcount = 0;
for (i = 0; i < MAXMXCOUNT && mxbuf[i]; i++) {
size_t ipn;
mf_status stat = a_lookup(mxbuf[i],
ipbuf + ipcount,
NELEMS(ipbuf) - ipcount,
&ipn,
NULL, NULL, 0);
if (stat == mf_success) {
size_t n;
for (n = 0; ipcount < NELEMS(ipbuf) && n < ipn;
n++, ipcount++)
ipbuf[ipcount] = ntohl(ipbuf[ipcount]);
if (ipcount == NELEMS(ipbuf))
break;
}
}
dns_freemx(mxbuf);
qsort(ipbuf, ipcount, sizeof ipbuf[0], comp_ipbuf);
for (i = 0; i < ipcount; i++) {
struct in_addr s;
s.s_addr = htonl(ipbuf[i]);
mxbuf[i] = xstrdup(inet_ntoa(s));
}
if (i < MAXMXCOUNT)
mxbuf[i] = NULL;
return mf_success;
}
mf_status
resolve_ipstr_domain(const char *ipstr, const char *domain, char **phbuf)
{
mf_status status;
static unsigned char *answer;
char *hbuf;
if (!answer)
answer = xmalloc(MAXPACKET);
debug1(80,"Getting canonical name for %s", ipstr);
status = dns_cache_get(T_PTR, ipstr, &hbuf, 1);
if (status == mf_success) {
debug2(80, "%s resolved to %s (cached value)", ipstr, hbuf);
*phbuf = hbuf;
} else if (status == mf_not_found) {
debug1(80, "%s not resolved", ipstr);
} else {
unsigned long ttl;
char buffer[256];
dns_status dstat;
dstat = dns_resolve_ipstr(ipstr, domain, answer, MAXPACKET,
buffer, sizeof buffer, &ttl);
switch (dstat) {
case dns_success:
debug2(80, "%s resolved to %s", ipstr, buffer);
*phbuf = xstrdup(buffer);
dns_cache_put(T_PTR, ipstr, ttl, phbuf, 1);
break;
case dns_not_found:
dns_cache_put(T_PTR, ipstr, 0, NULL, 0);
default:
debug1(80, "%s not resolved", ipstr);
}
status = dns_to_mf_status(dstat);
}
return status;
}
mf_status
resolve_ipstr(const char *ipstr, char **phbuf)
{
return resolve_ipstr_domain(ipstr, NULL, phbuf);
}
mf_status
resolve_hostname(const char *host, char **pipbuf)
{
mf_status status;
static unsigned char *answer;
char buffer[256];
char *ipbuf;
if (!answer)
answer = malloc(MAXPACKET);
debug1(80,"Getting IP address for %s", host);
status = dns_cache_get(T_A, host, &ipbuf, 1);
if (status == mf_success) {
debug2(80, "%s resolved to %s (cached value)", host, ipbuf);
*pipbuf = ipbuf;
} else if (status == mf_not_found) {
debug1(80, "%s not resolved (cached value)", host);
} else {
unsigned long ttl;
char *tmphost = xstrdup(host);
dns_status dstat;
dstat = dns_resolve_hostname(tmphost, answer, MAXPACKET,
buffer, sizeof buffer,
&ttl);
free(tmphost);
switch (dstat) {
case dns_success:
ipbuf = xstrdup(buffer);
debug2(80, "%s resolved to %s", host, ipbuf);
*pipbuf = ipbuf;
dns_cache_put(T_A, host, ttl, &ipbuf, 1);
break;
case dns_not_found:
dns_cache_put(T_A, host, 0, NULL, 0);
default:
debug1(80, "%s not resolved", host);
}
status = dns_to_mf_status(dstat);
}
return status;
}