/* 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; }