milter-greylist で差出人アドレスのドメイン部だけを評価する。

id:JULY:20100109 で id:kshiono さんとのコメントのやり取りの中、その存在がバレてしまった(^^;、「差出人アドレスのドメインパートだけを評価するキーワード」のパッチを公開します。

Ver 4.2.5 から作ったパッチですが、4.2.6 でもそのまま適用出来ます。

このパッチを当てると、「fromdom」というキーワードが使えるようになります。

racl whitelist fromdom example.jp domain mx.example.jp

と書くと、

  • 差出人のメールアドレスが example.jp で、
  • かつ、相手の MTA が mx.example.jp だった場合

に許可することになります。

普通の from との違いは、from の場合はメールアドレス全体に対して部分文字列一致か、正規表現で指定するのに対し、fromdom の場合は、メールアドレスのドメインパート(「@」より後ろ)だけを対象として評価します。その時の評価方法は domain と同じで、大文字小文字を無視します。また、domainexact が指定されていれば、ドメインの境界を考慮するようになり、「example.jp」と指定されている場合、

  • mail.example.jp はマッチする。
  • mailexample.jp はマッチしない。

といった具合に、サブドメインがマッチするようになるのも domain と同じです*1

このパッチでやっているのは、設定ファイルのキーワードとして fromdom を追加して、fromdom が来たら「@」の後ろの文字列を、domain キーワードを評価している関数に投げるようにしただけです。

きちんとテストした訳じゃないのですが、少なくとも手元では悪影響は出ていません。一応、お約束ですが、自己責任で(^^;

diff -uNr milter-greylist-4.2.5/acl.c milter-greylist-4.2.5-j/acl.c
--- milter-greylist-4.2.5/acl.c	2010-04-14 13:41:22.000000000 +0900
+++ milter-greylist-4.2.5-j/acl.c	2010-04-28 17:29:44.000000000 +0900
@@ -152,6 +152,10 @@
 void acl_free_prop_regex(acl_data_t *);
 #endif
 
+
+static void retrive_domain_part(const char *, char *, size_t);
+
+
 struct acl_clause_rec acl_clause_rec[] = {
 	/* Temporary types for lists */
 	{ AC_LIST, MULTIPLE_OK, AS_NONE, "list", 
@@ -180,6 +184,18 @@
 	  AT_LIST, AC_NONE, AC_NONE, EXF_ADDR,
 	  acl_print_list, acl_add_list, 
 	  NULL, acl_list_filter },
+	{ AC_FROMDOM, UNIQUE, AS_ANY, "fromdom", 
+	  AT_STRING, AC_FROMDOM_LIST, AC_DOMAIN, EXF_FROM,
+	  acl_print_string, acl_add_string,
+	  acl_free_string, acl_fromdom_cmp },
+	{ AC_FROMDOM_RE, UNIQUE, AS_ANY, "fromdom_re", 
+	  AT_REGEX, AC_FROMDOM_LIST, AC_REGEX, EXF_FROM,
+	  acl_print_regex, acl_add_regex,
+	  acl_free_regex, acl_fromdom_regexec },
+	{ AC_FROMDOM_LIST, UNIQUE, AS_ANY, "fromdom_list", 
+	  AT_LIST,  AC_NONE, AC_NONE, EXF_FROM,
+	  acl_print_list, acl_add_list, 
+	  NULL, acl_list_filter },
 	{ AC_DOMAIN, UNIQUE, AS_ANY, "domain", 
 	  AT_STRING, AC_DOMAIN_LIST, AC_DOMAIN, EXF_DOMAIN,
 	  acl_print_string, acl_add_string,
@@ -514,6 +530,47 @@
 	return (1);
 }
 
+static
+void
+retrive_domain_part(address, buf, bufsize)
+    const char *address;
+    char *buf;
+    size_t bufsize;
+{
+    char *domain_part, *bracket;
+
+    if (address == NULL || buf == NULL || bufsize < 1) return;
+
+    domain_part = strchr(address, '@');
+
+    if (domain_part != NULL) {
+        domain_part++;
+        strncpy(buf, domain_part, bufsize);
+        buf[bufsize - 1] = '\0';
+
+        bracket = strchr(buf, '>');
+        if (bracket != NULL)
+            *bracket = '\0';
+    } else {
+        buf[0] = '\0';
+    }
+}
+
+int
+acl_fromdom_cmp(ad, stage, ap, priv)
+	acl_data_t *ad;
+	acl_stage_t stage;
+	struct acl_param *ap;
+	struct mlfi_priv *priv;
+{
+    struct mlfi_priv copied_priv;
+
+    copied_priv = *priv;
+    retrive_domain_part(priv->priv_from, copied_priv.priv_hostname, sizeof(copied_priv.priv_hostname));
+
+    return acl_domain_cmp(ad, stage, ap, &copied_priv);
+}
+
 int
 acl_header_strstr(ad, stage, ap, priv)
 	acl_data_t *ad;
@@ -744,6 +801,21 @@
 }
 
 int
+acl_fromdom_regexec(ad, stage, ap, priv)
+	acl_data_t *ad;
+	acl_stage_t stage;
+	struct acl_param *ap;
+	struct mlfi_priv *priv;
+{
+    struct mlfi_priv copied_priv;
+
+    copied_priv = *priv;
+    retrive_domain_part(priv->priv_from, copied_priv.priv_hostname, sizeof(copied_priv.priv_hostname));
+
+    return acl_domain_regexec(ad, stage, ap, &copied_priv);
+}
+
+int
 acl_header_regexec(ad, stage, ap, priv)
 	acl_data_t *ad;
 	acl_stage_t stage;
diff -uNr milter-greylist-4.2.5/acl.h milter-greylist-4.2.5-j/acl.h
--- milter-greylist-4.2.5/acl.h	2010-04-19 01:19:36.000000000 +0900
+++ milter-greylist-4.2.5-j/acl.h	2010-04-28 17:31:17.000000000 +0900
@@ -111,6 +111,9 @@
 	AC_SA,
 	AC_SASCORE,
 	AC_RATELIMIT,
+	AC_FROMDOM,
+	AC_FROMDOM_RE,
+	AC_FROMDOM_LIST,
 } acl_clause_t;
 
 struct acl_clause;
@@ -302,6 +305,10 @@
 	           struct acl_param *, struct mlfi_priv *);
 int acl_domain_regexec(acl_data_t *, acl_stage_t, 
 		       struct acl_param *, struct mlfi_priv *);
