aboutsummaryrefslogtreecommitdiff
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
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
-rw-r--r--ChangeLog27
-rw-r--r--Makefile.am4
-rw-r--r--NEWS66
-rw-r--r--configure.ac1
-rw-r--r--doc/Makefile.am20
-rw-r--r--doc/extract.awk167
-rw-r--r--doc/mailfromd.texi68
-rw-r--r--etc/mailfromd.rc3
-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
-rw-r--r--src/bi_ipaddr.m452
-rw-r--r--src/gram.y58
-rw-r--r--src/lex.l57
-rw-r--r--src/mailfromd.h12
-rw-r--r--src/prog.c1
-rw-r--r--src/symtab.c3
-rw-r--r--testsuite/etc/catch.rc3
-rw-r--r--testsuite/etc/catch01.rc5
-rw-r--r--testsuite/etc/cidr.rc4
-rw-r--r--testsuite/lib/mailfromd.exp4
31 files changed, 1015 insertions, 307 deletions
diff --git a/ChangeLog b/ChangeLog
index e69e868f..6fc09507 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,30 @@
+2007-03-18 Sergey Poznyakoff <gray@gnu.org.ua>
+
+ * 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
+
2007-03-17 Sergey Poznyakoff <gray@gnu.org.ua>
* src/snarf.m4, src/bi_dns.m4, src/bi_dns.m4, src/bi_sa.m4,
diff --git a/Makefile.am b/Makefile.am
index 357e0cbd..eed87296 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,5 +1,5 @@
# This file is part of mailfrom filter.
-# Copyright (C) 2005, 2006 Sergey Poznyakoff
+# Copyright (C) 2005, 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
@@ -17,7 +17,7 @@
# MA 02110-1301 USA
AUTOMAKE_OPTIONS = gnits 1.8.5 std-options
-SUBDIRS = lib gacopyz src etc doc testsuite
+SUBDIRS = lib gacopyz src mflib etc doc testsuite
ACLOCAL_AMFLAGS = -I m4
distuninstallcheck_listfiles = find . -type f -not -name 'mailfromd.rc' -print
diff --git a/NEWS b/NEWS
index 16ee4efe..2fb9957c 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,4 @@
-Mailfromd NEWS -- history of user-visible changes. 2007-03-17
+Mailfromd NEWS -- history of user-visible changes. 2007-03-18
Copyright (C) 2005, 2006, 2007 Sergey Poznyakoff
See the end of file for copying conditions.
@@ -7,6 +7,39 @@ Please send mailfromd bug reports to <bug-mailfromd@gnu.org.ua>
Version 3.1.91, SVN
+* Optional arguments in user-defined functions
+
+User-defined functions can take optional arguments. In declaration,
+optional arguments are separated from the mandatory ones by a
+semicolon. For example:
+
+ func foo(number a, number b; string c)
+
+This function is declared with two mandatory arguments (a and b), and
+an optional one (c). Subsequently it can be invoked either as
+
+ foo(x, y, z)
+
+or
+
+ foo(x, y)
+
+When invoking such functions, any missing arguments are replaced with
+default values:
+
+ - 0 for numeric arguments
+ - "" for string arguments
+
+Thus, continuing our previous example, the invocation `foo(x, y)' is
+equivalent to `foo(x, y, "")'.
+
+* New statement #include_once
+
+This statement works exactly like `#include' except that it keeps
+track of the included files. If the requested file has already been
+included, `#include_once' returns silently, while `#include' issues
+an error message.
+
* Internet address manipulation functions
- number ntohl (number N)
@@ -18,6 +51,37 @@ Version 3.1.91, SVN
- number len_to_netmask (number N)
- number netmask_to_len (number N)
+* DNS functions
+
+DNS functions are reemplemented in two layers:
+
+1. Primitive calls:
+
+- string primitive_hostname (string IP)
+- string primitive_resolve (string S [, string DOMAIN])
+- number primitive_hasmx (string DOMAIN)
+- number primitive_ismx (string DOMAIN, string IP)
+
+These functions throw an exception if the requested lookup operation
+fails.
+
+2. Traditional calls:
+
+- string hostname (string IP)
+- string resolve (string S [, string DOMAIN])
+- number hasmx (string DOMAIN)
+- number ismx (string DOMAIN, string IP)
+
+These are implemented in MFL and work exactly as their predecessors in
+3.1.x branch.
+
+To use the traditional calls, include file "dns.mf".
+
+* Function `match_cidr'
+
+This function has been reemplemented in MFL. To use it, include
+"match_cidr.mf".
+
* New statement `throw'
The `throw' statement throws the given exception. For example:
diff --git a/configure.ac b/configure.ac
index a13d9c29..952ddef5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -453,6 +453,7 @@ AC_CONFIG_FILES([Makefile
lib/Makefile
gacopyz/Makefile
src/Makefile
+ mflib/Makefile
etc/Makefile
doc/Makefile
testsuite/Makefile
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 3ff44f15..07c4b9ba 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -1,5 +1,5 @@
# This file is part of mailfrom filter.
-# Copyright (C) 2005, 2006 Sergey Poznyakoff
+# Copyright (C) 2005, 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
@@ -27,7 +27,6 @@ mailfromd_TEXINFOS=\
EXTRA_DIST = \
check-docs.sh\
- extract.awk\
gendocs_template\
mastermenu.el\
untabify.el
@@ -131,20 +130,3 @@ manual:
TEXI2DVI="$(TEXI2DVI) -t @finalout" \
$(GENDOCS) $(PACKAGE) '$(PACKAGE_NAME) manual'
-extract:
- @echo "${SELECT}" > sel.tmp; \
- while [ -s sel.tmp ]; \
- do \
- s=`cat sel.tmp | tr '\n' ','`; \
- rm sel.tmp; \
- ${AWK} -vSELECT=$$s \
- -f ${top_srcdir}/doc/extract.awk ${info_TEXINFOS} | \
- while read word rest; \
- do \
- if [ $$word = "Require" ]; then \
- echo "$$rest" >> sel.tmp; \
- else \
- echo $$word $$rest; \
- fi; \
- done; \
- done
diff --git a/doc/extract.awk b/doc/extract.awk
deleted file mode 100644
index 63996214..00000000
--- a/doc/extract.awk
+++ /dev/null
@@ -1,167 +0,0 @@
-# This file is part of mailfrom filter.
-# 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
-
-BEGIN {
- if (SELECT) {
- gsub(/,$/,"", SELECT)
- n = split(SELECT, a, ",")
- for (i = 1; i <= n; i++)
- select[a[i]] = 1
- }
-}
-
-function error(s)
-{
- print "extract.awk: " ARGV[1] ":" NR ": " s > "/dev/stderr"
-}
-
-function output(file, s)
-{
- if (!notified) {
- print "Creating file `" file "'"
- notified = 1
- }
- print s > file
-}
-
-function sprintf_multitab(s, a, n, i, r)
-{
- sub(/@(head)?item/, "", s)
- n = split(s, a, /@tab/)
- r = ""
- for (i = 1; i <= n; i++)
- r = r "" sprintf("%-*s", multitable[i-1], a[i])
- return r
-}
-
-function flush_mtline( s)
-{
- if (match(mtline, "@headitem")) {
- s = sprintf_multitab(mtline)
- output(file, "# " s)
- gsub(/./, "-", s)
- output(file, "# " s)
- } else
- output(file, "# " sprintf_multitab(mtline))
-}
-
-state == 0 && /^@deftypefn[ \t]+{Sample[ \t]+Function}/ {
- name = $5
- if (SELECT && !select[name])
- next
- file = name ".mf"
- notified = 0
- state = 1
- if (match($0, ".*@$")) {
- save0 = substr($0, 1, length($0)-1)
- while (getline > 0 && match($0, ".*@$"))
- save0 = save0 substr($0, 1, length($0)-1)
- $0 = save0 $0
- }
-}
-
-state == 0 { next }
-
-/@end[ \t]+deftypefn/ {
- close(file)
- state = 0
- next
-}
-
-state == 1 && /^[ \t]*@smallexample/ { state = 2; next }
-state == 2 && /^@end[ \t]+smallexample/ { state = 1; next }
-state == 2 && /#include/ {
- s = $2
- gsub(/[<>\"]/,"",s)
- gsub(/\.mf$/,"",s)
- if (SELECT && !select[s])
- print "Require " s
-}
-
-state == 1 && /^[ \t]*@table/ { state = 3; table = $2; next }
-state == 3 && /^@end[ \t]+table/ { state = 1; next }
-
-state == 1 && /^[ \t]*@multitable/ {
- state = 6;
- delete multitable
- mtcount = 0
- for (i = 3; i <= NF; i++)
- multitable[mtcount++] = $i * 78
- next
-}
-state == 6 && /^@end[ \t]+multitable/ { flush_mtline(); state = 1; next }
-
-# Parse texinfo commands:
-
-/^[ \t]*@c[ \t]/ { next }
-/^[ \t]*@comment[ \t]/ { next }
-/^[ \t]*@ignore/ { oldstate = state; state = 4; next }
-state == 4 && /^[ \t]*@end ignore/ { state = oldstate; next }
-
-/^[ \t]*@example-output/ { oldstate = state; state = 5; next }
-state == 5 && /^}$/ { state = oldstate; next }
-
-state == 3 && /^@itemx*/ {
- if (table == "@samp")
- output(file, "# `" $2 "'")
- if (table == "@var")
- output(file, "# " toupper($2) )
- else
- output(file, "# " $2)
- next
-}
-
-# Remove texinfo markers
-{
- gsub(/@{/, "{")
- gsub(/@}/, "}")
- gsub(/@result{}/, "=>")
- $0 = gensub(/@samp{([^}]*)}/, "`\\1'", "g")
- while (match($0, "@var{[^}]*}")) {
- $0 = substr($0, 1, RSTART-1) \
- toupper(substr($0, RSTART+5, RLENGTH-6)) \
- substr($0, RSTART+RLENGTH)
- }
- $0 = gensub(/@[a-z]+{([^}]*)}/, "\\1", "g")
-}
-
-/^@deftypefn[ \t]+{Sample[ \t]+Function}/ {
- s = ""
- for (i = 4; i <= NF; i++)
- s = s " " $i
- $0 = s
-}
-
-state == 6 && /@item/ { flush_mtline(); mtline = $0; next }
-state == 6 && /@headitem/ { flush_mtline(); mtline = $0; next }
-state == 6 { mtline = mtline " " $0; next }
-
-# Remove any leftover commands
-/^[ \t]*@.*/ { next }
-
-state == 3 || state == 5 {
- output(file, "# " $0)
- next
-}
-
-{
- if (state == 1)
- output(file, "# " $0)
- else
- output(file, $0)
-}
diff --git a/doc/mailfromd.texi b/doc/mailfromd.texi
index 11890f79..2190cb65 100644
--- a/doc/mailfromd.texi
+++ b/doc/mailfromd.texi
@@ -735,12 +735,34 @@ steps:
your startup file:
@smallexample
-#include <status.mfh>
+#include_once <status.mfh>
@end smallexample
@item
Remove all instances of @samp{&} in front of the constants. You can
use the following @command{sed} expression: @samp{s/&\([a-z]\)/\1/g}.
+
+@item
+ If your code uses any of the following functions: @code{hostname},
+@code{resolve}, @code{hasmx} or @code{ismx}, add the following line
+to the top of your script:
+
+@smallexample
+#include_once <dns.mf>
+@end smallexample
+
+@FIXME-xref{}
+
+@item
+ If your code uses function @code{match_cidr}, add the following line
+to the top of your script:
+
+@smallexample
+#include_once <match_cidr.mf>
+@end smallexample
+
+@FIXME-xref{}
+
@end enumerate
@node 30x-31x
@@ -4189,6 +4211,7 @@ inet_ntoa(2130706433) @result{} "127.0.0.1"
@deftypefn {Built-in Function} boolean match_cidr (string @var{ip}, @
string @var{cidr})
+@FIXME{Include @file{match_cidr.mf}}
Returns @code{true} if the IP address @var{ip} pertains to the
IP range @var{cidr}. The first argument, @var{ip}, is a string
representation of an IP address. The second argument, @var{cidr}, is
@@ -4212,6 +4235,11 @@ fi
@node DNS functions
@subsubsection DNS Functions
+@UNREVISED{}
+
+@FIXME{The functions are reimplemented in two layers. Instruct how
+to use upper-level functions (@code{#include_once <dns.mf>}), and
+describe lower-level ones.}
All DNS-related functions cache their results in the database
@samp{dns}, so no matter how many times you use a particular function
@@ -4276,7 +4304,7 @@ equivalent:
@smallexample
hostname("213.130.0.22")
-resolve("22.0.120.213", "in-addr.arpa")
+resolve("22.0.130.213", "in-addr.arpa")
@end smallexample
This makes it possible to use @code{resolve} for querying DNS black
@@ -5196,6 +5224,7 @@ done
@node Some Useful Functions
@subsubsection Some Useful Functions
+@UNREVISED{}
This subsection introduces several functions that can be useful in
your scripts. It can serve both as an example of writing
@@ -5203,39 +5232,8 @@ user-defined functions and as a repository of such functions (until
@command{mailfromd} has a library facility, which is planned for one of
the next releases).
-@cindex make extract
-@cindex extract, @command{make} command
-@cindex extract.awk
- To extract any of these functions into files suitable for inclusion
-in you @command{mailfromd} configuration, change to the directory
-@file{/doc} of the distribution and run @kbd{make extract}. By
-default, it will extract all functions into separate files. The names
-of the created files will be printed on the standard output:
-
-@smallexample
-@group
-$ @kbd{make extract}
-Creating file `revip.mf'
-Creating file `strip_domain_part.mf'
-Creating file `match_dnsbl.mf'
-Creating file `match_rhsbl.mf'
-@end group
-@end smallexample
-
- If you wish to extract only selected functions, type the
-comma-separated list of their names in the variable @code{SELECT},
-for example:
-
-@smallexample
-@group
-$ @kbd{make extract SELECT=revip,match_dnsbl}
-Creating file `revip.mf'
-Creating file `match_dnsbl.mf'
-@end group
-@end smallexample
-
- Use the @code{#include} statement to include the extracted files
-in your filter script (@pxref{include}).
+@FIXME{The functions are located in @file{mflib/}. Instruct how to use
+them}.
@anchor{revip}
@deftypefn {Sample Function} string revip (string @var{ip})
diff --git a/etc/mailfromd.rc b/etc/mailfromd.rc
index e1fd35e8..045b0582 100644
--- a/etc/mailfromd.rc
+++ b/etc/mailfromd.rc
@@ -24,7 +24,8 @@
#pragma regex +extended +icase
#pragma option debug 1
-#include <status.mfh>
+#include_once <status.mfh>
+#include_once <dns.mf>
set mailfrom_address "<>"
set ehlo_domain "your.domain"
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