MySQL gerçeklenimi

Bu gerçeklenim, aşağıdaki gerçeklenimlerin üzerine inşa edilerek Johannes Berg tarafından geliştirilmiştir:

Başka bir pograma ihtiyaç duymaz - gerçeklenim tamamen MySQL veritabanında yapılandırılmıştır.

Yapılandırmanın gelişimini içeren bir arşiv ve bir README dosyası
http://johannes.sipsolutions.net/wiki/Projects/exim-greylist adresinde mevcuttur.

Sisteminizde MySQL kurulu olmalıdır. MySQL komut satırında exim_greylist ve exim_greylist_log isimli iki tablo ile exim4 veritabanı oluşturulur:

CREATE DATABASE exim4;
use exim4;

CREATE TABLE exim_greylist (
   id bigint(20) NOT NULL auto_increment,
   relay_ip varchar(80) default NULL,
   sender varchar(255) default NULL,
   recipient varchar(255) default NULL,
   block_expires datetime NOT NULL default '0000-00-00 00:00:00',
   record_expires datetime NOT NULL default '9999-12-31 23:59:59',
   create_time datetime NOT NULL default '0000-00-00 00:00:00',
   type enum('AUTO','MANUAL') NOT NULL default 'MANUAL',
   passcount bigint(20) NOT NULL default '0',
   blockcount bigint(20) NOT NULL default '0',
   PRIMARY KEY  (id)
);

CREATE TABLE exim_greylist_log (
   id bigint(20) NOT NULL auto_increment,
   listid bigint(20) NOT NULL,
   timestamp datetime NOT NULL default '0000-00-00 00:00:00',
   kind enum('deferred', 'accepted') NOT NULL,
   PRIMARY KEY (id)
);

Exim yapılandırma dosyasının ana bölümüne bazı makrolar eklenir:

# Eğer başka veritabanları da kullanıyorsanız, bu veritabanına erişimi
# mysql_servers = localhost/exim4/kullanıcı/parola şeklinde sağlayabilirsiniz.

# seçenekler
# bunlar, xxx olarak mysql'in DATE_ADD(..,INTERVAL xxx) deyiminde
# geçerli olacak şekilde belirtilmelidir, örneğin çoğul olarak
# "2 HOUR" yerine "2 HOURS" belirtilirse geçersiz olacaktır.
GREYLIST_INITIAL_DELAY = 1 HOUR
GREYLIST_INITIAL_LIFETIME = 4 HOUR
GREYLIST_WHITE_LIFETIME = 36 DAY
GREYLIST_BOUNCE_LIFETIME = 0 HOUR

# tablo isimlerini değiştirebilirsiniz
GREYLIST_TABLE=exim_greylist
GREYLIST_LOG_TABLE=exim_greylist_log

# grilistelemeyi (geçici olarak) iptal etmek için bu satırı açıklama
# haline getirin
GREYLIST_ENABLED=

# günlük kayıtlarını etkinleştirmek için bu satırın başındaki # işaretini
# kaldırın
#GREYLIST_LOG_ENABLED=

# bundan sonrasında normalde bir düzenleme yapılmamalıdır

.ifdef GREYLIST_ENABLED
# veritabanı makroları
GREYLIST_TEST = SELECT CASE \
   WHEN now() > block_expires THEN "accepted" \
   ELSE "deferred" \
 END AS result, id \
 FROM GREYLIST_TABLE \
 WHERE (now() < record_expires) \
   AND (sender      = '${quote_mysql:$sender_address}' \
     OR (type='MANUAL' \
       AND (    sender IS NULL \
         OR sender = '${quote_mysql:@$sender_address_domain}' \
           ) \
        ) \
      ) \
   AND (recipient   = '${quote_mysql:$local_part@$domain}' \
     OR (type = 'MANUAL' \
       AND (    recipient IS NULL \
         OR recipient = '${quote_mysql:$local_part@}' \
          OR recipient = '${quote_mysql:@$domain}' \
            ) \
         ) \
       ) \
   AND (relay_ip    = '${quote_mysql:$sender_host_address}' \
     OR (type='MANUAL' \
       AND (    relay_ip IS NULL \
         OR relay_ip = \
         substring('${quote_mysql:$sender_host_address}',1,length(relay_ip)) \
           ) \
         ) \
      ) \
 ORDER BY result DESC LIMIT 1

GREYLIST_ADD = INSERT INTO GREYLIST_TABLE \
  (relay_ip, sender, recipient, block_expires, \
   record_expires, create_time, type) \
 VALUES ( '${quote_mysql:$sender_host_address}', \
  '${quote_mysql:$sender_address}', \
  '${quote_mysql:$local_part@$domain}', \
  DATE_ADD(now(), INTERVAL GREYLIST_INITIAL_DELAY), \
  DATE_ADD(now(), INTERVAL GREYLIST_INITIAL_LIFETIME), \
  now(), \
  'AUTO' \
)

