aboutsummaryrefslogtreecommitdiff
path: root/mflib
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2007-03-18 11:09:25 +0000
committerSergey Poznyakoff <gray@gnu.org.ua>2007-03-18 11:09:25 +0000
commitccef20a48e758594256dbfa246dc6c4bcffc9003 (patch)
tree3c4ada7f4b3096ef564d8c8ba8dfe8db2002fc81 /mflib
parentec1605d16b925c61f6046760af5eb95e02da2f2a (diff)
downloadmailfromd-ccef20a48e758594256dbfa246dc6c4bcffc9003.tar.gz
mailfromd-ccef20a48e758594256dbfa246dc6c4bcffc9003.tar.bz2
* configure.ac, Makefile.am: Add mflib
* NEWS: Update * mflib: New subdirectory * mflib/match_dnsbl.mf, mflib/strip_domain_part.mf, mflib/heloarg_test.mf, mflib/is_ip.mf, mflib/safedb.mf, mflib/mx.mf, mflib/dns.mf, mflib/revip.mf, mflib/valid_domain.mf, mflib/match_rhsbl.mf, mflib/spf.mf, mflib/Makefile.am, mflib/match_cidr.mf: New files * doc/Makefile.am: Remove extract.awk * doc/extract.awk: Remove * doc/mailfromd.texi: Update * src/symtab.c, src/gram.y, src/mailfromd.h: Implement optional arguments for user functions * src/lex.l: Implement #include_once * src/prog.c (name_destroy): Free the object * src/bi_ipaddr.m4 (match_cidr): Remove. The function is implemented in MFL (mflib/match_cidr.mf) * testsuite/lib/mailfromd.exp, testsuite/etc/cidr.rc, testsuite/etc/catch.rc, testsuite/etc/catch01.rc, etc/mailfromd.rc: Use includes when necessary git-svn-id: file:///svnroot/mailfromd/trunk@1292 7a8a7f39-df28-0410-adc6-e0d955640f24
Diffstat (limited to 'mflib')
-rw-r--r--mflib/Makefile.am32
-rw-r--r--mflib/dns.mf57
-rw-r--r--mflib/heloarg_test.mf127
-rw-r--r--mflib/is_ip.mf34
-rw-r--r--mflib/match_cidr.mf32
-rw-r--r--mflib/match_dnsbl.mf78
-rw-r--r--mflib/match_rhsbl.mf55
-rw-r--r--mflib/mx.mf88
-rw-r--r--mflib/revip.mf34
-rw-r--r--mflib/safedb.mf38
-rw-r--r--mflib/spf.mf122
-rw-r--r--mflib/strip_domain_part.mf40
-rw-r--r--mflib/valid_domain.mf30
13 files changed, 767 insertions, 0 deletions
diff --git a/mflib/Makefile.am b/mflib/Makefile.am
new file mode 100644
index 00000000..75bb1ece
--- /dev/null
+++ b/mflib/Makefile.am
@@ -0,0 +1,32 @@
+# This file is part of mailfromd.
+# Copyright (C) 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 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
+
+incdir=$(pkgdatadir)/$(VERSION)/include
+inc_DATA =\
+ dns.mf\
+ heloarg_test.mf\
+ is_ip.mf\
+ match_cidr.mf\
+ match_dnsbl.mf\
+ match_rhsbl.mf\
+ mx.mf\
+ revip.mf\
+ safedb.mf\
+ spf.mf\
+ strip_domain_part.mf\
+ valid_domain.mf
diff --git a/mflib/dns.mf b/mflib/dns.mf
new file mode 100644
index 00000000..00dcdc58
--- /dev/null
+++ b/mflib/dns.mf
@@ -0,0 +1,57 @@
+/* User-level DNS functions
+ Copyright (C) 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 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 */
+
+func hostname (string ipstr) returns string
+do
+ catch *
+ do
+ return %ipstr
+ done
+ return primitive_hostname(%ipstr)
+done
+
+func resolve (string str; string domain) returns string
+do
+ catch *
+ do
+ return "0"
+ done
+ if %domain == ""
+ return primitive_resolve (%str)
+ else
+ return primitive_resolve (%str, %domain)
+ fi
+done
+
+func hasmx (string str) returns string
+do
+ catch *
+ do
+ return 0
+ done
+ return primitive_hasmx(%str)
+done
+
+func ismx (string domain, string ipstr) returns number
+do
+ catch *
+ do
+ return 0
+ done
+ return primitive_ismx (%domain, %ipstr)
+done
diff --git a/mflib/heloarg_test.mf b/mflib/heloarg_test.mf
new file mode 100644
index 00000000..80b713eb
--- /dev/null
+++ b/mflib/heloarg_test.mf
@@ -0,0 +1,127 @@
+/* HELO consistency checker
+ Copyright (C) 2006, 2007 Jan Rafaj
+
+ 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 */
+
+# number heloarg_test (string ARG, string REMOTE_IP, string LOCAL_IP)
+#
+# Verify if an argument of `HELO' (`EHLO') command is
+# valid. Arguments:
+#
+# ARG
+# `HELO' (`EHLO') argument. Typically, the value of $s
+# Sendmail macro;
+#
+# REMOTE_IP
+# IP address of the remote clinet. Typically, the value of
+# $client_addr Sendmail macro;
+#
+# LOCAL_IP
+# IP address of this SMTP server;
+#
+# If ARG passes all tests, the function returns `0'.
+# Otherwise it returns a numeric error code. Increasing error codes
+# correspond to increased strictness level of the performed check, as
+# shown in the table below:
+#
+#
+# Code Meaning
+# ---------------------------------------------------------------------
+# 1 ARG is our IP address.
+# 2 ARG is an IP, but it does not match the remote party IP address.
+# 3 ARG is an IP, but it does not resolve.
+# 4 ARG is in square brackets, but it is not an IP address.
+# 5 ARG is not an IP address and does not resolve to one.
+# 6 ARG resolves to our server IP.
+# 7 ARG does not resolve to the remote client IP address,
+#
+#pragma regex +extended
+#include_once "is_ip.mf"
+#include_once "dns.mf"
+
+const HELO_SUCCESS 0
+const HELO_MYIP 1 # ARG is our IP address.
+const HELO_IPNOMATCH 2 # ARG is an IP, but it does not match the remote
+ # party IP address.
+const HELO_ARGNORESOLVE 3 # ARG is an IP, but it does not resolve.
+const HELO_ARGNOIP 4 # ARG is in square brackets, but it is not an
+ # IP address.
+const HELO_ARGINVALID 5 # ARG is not an IP address and does not resolve
+ # to one.
+const HELO_MYSERVERIP 6 # ARG resolves to our server IP.
+const HELO_IPMISMATCH 7 # ARG does not resolve to the remote client
+ # IP address,
+
+func domainof(string arg) returns string
+do
+ if %arg matches '[^.]+\.(.*)'
+ return \1
+ else
+ return %arg
+ fi
+done
+
+func heloarg_test(string arg, string remote_ip, string local_ip)
+ returns number
+do
+ string helo_arg
+ number heloarg_must_be_ip
+
+ set helo_arg %arg
+ set heloarg_must_be_ip 0
+
+ if %arg matches '^\[(.*)\]$'
+ set helo_arg "\1"
+ set heloarg_must_be_ip 1
+ fi
+
+ if is_ip (%helo_arg)
+ if (%helo_arg = %local_ip and %local_ip != %remote_ip)
+ # `HELO' arg may not be this server's IP
+ return HELO_MYIP
+ elif %helo_arg != %remote_ip
+ # `HELO' arg does not match remote server's IP
+ return HELO_IPNOMATCH
+ elif (%heloarg_must_be_ip = 0
+ and hostname %helo_arg = %helo_arg)
+ # `HELO' arg not in brackets and doesnt resolve
+ return HELO_ARGNORESOLVE
+ else
+ return HELO_SUCCESS
+ fi
+ elif %heloarg_must_be_ip = 1
+ # `HELO' arg in brackets is not an IP
+ return HELO_ARGNOIP
+ elif ismx(%helo_arg, %remote_ip)
+ or domainof(hostname(%remote_ip)) = %helo_arg
+ return HELO_SUCCESS
+ elif (resolve %helo_arg = "0")
+ # `HELO' arg does not resolve to an IP
+ return HELO_ARGINVALID
+ elif (%helo_arg = hostname %local_ip
+ and %local_ip != %remote_ip)
+ # `HELO' arg may not be this server's hostname
+ return HELO_MYSERVERIP
+ elif (resolve %helo_arg != %remote_ip
+ and hostname %remote_ip != %helo_arg)
+ # `HELO' arg does not resolve to remote server's IP nor to its
+ # domain
+ return HELO_IPMISMATCH
+ else
+ return HELO_SUCCESS
+ fi
+done
+
diff --git a/mflib/is_ip.mf b/mflib/is_ip.mf
new file mode 100644
index 00000000..9684be39
--- /dev/null
+++ b/mflib/is_ip.mf
@@ -0,0 +1,34 @@
+/* IP validity checker.
+ Copyright (C) 2006, 2007 Jan Rafaj
+
+ 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 */
+
+# boolean is_ip (string STR)
+#
+# Returns `true' if STR is a valid IPv4 address. For
+# example:
+#
+# is_ip("1.2.3.4") => 1
+# is_ip("1.2.3.x") => 0
+# is_ip("blah") => 0
+# is_ip("255.255.255.255") => 1
+# is_ip("0.0.0.0") => 1
+#
+#pragma regex +extended
+func is_ip(string ip) returns number
+do
+ return %ip matches '^([0-9]{1,3}\.){3}[0-9]{1,3}$'
+done
diff --git a/mflib/match_cidr.mf b/mflib/match_cidr.mf
new file mode 100644
index 00000000..94541c26
--- /dev/null
+++ b/mflib/match_cidr.mf
@@ -0,0 +1,32 @@
+/* Implementation of match_cidr call
+ Copyright (C) 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 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_once "status.mfh"
+#pragma regex +extended
+
+func match_cidr(string ipstr, string cidr) returns number
+do
+ number netmask
+
+ if %cidr matches '^(([0-9]{1,3}\.){3}[0-9]{1,3})/([0-9][0-9]?)'
+ return inet_aton(%ipstr) & len_to_netmask(\3) = inet_aton(\1)
+ else
+ throw invcidr "invalid CIDR (%cidr)"
+ fi
+ return 0
+done
diff --git a/mflib/match_dnsbl.mf b/mflib/match_dnsbl.mf
new file mode 100644
index 00000000..6578f759
--- /dev/null
+++ b/mflib/match_dnsbl.mf
@@ -0,0 +1,78 @@
+/* DNSBL checker.
+ Copyright (C) 2006, 2007 Jan Rafaj
+
+ 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 */
+
+# boolean match_dnsbl (string ADDRESS, string ZONE, string RANGE)
+#
+# This function looks up the ADDRESS in the DNS
+# blacklist zone ZONE and checks if the return matches
+# given RANGE of IP addresses.
+#
+# It is intended as a replacement for the Sendmail macros `dnsbl' and
+# `enhdnsbl'.
+#
+# Arguments:
+#
+# ADDRESS
+# IP address of the SMTP server to be tested.
+#
+# ZONE
+# FQDN of the DNSbl zone to test against.
+#
+# RANGE
+# The range of IP addresses in CIDR notation or
+# the word `ANY', which stands for `127.0.0.0/8'.
+#
+# The function returns true if dns lookup for ADDRESS in
+# the zone DNSBL yields an IP that falls within the range,
+# specified by CIDR. Otherwise, it returns false. If
+# any of ADDRESS or CIDR is invalid, match_dnsbl
+# returns false.
+#
+#include_once "dns.mf"
+#include_once "match_cidr.mf"
+
+#pragma regex +extended
+
+func match_dnsbl(string address, string zone, string range)
+ returns number
+do
+ string rbl_ip
+ if %range = 'ANY'
+ set rbl_ip '127.0.0.0/8'
+ else
+ set rbl_ip %range
+ if not %range matches '^([0-9]{1,3}\.){3}[0-9]{1,3}$'
+ return 0
+ fi
+ fi
+
+ if not (%address matches '^([0-9]{1,3}\.){3}[0-9]{1,3}$'
+ and %address != %range)
+ return 0
+ fi
+
+ if %address matches
+ '^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$'
+ if match_cidr (resolve ("\4.\3.\2.\1", %zone), %rbl_ip)
+ return 1
+ else
+ return 0
+ fi
+ fi
+ # never reached
+done
diff --git a/mflib/match_rhsbl.mf b/mflib/match_rhsbl.mf
new file mode 100644
index 00000000..92816f5b
--- /dev/null
+++ b/mflib/match_rhsbl.mf
@@ -0,0 +1,55 @@
+/* RHSBL checker.
+ Copyright (C) 2006, 2007 Jan Rafaj
+
+ 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 */
+
+# boolean match_rhsbl (string EMAIL, string ZONE, string RANGE)
+#
+# This function checks if the IP address, corresponding to the domain
+# part of EMAIL is listed in the RHS DNS blacklist zone
+# ZONE, and if so, whether its record matches the given range of
+# IP addresses RANGE.
+#
+# It is intended as a replacement for the Sendmail macro `rhsbl'
+# by Derek J. Balling.
+#
+# Arguments:
+#
+# EMAIL
+# E-mail address, whose domain name should be tested (usually, it is
+# $f)
+#
+# ZONE
+# Domain name of the RHS DNS blacklist zone.
+#
+# RANGE
+# The range of IP addresses in CIDR notation.
+#
+
+#include_once "dns.mf"
+#include_once "match_cidr.mf"
+
+#pragma regex +extended
+func match_rhsbl(string email, string zone, string range)
+ returns number
+do
+ if not (%email matches '@.+$'
+ and %range matches '^([0-9]{1,3}\.){3}[0-9]{1,3}$')
+ return 0
+ fi
+
+ return match_cidr (resolve ((domainpart %email), %zone), %range)
+done
diff --git a/mflib/mx.mf b/mflib/mx.mf
new file mode 100644
index 00000000..509e8d29
--- /dev/null
+++ b/mflib/mx.mf
@@ -0,0 +1,88 @@
+/* MX functions.
+ Copyright (C) 2006, 2007 Jan Rafaj
+
+ 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 */
+
+# string mxof (string DOMAIN)
+#
+# DOMAIN : domain name to find MX servers for
+#
+# The function returns a string of MX server names for a domain sorted by
+# their preference and name. The names in the list are separated by a
+# a single space. If domain has no MX servers, empty string is returned.
+# Examples:
+#
+# prerequisities used in examples:
+# 1) domain "mafra.cz" with following MXes:
+# 10 smtp2.mafra.cz
+# 20 relay.iol.cz
+# 10 smtp1.mafra.cz
+# 2) domain "idnes.cz" with following MXes:
+# 20 relay.iol.cz
+# 10 smtp1.mafra.cz
+# 10 smtp2.mafra.cz
+# 3) domain "gnu.org" with following MXes:
+# 10 mx10.gnu.org
+# 20 mx20.gnu.org
+# 4) domain "org.pl" without MXes
+#
+# mxof("mafra.cz") => "smtp1.mafra.cz smtp2.mafra.cz relay.iol.cz"
+# mxof("idnes.cz") => "smtp1.mafra.cz smtp2.mafra.cz relay.iol.cz"
+# mxof("gnu.org") => "mx10.gnu.org mx20.gnu.org"
+# mxof("org.pl") => ""
+#
+# Returns: single space-separated string consisting of MX servers for given
+# domain. Servers are sorted according to their name and priority
+# (in this order). If a domain has no MX servers, empty string
+# is returned.
+# Remark: due to current limitations in mailfromd, the variable "db" below
+# has to be set to point to the same "dns" format database file,
+# that has bee configured using '#pragma database dns file' option.
+
+#include_once "dns.mf"
+
+# TODO for Sergey: predefined variable as counterpart mirroring setup
+# of '#pragma database dns file' would suffice here.
+# I really hate to have basic config. parameters scattered
+# around this way (see comment above 'set db' below).
+set db "/var/run/mailfromd/dns.db"
+
+func mxof(string domain) returns s
+do
+ set dumb hasmx $1 # assure %db is populated with MX records
+ set mxservers ""
+ if dbget(%db, "MX " %domain, "", 1) matches '^[0-9]+ (.*)'
+ set mxservers "\1"
+ fi
+ return %mxservers
+done
+
+# number has_same_mx(string DOMAIN1, string DOMAIN2)
+# Returns true, if domains DOMAIN1 and DOMAIN2 share exactly the same
+# MX servers. Otherwise, false is returned.
+# Examples:
+#
+# prerequisities used in examples:
+# (the same as in case of 'mxof()' function above)
+#
+# has_same_mx("mafra.cz", "idnes.cz") => 1
+# has_same_mx("gnu.org", "idnes.cz") => 0
+# has_same_mx("gnu.org", "org.pl") => 0
+#
+func has_same_mx(string domain1, string domain2) returns n
+do
+ return (mxof $1 = mxof $2)
+done
diff --git a/mflib/revip.mf b/mflib/revip.mf
new file mode 100644
index 00000000..bf1cae8f
--- /dev/null
+++ b/mflib/revip.mf
@@ -0,0 +1,34 @@
+/* Reverse IP address.
+ Copyright (C) 2006, 2007 Jan Rafaj, 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 */
+
+# string revip (string IP)
+#
+# Reverses octets in IP.
+#
+# Example:
+#
+# revip("127.0.0.1") => "1.0.0.127"
+#
+#pragma regex +extended
+func revip(string ip) returns string
+do
+ if %ip matches '([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)'
+ return "\4.\3.\2.\1"
+ fi
+ return %ip
+done
diff --git a/mflib/safedb.mf b/mflib/safedb.mf
new file mode 100644
index 00000000..3ed6babb
--- /dev/null
+++ b/mflib/safedb.mf
@@ -0,0 +1,38 @@
+/* Safe DB I/O
+ Copyright (C) 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 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_once <status.mfh>
+
+func safedbget(string name, string key) returns string
+do
+ catch dbfailure
+ do
+ return ""
+ done
+ return dbget(%name, %key)
+done
+
+func safedbput(string name, string key, string value)
+do
+ catch dbfailure
+ do
+ return
+ done
+ dbput(%name, %key, %value)
+done
+
diff --git a/mflib/spf.mf b/mflib/spf.mf
new file mode 100644
index 00000000..99e33534
--- /dev/null
+++ b/mflib/spf.mf
@@ -0,0 +1,122 @@
+/* Cached SPF interface.
+ Copyright (C) 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 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_once "safedb.mf"
+#pragma regex +extended +icase
+
+set spf_database "%__statedir__/spf.db"
+set spf_negative_ttl interval("1 day")
+number spf_cached 0
+
+const None 0
+const Neutral 1
+const Pass 2
+const Fail 3
+const SoftFail 4
+const TempError 5
+const PermError 6
+
+func spf_status_string(number code) returns string
+do
+ switch %code
+ do
+ case None: return "None"
+ case Neutral: return "Neutral"
+ case Pass: return "Pass"
+ case Fail: return "Fail"
+ case SoftFail: return "SoftFail"
+ case TempError: return "TempError"
+ case PermError: return "PermError"
+ done
+ return "UNKNOWN (" %code ")"
+done
+
+func spf_get_cache(string ip, string domain, string sender)
+ returns number
+do
+ string record safedbget(%spf_database, "%ip-%domain-%sender")
+ number timestamp
+ number ttl
+ number result
+
+ if %record = ""
+ set result -1
+ elif %record matches '([^ ]+) ([^ ]+) <(.*)> <(.*)>'
+ set timestamp \1
+ if time() >= %timestamp
+ echo "$i: CLEARING record %record"
+ set result -1
+ else
+ set result \2
+ set spf_mechanism \3
+ set spf_explanation \4
+ fi
+ else
+ echo "$i: ERROR: Malformed DB line: %record"
+ set result -1
+ fi
+ return %result
+done
+
+func spf_put_cache(number result, string ip, string domain, string sender)
+do
+ safedbput(%spf_database, "%ip-%domain-%sender",
+ (time() + %spf_ttl)
+ " %result <%spf_mechanism> <%spf_explanation>")
+done
+
+func spf_log(number result, string ip, string domain, string sender)
+do
+ string logmsg "SPF check_host(%ip, %domain, %sender) = "
+ spf_status_string(%result)
+ if %spf_cached
+ set logmsg %logmsg " [CACHED]"
+ fi
+ if %spf_mechanism != ""
+ set logmsg %logmsg
+ "; matching mechanism \"%spf_mechanism\""
+ fi
+ if %spf_explanation != ""
+ set logmsg %logmsg
+ "; %spf_explanation"
+ fi
+ echo "$i: %logmsg"
+done
+
+func check_host(string ip, string domain, string sender, string helo)
+ returns number
+do
+ number result spf_get_cache(%ip, %domain, %sender)
+
+ if %result == -1
+ set result spf_check_host(%ip, %domain, %sender, %helo,
+ %ehlo_domain)
+ set spf_cached 0
+
+ if %result = None
+ set spf_ttl %spf_negative_ttl
+ fi
+ spf_put_cache(%result, %ip, %domain, %sender)
+ else
+ set spf_cached 1
+ fi
+ spf_log(%result, %ip, %domain, %sender)
+ return %result
+done
+
+
diff --git a/mflib/strip_domain_part.mf b/mflib/strip_domain_part.mf
new file mode 100644
index 00000000..82c7c89f
--- /dev/null
+++ b/mflib/strip_domain_part.mf
@@ -0,0 +1,40 @@
+/* Strip domain part from an email address.
+ Copyright (C) 2006, 2007 Jan Rafaj
+
+ 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 */
+
+# string strip_domain_part (string DOMAIN, number N)
+#
+# Returns at most N last components of the domain name DOMAIN.
+# If N is 0 the function is equivalent to domainpart.
+#
+# Examples:
+#
+# strip_domain_part("puszcza.gnu.org.ua", 2) => "org.ua"
+# strip_domain_part("puszcza.gnu.org.ua", 0) => "gnu.org.ua"
+#
+#pragma regex +extended
+
+func strip_domain_part(string domain, number n) returns string
+do
+ if %n = 0
+ return domainpart %domain
+ elif domainpart(%domain) matches '.*((\.[^.]+){' $2 '})'
+ return substring(\1, 1, -1)
+ else
+ return %domain
+ fi
+done
diff --git a/mflib/valid_domain.mf b/mflib/valid_domain.mf
new file mode 100644
index 00000000..bb49e924
--- /dev/null
+++ b/mflib/valid_domain.mf
@@ -0,0 +1,30 @@
+/* Domain name validation.
+ Copyright (C) 2006, 2007 Jan Rafaj
+
+ 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_once "dns.mf"
+
+# boolean valid_domain (string DOMAIN)
+#
+# Returns true if the domain name DOMAIN has a
+# corresponding A record or if it has any MX records, that is if it can
+# be possible to send mail to it.
+#
+func valid_domain(string domain) returns number
+do
+ return not (resolve(%domain) = "0" and not hasmx(%domain))
+done

Return to:

Send suggestions and report system problems to the System administrator.