/* This file is part of mailfromd. -*- c -*-
Copyright (C) 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 . */
#include
#include
#include
#include
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:%lu: resolve_hostname returned "
"invalid IP address: %s"),
__FILE__, __FILE__, 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