diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2007-03-18 11:09:25 +0000 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2007-03-18 11:09:25 +0000 |
commit | ccef20a48e758594256dbfa246dc6c4bcffc9003 (patch) | |
tree | 3c4ada7f4b3096ef564d8c8ba8dfe8db2002fc81 /mflib | |
parent | ec1605d16b925c61f6046760af5eb95e02da2f2a (diff) | |
download | mailfromd-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.am | 32 | ||||
-rw-r--r-- | mflib/dns.mf | 57 | ||||
-rw-r--r-- | mflib/heloarg_test.mf | 127 | ||||
-rw-r--r-- | mflib/is_ip.mf | 34 | ||||
-rw-r--r-- | mflib/match_cidr.mf | 32 | ||||
-rw-r--r-- | mflib/match_dnsbl.mf | 78 | ||||
-rw-r--r-- | mflib/match_rhsbl.mf | 55 | ||||
-rw-r--r-- | mflib/mx.mf | 88 | ||||
-rw-r--r-- | mflib/revip.mf | 34 | ||||
-rw-r--r-- | mflib/safedb.mf | 38 | ||||
-rw-r--r-- | mflib/spf.mf | 122 | ||||
-rw-r--r-- | mflib/strip_domain_part.mf | 40 | ||||
-rw-r--r-- | mflib/valid_domain.mf | 30 |
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 |