GREYLIST_DEFER_HIT = UPDATE GREYLIST_TABLE \
                     SET blockcount=blockcount+1 \
                     WHERE id = $acl_m9

GREYLIST_OK_COUNT = UPDATE GREYLIST_TABLE \
                    SET passcount=passcount+1 \
                    WHERE id = $acl_m9

GREYLIST_OK_NEWTIME = UPDATE GREYLIST_TABLE \
                      SET record_expires = DATE_ADD(now(), \
                      INTERVAL GREYLIST_WHITE_LIFETIME) \
                      WHERE id = $acl_m9 AND type='AUTO'

GREYLIST_OK_BOUNCE = UPDATE GREYLIST_TABLE \
                     SET record_expires = DATE_ADD(now(), \
                     INTERVAL GREYLIST_BOUNCE_LIFETIME) \
                     WHERE id = $acl_m9 AND type='AUTO'

GREYLIST_LOG = INSERT INTO GREYLIST_LOG_TABLE \
               (listid, timestamp, kind) \
               VALUES ($acl_m9, now(), '$acl_m8')
.endif

Artık, ACL bölümünde (begin acl satırından sonra) “greylist_acl” ismiyle yeni bir ACL tanımlayabiliriz:

.ifdef GREYLIST_ENABLED
# Bu acl ya deny ya da accept döndürecek.
# acl = greylist_acl'yi ber deger ile kullandığımızdan,
# bir accept, kuralı DOĞRU yapacak, dolayısıyla bir erteleme olacak;
# bir deny ise kuralı YANLIŞ yapacak, dolayısıyla erteleme olmayacak.
greylist_acl:
  # Normal teslimatlar için griliste sınanacak.

  # Griliste sınanıp, acl_m8'e "accepted", "deferred" veya "unknown"
  # ve acl_m9'a kayıt numarası döndürülecek.

  warn set acl_m8 = ${lookup mysql{GREYLIST_TEST}{$value}{result=unknown}}
       # Burada acl_m8 = "result=x id=y"

       set acl_m9 = ${extract{id}{$acl_m8}{$value}{-1}}
       # Artık acl_m9 kayıt numarasını (veya -1) içerecek.

       set acl_m8 = ${extract{result}{$acl_m8}{$value}{unknown}}
       # acl_m8 unknown/deferred/accepted içerecek.

  # Bu üçlüyü bilmiyorsak, ileti ekleyeceğiz yoksa erteleyeceğiz
  accept
       # yukarıdaki sınama unknown (henüz kayıt yok) döndürmüşse
       condition = ${if eq{$acl_m8}{unknown}{1}}
       # ayrıca bir kayıt ekleyeceğiz
       condition = ${lookup mysql{GREYLIST_ADD}{yes}{no}}

  # Şimdi günlük kaydı yapacağız, sonucun önemi yok.
  # Üçlüyü bilmiyorsak bir günlük girdisine gerek yok çünkü
  # yukarıda oluşturma sırasında dolaylı olarak yapıldı.
  #
  .ifdef GREYLIST_LOG_ENABLED
  warn condition = ${lookup mysql{GREYLIST_LOG}}
  .endif

  # Üçlü hala engelleniyor mu bakalım
  accept
       # Yukarıdaki sınama deferred döndünmüşse ertele
       condition = ${if eq{$acl_m8}{deferred}{1}}
       # ve kayda geçir
       condition = ${lookup mysql{GREYLIST_DEFER_HIT}{yes}{yes}}

  # Bakılan kayıtları saymak için bir warn deyimi kullanıyoruz.
  warn condition = ${lookup mysql{GREYLIST_OK_COUNT}}

  # Özdevinimli kayıtlarda zaman aşımını belirlemek için bir
  # warn deyimi kullanıyoruz. Ancak, posta boş göndericili değilse
  # zamanaşımı uygulanacak, aksi takdirde zamanaşımı uygulanmayacak.
  #
  warn !senders = : postmaster@*
       condition = ${lookup mysql{GREYLIST_OK_NEWTIME}}
  warn senders = : postmaster@*
       condition = ${lookup mysql{GREYLIST_OK_BOUNCE}}

  deny
.endif

Gönderici adresi boş olmayan üçlüleri grilistelemek için bu ACL'yi acl_rcpt_to ACL'nize yerleştirin. Böylece, gönderici varlık doğrulaması yapmanız mümkün olacak:

.ifdef GREYLIST_ENABLED
  defer !senders = : postmaster@*
        acl      = greylist_acl
        message  = greylisted - try again later
.endif

Onu ayrıca acl_data'e de yerleştirin, fakat sadece gönderici adresinin boş olduğunu tespit ettikten sonraya. Bu, spamcıların grilistelemeyi gönderici adresini boş bırakarak aşmaya çalışmalarını önlemek içindir.

.ifdef GREYLIST_ENABLED
  defer senders  = : postmaster@*
        acl      = greylist_acl
        message  = greylisted - try again later
.endif