diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2008-02-10 14:08:36 +0000 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2008-02-10 14:08:36 +0000 |
commit | a1871918823166cac9f0c12164ba27cb3b1f0c2c (patch) | |
tree | 7260d118aa5af6a8f006f9b2dac6cabde782db8c /mfd/bi_dns.m4 | |
parent | 455b645247bdc0f01239b2352a9d8f07f446024f (diff) | |
download | mailfromd-a1871918823166cac9f0c12164ba27cb3b1f0c2c.tar.gz mailfromd-a1871918823166cac9f0c12164ba27cb3b1f0c2c.tar.bz2 |
Merged HEAD from branches/gmach
git-svn-id: file:///svnroot/mailfromd/trunk@1612 7a8a7f39-df28-0410-adc6-e0d955640f24
Diffstat (limited to 'mfd/bi_dns.m4')
-rw-r--r-- | mfd/bi_dns.m4 | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/mfd/bi_dns.m4 b/mfd/bi_dns.m4 new file mode 100644 index 00000000..6ca93d17 --- /dev/null +++ b/mfd/bi_dns.m4 @@ -0,0 +1,297 @@ +/* This file is part of Mailfromd. -*- c -*- + Copyright (C) 2006, 2007, 2008 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 <http://www.gnu.org/licenses/>. */ + +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> +#include <arpa/inet.h> + +MF_DEFUN(primitive_hostname, STRING, STRING string) +{ + char *hbuf; + mf_status stat; + + stat = resolve_ipstr(string, &hbuf); + MF_ASSERT(stat == mf_success, + stat, + _("Cannot resolve IP %s"), + string); + + pushs(env, hbuf); + free(hbuf); +} +END + +MF_DEFUN(primitive_resolve, STRING, STRING string, OPTIONAL, STRING domain) +{ + char *ipstr; + mf_status stat; + + if (MF_OPTVAL(domain,"")[0]) { + stat = resolve_ipstr_domain(string, domain, &ipstr); + MF_ASSERT(stat == mf_success, + stat, + _("Cannot resolve %s.%s"), string, domain); + } else { + stat = resolve_hostname(string, &ipstr); + MF_ASSERT(stat == mf_success, + stat, + _("Cannot resolve %s"), string); + } + pushs(env, ipstr); + free(ipstr); +} +END + +static int +ipaddr_cmp(const void *a, const void *b) +{ + GACOPYZ_UINT32_T ipa = ntohl(*(GACOPYZ_UINT32_T*)a); + GACOPYZ_UINT32_T ipb = ntohl(*(GACOPYZ_UINT32_T*)b); + if (ipa < ipb) + return -1; + if (ipa > ipb) + return 1; + return 0; +} + +MF_DEFUN(dns_getaddr, STRING, STRING string) +{ + GACOPYZ_UINT32_T ipbuf[64]; /* FIXME: arbitrary limit */ + size_t i, ipcount; + unsigned long ttl; + dns_status dnstat; + + dnstat = a_lookup(string, ipbuf, NELEMS(ipbuf), &ipcount, + &ttl, NULL, 0); + switch (dnstat) { + case dns_success: { + MF_OBSTACK_BEGIN(); + qsort(ipbuf, ipcount, sizeof ipbuf[0], ipaddr_cmp); + for (i = 0; i < ipcount; i++) { + struct in_addr addr; + char *q; + + addr.s_addr = ipbuf[i]; + q = inet_ntoa(addr); + if (i > 0) + MF_OBSTACK_1GROW(' '); + MF_OBSTACK_GROW(q); + } + MF_OBSTACK_1GROW(0); + MF_RETURN_OBSTACK(); + } + case dns_not_found: + MF_RETURN_STRING(""); + default: + MF_THROW(dns_to_mf_status(dnstat), + _("Failed to get A record for %s"), string); + } +} +END + +static int +hostname_cmp(const void *a, const void *b) +{ + return strcmp(*(const char**) a, *(const char**) b); +} + +MF_DEFUN(dns_getname, STRING, STRING ipstr) +{ + dns_status dnstat; + struct in_addr addr; + unsigned long ttl; + char *names[64]; + + MF_ASSERT(inet_aton(ipstr, &addr), + mf_invip, + _("Invalid IP: %s"), ipstr); + + dnstat = ptr_lookup(addr, names, NELEMS(names), &ttl, NULL, 0); + switch (dnstat) { + case dns_success: { + size_t i; + size_t ncount; + + for (ncount = 0; ncount < NELEMS(names) && names[ncount]; + ncount++); + + qsort(names, ncount, sizeof names[0], hostname_cmp); + + for (i = 0; i < ncount; i++) { + if (i > 0) + MF_OBSTACK_1GROW(' '); + MF_OBSTACK_GROW(names[i]); + } + MF_OBSTACK_1GROW(0); + + for (; i < ncount; i++) + free(names[i]); + + MF_RETURN_OBSTACK(); + } + case dns_not_found: + MF_RETURN_STRING(""); + default: + MF_THROW(dns_to_mf_status(dnstat), + _("Failed to get PTR record for %s"), ipstr); + } +} +END + +MF_DEFUN(primitive_hasmx, NUMBER, STRING string) +{ + mxbuf_t mxbuf; + mf_status mxstat; + + mxstat = getmx(string, mxbuf); + + MF_ASSERT(mxstat == mf_success || mxstat == mf_not_found, + mxstat, + _("Cannot get MX records for %s"), + string); + + if (mxstat == mf_success) { + dns_freemx(mxbuf); + MF_RETURN(1); + } + MF_RETURN(0); +} +END + +MF_DEFUN(getmx, STRING, STRING domain, OPTIONAL, NUMBER resolve) +{ + mxbuf_t mxbuf; + mf_status mxstat; + + if (MF_OPTVAL(resolve)) + mxstat = getmxip(domain, mxbuf); + else + mxstat = getmx(domain, mxbuf); + MF_ASSERT(mxstat == mf_success || mxstat == mf_not_found, + mxstat, + _("Cannot get MX records for %s"), domain); + if (mxstat == mf_not_found) + MF_RETURN_STRING(""); + else { + int i; + + MF_OBSTACK_BEGIN(); + for (i = 0; i < MAXMXCOUNT && mxbuf[i]; i++) { + if (i > 0) + MF_OBSTACK_1GROW(' '); + MF_OBSTACK_GROW(mxbuf[i]); + } + MF_OBSTACK_1GROW(0); + dns_freemx(mxbuf); + MF_RETURN_OBSTACK(); + } +} +END + +static int +resolve_host(const char *string, unsigned long *ip) +{ + int rc; + struct in_addr addr; + char *ipstr; + + if (inet_aton(string, &addr)) { + *ip = addr.s_addr; + return 0; + } + + if (resolve_hostname(string, &ipstr) != mf_success) + return 1; + + rc = inet_aton(ipstr, &addr); + free(ipstr); + if (rc == 0) { + mu_error(_("INTERNAL ERROR at %s:%d: resolve_hostname returned " + "invalid IP address: %s"), + __FILE__, __LINE__, ipstr); + return 1; + } + *ip = addr.s_addr; + return 0; +} + +MF_DEFUN(primitive_ismx, NUMBER, STRING domain, STRING ipstr) +{ + mxbuf_t mxbuf; + mf_status mxstat; + unsigned long ip; + int rc = 0; + int i; + + MF_ASSERT(resolve_host(ipstr, &ip) == 0, mf_noresolve, + _("Cannot resolve host name %s"), ipstr); + + mxstat = getmx(domain, mxbuf); + + MF_ASSERT(mxstat == mf_success, + mxstat, + _("Cannot get MXs for %s"), domain); + + for (i = 0; i < MAXMXCOUNT && mxbuf[i]; i++) { + unsigned long n; + + if (!resolve_host(mxbuf[i], &n) && n == ip) { + rc = 1; + break; + } + } + dns_freemx(mxbuf); + MF_RETURN(rc); +} +END + +MF_DEFUN(relayed, NUMBER, STRING s) +{ + MF_RETURN(relayed_domain_p(s)); +} +END + +MF_DEFUN(listens, NUMBER, STRING s, OPTIONAL, NUMBER port) +{ + MF_RETURN(listens_on (s, MF_OPTVAL(port, 25)) == mf_success); +} +END + +MF_DEFUN(domainpart, STRING, STRING str) +{ + char *p = strchr(str, '@'); + MF_RETURN_STRING(p ? p+1 : str); +} +END + +MF_DEFUN(localpart, STRING, STRING str) +{ + char *p = strchr(str, '@'); + + if (p) { + size_t off; + size_t size = p - str; + char *string_space = MF_ALLOC_HEAP(off, size + 1); + memcpy(string_space, str, size); + string_space[size] = 0; + MF_RETURN(off); + } else + MF_RETURN_STRING(str); +} +END + +MF_INIT |