+int acl_fromdom_cmp(acl_data_t *, acl_stage_t, 
+	           struct acl_param *, struct mlfi_priv *);
+int acl_fromdom_regexec(acl_data_t *, acl_stage_t, 
+		       struct acl_param *, struct mlfi_priv *);
 int acl_body_strstr(acl_data_t *, acl_stage_t, 
 		    struct acl_param *, struct mlfi_priv *);
 int acl_header_strstr(acl_data_t *, acl_stage_t, 
diff -uNr milter-greylist-4.2.5/conf_lex.l milter-greylist-4.2.5-j/conf_lex.l
--- milter-greylist-4.2.5/conf_lex.l	2010-04-15 16:52:16.000000000 +0900
+++ milter-greylist-4.2.5-j/conf_lex.l	2010-04-28 17:26:20.000000000 +0900
@@ -17,6 +17,7 @@
 addr		[Aa][Dd][Dd][Rr]:?
 helo		[Hh][Ee][Ll][Oo]
 from		[Ff][Rr][Oo][Mm]:?
+fromdom		[Ff][Rr][Oo][Mm][Dd][Oo][Mm]:?
 rcpt		[Rr][Cc][Pp][Tt]:?
 peer		[Pp][Ee][Ee][Rr]:?
 verbose		[Vv][Ee][Rr][Bb][Oo][Ss][Ee]
@@ -204,6 +205,7 @@
 {addr}		{ return ADDR; }
 {helo}		{ BEGIN(S_REGEX); return HELO; }
 {from}		{ BEGIN(S_REGEX); return FROM; }
+{fromdom}	{ BEGIN(S_REGEX); return FROMDOM; }
 {rcpt}		{ BEGIN(S_REGEX); return RCPT; }
 {peer}		{ return PEER; }
 {autowhite}	{ return AUTOWHITE; }
diff -uNr milter-greylist-4.2.5/conf_yacc.y milter-greylist-4.2.5-j/conf_yacc.y
--- milter-greylist-4.2.5/conf_yacc.y	2010-04-15 00:32:49.000000000 +0900
+++ milter-greylist-4.2.5-j/conf_yacc.y	2010-04-28 17:34:15.000000000 +0900
@@ -15,6 +15,7 @@
 %token LOGFAC_LOCAL0 LOGFAC_LOCAL1 LOGFAC_LOCAL2 LOGFAC_LOCAL3 LOGFAC_LOCAL4
 %token LOGFAC_LOCAL5 LOGFAC_LOCAL6 LOGFAC_LOCAL7 P0F P0FSOCK DKIMCHECK
 %token SPAMDSOCK SPAMDSOCKT SPAMD DOMAINEXACT ADDHEADER NOLOG RATELIMIT KEY
+%token FROMDOM
 
 %{
 #include "config.h"
@@ -117,6 +118,8 @@
 	|	lines rcptaddr '\n' 
 	|	lines fromregex '\n' 
 	|	lines rcptregex '\n' 
+	|	lines fromdomaddr '\n'
+	|	lines fromdomregex '\n'
 	|	lines domainaddr '\n'
 	|	lines domainregex '\n'
 	|	lines peeraddr '\n' 
@@ -250,6 +253,16 @@
 				acl_register_entry_first(AS_RCPT, A_WHITELIST);
 		}
 	;
+fromdomaddr:	FROMDOM DOMAINNAME {
+			acl_add_clause(AC_FROMDOM, $2);
+			acl_register_entry_first(AS_RCPT, A_WHITELIST);
+		}
+	;
+fromdomregex:	FROMDOM REGEX	 {
+			acl_add_clause(AC_FROMDOM_RE, $2);
+			acl_register_entry_first(AS_RCPT, A_WHITELIST);
+		}
+	;
 domainaddr:	DOMAIN DOMAINNAME {
 			acl_add_clause(AC_DOMAIN, $2);
 			acl_register_entry_first(AS_RCPT, A_WHITELIST);
@@ -799,6 +812,8 @@
 	|	fromregex_clause
 	|	rcptaddr_clause
 	|	rcptregex_clause
+	|	fromdomaddr_clause
+	|	fromdomregex_clause
 	|	domainaddr_clause
 	|	domainregex_clause
 	|	netblock_clause
@@ -984,6 +999,12 @@
 rcptregex_clause:	RCPT REGEX { acl_add_clause(AC_RCPT_RE, $2); }
 	;
 
+fromdomaddr_clause:	FROMDOM DOMAINNAME { acl_add_clause(AC_FROMDOM, $2); }
+	;
+
+fromdomregex_clause:	FROMDOM REGEX { acl_add_clause(AC_FROMDOM_RE, $2); }
+	;
+
 domainaddr_clause:	DOMAIN DOMAINNAME { acl_add_clause(AC_DOMAIN, $2); }
 	;
 
@@ -1496,6 +1517,8 @@
 			{ all_list_settype(glist, AC_FROM_LIST); }
 	|	RCPT OPENLIST email_list CLOSELIST
 			{ all_list_settype(glist, AC_RCPT_LIST); }
+	|	FROMDOM OPENLIST fromdom_list CLOSELIST
+			{ all_list_settype(glist, AC_FROMDOM_LIST); }
 	|	DOMAIN OPENLIST domain_list CLOSELIST
 			{ all_list_settype(glist, AC_DOMAIN_LIST); }
 	|	DNSRBL OPENLIST qstring_list CLOSELIST
@@ -1530,6 +1553,14 @@
 	|	REGEX 	{ list_add(glist, AC_REGEX, $1); }
 	;
 
+fromdom_list:	fromdom_item
+	|	fromdom_list fromdom_item
+	;
+
+fromdom_item:	DOMAINNAME	{ list_add(glist, AC_FROMDOM, $1); }
+	|	REGEX		{ list_add(glist, AC_FROMDOM_RE, $1); }	
+	;
+
 domain_list:	domain_item
 	|	domain_list domain_item
 	;

*1:domainexact が無いと mailexample.jp もマッチします