/* This file is part of mailfrom filter. -*- c -*- Copyright (C) 2006 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 2, 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include MF_DEFUN(hostname, STRING, STRING string) { char *hbuf; if (resolve_ipstr(string, &hbuf) != mf_success) pushs(env, string); else { pushs(env, hbuf); free(hbuf); } } END MF_DEFUN(resolve, STRING, STRING string) { char *ipstr; if (resolve_hostname(string, &ipstr) != mf_success) pushs(env, "0"); else { pushs(env, ipstr); free(ipstr); } } END MF_DEFUN(hasmx, NUMBER, STRING string) { mxbuf_t mxbuf; mf_status mxstat; mxstat = getmx(string, mxbuf); if (mxstat != mf_success) { if (env_catch(env, mxstat) == 0) return; } else freemx(mxbuf); MF_RETURN(mxstat == mf_success); } END MF_DEFUN(getmx, STRING, STRING domain, OPTIONAL, NUMBER resolve) { mxbuf_t mxbuf; mf_status mxstat; int i; if (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; size_t ns; char *p; MF_BEGIN_TEMP_SPACE(s, size); for (i = 0, ns = 0, p = s; i < MAXMXCOUNT && mxbuf[i]; i++) { size_t len = strlen(mxbuf[i]); if (ns + len + 1 > size) break; if (i > 0) *p++ = ' '; memcpy(p, mxbuf[i], len); p += len; ns += len + 1; } *p = 0; freemx(mxbuf); MF_RETURN_TEMP_SPACE(ns); } } 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(ismx, NUMBER, STRING domain, STRING ipstr) { mxbuf_t mxbuf; mf_status mxstat; unsigned long ip; int rc = 0; MF_ASSERT(resolve_host(ipstr, &ip) == 0, mf_resolve, "cannot resolve host name %s", ipstr); mxstat = getmx(domain, mxbuf); if (mxstat != mf_success) { if (env_catch(env, mxstat) == 0) return; } else { int i; for (i = 0; i < MAXMXCOUNT && mxbuf[i]; i++) { unsigned long n; if (!resolve_host(mxbuf[i], &n) && n == ip) { rc = 1; break; } } 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) { MF_RETURN(listens_on (s, 25) == mf_success); } END MF_DEFUN(match_cidr, NUMBER, STRING ipstr, STRING cidrstr) { char *p; struct in_addr addr, cidr; char netbuf[16], *netstr; unsigned long netmask; int result = 0; const struct locus *locus = env_get_locus(env); do { MF_ASSERT(inet_aton(ipstr, &addr), mf_invip, "invalid IP address (%s)", ipstr); p = strchr(cidrstr, '/'); if (!p) { netstr = cidrstr; netmask = 0xfffffffful; } else { size_t len = p - cidrstr; unsigned long n; MF_ASSERT(len < sizeof netbuf, mf_invcidr, "invalid CIDR (%s)", cidrstr); memcpy(netbuf, cidrstr, len); netbuf[len] = 0; netstr = netbuf; n = strtoul(p + 1, &p, 10); MF_ASSERT(*p == 0 && n <= 32, mf_invcidr, "invalid CIDR (netmask of %s)", cidrstr); n = 32 - n; if (n == 32) netmask = 0; else netmask = (0xfffffffful >> n) << n; } MF_ASSERT(inet_aton(netstr, &cidr), mf_invcidr, "invalid CIDR (network part of %s)", cidrstr); addr.s_addr = ntohl(addr.s_addr); cidr.s_addr = ntohl(cidr.s_addr); debug5(100, "%s:%lu: addr=%lx net=%lx mask=%lx" , locus->file, locus->line, addr.s_addr, cidr.s_addr, netmask); result = (addr.s_addr & netmask) == cidr.s_addr; } while (0); MF_RETURN(result); } END MF_DEFUN(domainpart, STRING, STRING str) { char *p = strchr(str, '@'); MF_RETURN(p ? p+1 : str); } END MF_DEFUN(localpart, STRING, STRING str) { char *p = strchr(str, '@'); if (p) { size_t size = p - str; char *string_space = MF_ALLOC_HEAP(size + 1); memcpy(string_space, str, size); string_space[size] = 0; MF_RETURN(string_space); } else MF_RETURN_STRING(str); } END MF_INIT