dnl dnl проверка FQDN хоста отправителя в HELO по следующему алгоритму: dnl dnl 1. поизводится получение A записи аргумента команды HELO dnl 2. полученная A запись сравнивается с A записью рилея dnl 3. если A записи равны, проверка оканчивается успешно dnl 4. если A записи не равны, сравниваются доменные части HELO и PTR записи рилея dnl 5. если они не равны, сообщение считается не прошедшим проверку dnl 6. если доменные части HELO и PTR записи рилея равны, то сравниваются номера dnl сетей класса C полученной ранее A записи HELO и A записи рилея dnl 7. если номера сетей равны (A запись HELO и A запись рилея находятся в одной dnl сети класса C), то проверка оканчивается успешно dnl 8. в противном случае сообщение считается не прошедшим проверку dnl NO - не проводить проверку dnl REJECT - возврата клиенту кода 5xx dnl DROP - возврат клиенту кода 5xx и обрыв соединения dnl DEFER - возврата клиенту кода 451 dnl WARN - вывода в лог файл предупреждения dnl PAUSE:XX - пауза XX секунд dnl GREYLIST:XX - добавить XX баллов к счетчику опционального greylisting'а dnl REJECT:XX - добавить XX баллов к счетчику опционального reject'а dnl define(`confCHECK_HELO_FQDN', `NO')dnl dnl в confCHECK_HELO_FQDN могут быть указаны несколько значений, разделеные пробелом dnl dnl исключеня из проверки FQDN в HELO (список) dnl AUTH - не проводить проверку аутентифицированных отправителей dnl RELAY_FROM - не проводить проверку исходящих сообщений dnl HOST_LIST - не проводить проверку сообщений, получаемых с определенного списка хостов dnl (список хостов/сетей находится в файле skip_helo_fqdn_check) dnl define(`confCHECK_HELO_FQDN_SKIP', `AUTH RELAY_FROM')dnl dnl ifelse(SECTION, `MAIN', `dnl ifelse_strstr(confCHECK_HELO_FQDN_SKIP, `HOST_LIST', `dnl hostlist skip_helo_fqdn_check = CONFDIR/skip_helo_fqdn_check ')') ifelse(SECTION, `ACL_CHECK_RCPT', `dnl define(`_CHECK_HELO_FQDN_TMP', `NORMALIZE_ACTION(confCHECK_HELO_FQDN)')dnl define(`confCHECK_HELO_FQDN', _CHECK_HELO_FQDN_TMP` ')dnl # проверка HELO на наличие FQDN хоста отправителя warn set acl_m0 = set acl_m3 = ifelse_strstr(confCHECK_HELO_FQDN_SKIP, `AUTH', `dnl warn condition = ${if eq{$acl_m3}{}{yes}{no}} authenticated = * set acl_m3 = skip ')dnl ifelse_strstr(confCHECK_HELO_FQDN_SKIP, `RELAY_FROM', `dnl warn condition = ${if eq{$acl_m3}{}{yes}{no}} hosts = +relay_from_hosts set acl_m3 = skip ')dnl ifelse_strstr(confCHECK_HELO_FQDN_SKIP, `HOST_LIST', `dnl warn condition = ${if eq{$acl_m3}{}{yes}{no}} hosts = +skip_helo_fqdn_check set acl_m3 = skip ')dnl warn condition = ${if eq{$acl_m3}{}{yes}{no}} set acl_m1 = ${lookup dnsdb{a=$sender_helo_name}} condition = ${if eq{$acl_m1}{$sender_host_address}{yes}{no}} set acl_m3 = ok warn condition = ${if eq{$acl_m3}{}{yes}{no}} condition = ${if match{$acl_m1}{\N^(\d{1,3}\.\d{1,3}\.\d{1,3})\.\d{1,3}\N}{no}{yes}} set acl_m3 = helo_doesnot_resolved warn condition = ${if eq{$acl_m3}{}{yes}{no}} set acl_m3 = ${if and{\ {\ eq\ {${sg{$acl_m1}{\N^(\d{1,3}\.\d{1,3}\.\d{1,3})\.\d{1,3}\N}{\$1}}}\ {${sg{$sender_host_address}{\N^(\d{1,3}\.\d{1,3}\.\d{1,3})\.\d{1,3}\N}{\$1}}}\ }\ {\ eq{\ ${lc:${if match{$sender_helo_name}\ {\N(?i)^[^\.]+\.(.+)\N}\ {$1}{helo_without_dot}}}\ }\ {\ ${lc:${if match{$sender_host_name}\ {\N(?i)^[^\.]+\.(.+)\N}\ {$1}{sender_host_name_without_dot}}}\ }\ }\ }{passed}{forged}} warn condition = ${if eq{$acl_m3}{forged}{yes}{no}} set acl_m2 = Forged HELO used set acl_m0 = Forged HELO used (A record of HELO $sender_helo_name does not correspond to relay address) ifelse_strstr(confCHECK_HELO_FQDN, `warn', `dnl # Warning в случае указания в качестве HELO не FQDN хоста-отправителя warn condition = ${if eq{$acl_m0}{}{no}{yes}} add_header = X-Warn-HELO-Forged: $acl_m0 log_message = $acl_m0 ')dnl ifelse_strstr(confCHECK_HELO_FQDN, `pause', ` warn condition = ${if eq{$acl_m0}{}{no}{yes}} delay = EXTRACT_NAMED(`pause', confCHECK_HELO_FQDN)s set acl_m15 = ${acl_m15}\t\ delay=EXTRACT_NAMED(`pause', confCHECK_HELO_FQDN)s\t\t\ $acl_m0\n ')dnl ifelse_strstr(confCHECK_HELO_FQDN, `pause', `') ifelse_strstr(confCHECK_HELO_FQDN, `reject ', `dnl # 5xx в случае указания в качестве HELO не FQDN хоста-отправителя deny condition = ${if eq{$acl_m0}{}{no}{yes}} message = $acl_m2 log_message = $acl_m0 ')dnl ifelse_strstr(confCHECK_HELO_FQDN, `reject ', `') ifelse_strstr(confCHECK_HELO_FQDN, `defer', `dnl # 4xx в случае указания в качестве HELO не FQDN хоста-отправителя defer condition = ${if eq{$acl_m0}{}{no}{yes}} message = $acl_m2 log_message = $acl_m0 ')dnl ifelse_strstr(confCHECK_HELO_FQDN, `defer', `') ifelse_strstr(confCHECK_HELO_FQDN, `drop', ` drop condition = ${if eq{$acl_m0}{}{no}{yes}} message = $acl_m2 log_message = $acl_m0 ')dnl ifelse_strstr(confCHECK_HELO_FQDN, `drop', `') ifelse(confGREYLIST, `OPTIONAL', ` ifelse_strstr(confCHECK_HELO_FQDN, `greylist', ` warn condition = ${if eq{$acl_m0}{}{no}{yes}} set acl_c8 = \ scores=${eval:${extract{scores}{$acl_c8}}+EXTRACT_NAMED(`greylist', confCHECK_HELO_FQDN)} \ log_message="${extract{log_message}{$acl_c8}} $acl_m0;" set acl_m15 = ${acl_m15}\t\ greylist scores=EXTRACT_NAMED(`greylist', confCHECK_HELO_FQDN)\t\ $acl_m0\n ')dnl ifelse_strstr(confCHECK_HELO_FQDN, `greylist', `') ')dnl ifelse(confGREYLIST, `OPTIONAL', `') ifdef(`confOPTIONAL_REJECT', `ifelse(confOPTIONAL_REJECT, `NO', `dnl', `dnl ifelse_strstr(confCHECK_HELO_FQDN, `reject=', ` warn condition = ${if eq{$acl_m0}{}{no}{yes}} set acl_c6 = \ scores=${eval:${extract{scores}{$acl_c6}}+EXTRACT_NAMED(`reject', confCHECK_HELO_FQDN)} \ log_message="${extract{log_message}{$acl_c6}} $acl_m0;" set acl_m15 = ${acl_m15}\t\ reject scores=EXTRACT_NAMED(`reject', confCHECK_HELO_FQDN)\t\t\ $acl_m0\n ')dnl ifelse_strstr(confCHECK_HELO_FQDN, `reject=', `') ')') dnl ifdef(`confOPTIONAL_REJECT', `ifelse(confOPTIONAL_REJECT, `NO', `', `')') ')dnl ifelse(SECTION, `ACL_CHECK_RCPT', `')