Как вы знаете, на территории Украины в последнее время почта от Mail.Ru перестала открываться. С доступом к веб-версии все легко — там проблемы решаются в несколько кликов,
 а вот с IMAP-клиентом веселее. У меня в телефоне, например, работает штатная почтовая программа от Apple, но уже неделю я не могу получать почту в то время, когда я подключен к Интернету от сотовой сети. А я, надо сказать, мобильным Интернетом от «Vodafone» пользуюсь исключительно для получения почты на мобильный, в остальном он мне без надобности. Решил исправить проблему оригинально, но из этого так ничего и не вышло. Пишу здесь на случай,
 если кто-нибудь, кто лучше меня понимает исходный код nginx, придумает патч, который будет в силах ситуацию исправить. 
Итак, в nginx, как вы, наверное, знаете, есть модуль из базовой комплектации, который позволяет использовать веб-сервер как прокси для почты по протоколам IMAP, POP3 и SMTP с местной авторизацией. В принципе, функционал весьма интересный, поэтому мне эта идея понравилась. Для начала, собираем nginx с указанием того, что мы желаем пользоваться электронной почтой:
  ./configure --with-mail --with-mail_ssl_module --with-openssl=/path/to/openssl 
После сборки nginx, создаем конфигурационный документ примерно следующего вида:
 mail {
	auth_http 127.0.0.1:9990/auth.php;
	proxy_pass_error_message on;
	server_name my.perfect.mail;
	xclient off;
	proxy on;
	smtp_auth "plain";
	smtp_capabilities "8BITMIME" "SIZE 42991616" "ENHANCEDSTATUSCODES";
	ssl		 on;
	ssl_certificate     /some/ssl/cert.crt;
	ssl_certificate_key /some/ssl/cert.key;
	ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
	ssl_ciphers	 HIGH:!aNULL:!MD5;
	pop3_capabilities  "TOP"  "USER";
	imap_capabilities  "IMAP4rev1"  "UIDPLUS" "ID" "XLIST" "UNSELECT" "MOVE" "LIST-STATUS";
	server {
		listen     465;
		listen     [::]:465;
		protocol   smtp;
		smtp_auth  login plain cram-md5;
	}
	server {
		listen    995;
		listen    [::]:995;
		protocol  pop3;
		pop3_auth plain apop cram-md5;
	}
	server {
		listen   993;
		listen   [::]:993;
		protocol imap;
	}
}
 
Размещается вся эта красота ниже секции http в файле /etc/nginx/nginx.conf. Немного поясню о том, что это все значит. Итак, в самой первой строке мы объявили, что обращаться за авторизацией перед соединением нужно по адресу 127.0.0.1:9990/auth.php (пока этого у нас нет, далее расскажу подробнее). В поле «server_name» указано доменное имя сервера, к которому мы будем обращаться с клиента. «ssl_certificate» и «ssl_certificate_key» — это сертификат и ключ, соответствующие тому домену, который указан в «server_name». Нужно для того, чтобы трафик между клиентом и прокси-сервером шифровался, а не передавался в открытом виде. В секциях «server» объявлено то, что сервер будет слушать порты IMAP, POP3 и SMTP как по IPv4, так и по IPv6 (если у вас, конечно, нет поддержки IPv6, то строки с двоеточиями в квадратных скобках можно смело ликвидировать).
Теперь немного о том самом 127.0.0.1:9990/auth.php. Это адрес, на который прокси-сервер будет передавать логин и пароль от ящика при авторизации. В ответ на эти данные мы должны дать прокси разрешение на соединение, а вместе с тем указать, какой именно сервер и порт необходимо проксировать для данного ящика. По сути дела, ничего сложного.
 Многие коллеги писали тяжелые скрипты на Perl с получением данных из MySQL. Я решил пока ограничиться небольшим тестовым скриптом на PHP, суть которого заключается в том,
 что он принимает логин и если он соответствует моей почте, отдает IMAP-сервер mail.ru для дальнейшей работы.
  <?php
	if(@$_SERVER['HTTP_AUTH_USER'] == "my@perfect.mail"){
		if(@$_SERVER['HTTP_AUTH_PROTOCOL'] == "imap"){
			header("Auth-Status: OK", true);
			header("Auth-Server: imap.mail.ru", true);
			header("Auth-Port: 993", true);
		}elseif(@$_SERVER['HTTP_AUTH_PROTOCOL'] == "pop3"){
			header("Auth-Status: OK", true);
			header("Auth-Server: pop.mail.ru", true);
			header("Auth-Port: 995", true);
		}elseif(@$_SERVER['HTTP_AUTH_PROTOCOL'] == "smtp"){
			header("Auth-Status: OK", true);
			header("Auth-Server: smtp.mail.ru", true);
			header("Auth-Port: 465", true);
		}else{
			header("Auth-Status: Internal Error", true);
		}
	}else{
		header("Auth-Status: Invalid Mailbox", true);
	}
?> 
Скрипт из семейства простейших, но свою функцию исполняет. Разместить его можно где угодно, но только на HTTP, так как с шифрованием эта штука работать не умеет. Лучше всего создать отдельный локальный виртуальный хост на выделенном порту и привязать авторизацию туда. В nginx это делается достаточно просто:
 server {
        listen 127.0.0.1:9990;
        server_name 127.0.0.1;
        access_log off;
        error_log /var/log/nginx/127.0.0.1-error.log;
        location @apache {
                proxy_pass http://127.0.0.1:8400$uri$is_args$args;
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-For $remote_addr;
                proxy_connect_timeout 120;
                proxy_send_timeout 120;
                proxy_read_timeout 180;
        }
	location / {
                try_files /BYCezwf54s @apache;
        }
	location ~* \.(jpg|jpeg|gif|png|ico|css|bmp|swf|js|html|txt)$ {
                root /var/www/127.0.0.1/;
                try_files $uri @apache;
        }
} 
Я взял типовую конфигурацию, в которой все скрипты обрабатывает Apache, а статику отдает nginx. Можно было, конечно, и переписать, но мне было лень. «/var/www/127.0.0.1/» — это директория, в которой находится скрипт авторизации. Все остальное, я думаю, будет понятно. На случай, если у вас вдруг нет Apache, то ставить его не нужно — просто возьмите аналогичную конфигурацию на другом сайте — я много такого сегодня встречал в Интернете, пока искал решение проблемы.
Ну все, вроде бы готово. Пробуем подключиться с клиента. Фигушки! Процесс подключения начинается и вполне себе успешно виснет. В чем же дело? А дело, как выяснилось, очень простое! «mail_ssl_module» обеспечивает только подключение клиентов к прокси-серверу по SSL, но не подключение самого прокси-сервера к конечному узлу. Таким образом, nginx пытается подключиться к серверу mail.ru на SSL-порту не используя при этом SSL. Исправить это средствами nginx, кстати, никак нельзя (или же мне за сутки поисков просто не попалась информация об этом). Зато есть stunnel — хитрый прокси-сервер, который подключается к целевому узлу по SSL, а нам разрешает подключиться к себе по обычному прозрачному протоколу. Ok, устанавливаем. /etc/stunnel/stunnel.conf для mail.ru имеет примерно такой вид: 
 client = yes
[pop3s]
accept  = 127.0.0.1:1995
connect = pop.mail.ru:995
[imaps]
accept  = 127.0.0.1:1993
connect = imap.mail.ru:993
[ssmtp]
accept  = 127.0.0.1:1465
connect = smtp.mail.ru:465 
Все остальное в файле можно не трогать. Обратите внимание: «accept» — это наша внутренняя точка, к которой мы будем подключаться без SSL; «connect» — это сервер mail.ru с SSL-шифрованием. Соответственно, теперь нам придется править наш скрипт авторизации, который отвечает по адресу 127.0.0.1:9990/auth.php:
  <?php
	if(@$_SERVER['HTTP_AUTH_USER'] == "my@perfect.mail"){
		if(@$_SERVER['HTTP_AUTH_PROTOCOL'] == "imap"){
			header("Auth-Status: OK", true);
			header("Auth-Server: 127.0.0.1", true);
			header("Auth-Port: 1993", true);
		}elseif(@$_SERVER['HTTP_AUTH_PROTOCOL'] == "pop3"){
			header("Auth-Status: OK", true);
			header("Auth-Server: 127.0.0.1", true);
			header("Auth-Port: 1995", true);
		}elseif(@$_SERVER['HTTP_AUTH_PROTOCOL'] == "smtp"){
			header("Auth-Status: OK", true);
			header("Auth-Server: 127.0.0.1", true);
			header("Auth-Port: 1465", true);
		}else{
			header("Auth-Status: Internal Error", true);
		}
	}else{
		header("Auth-Status: Invalid Mailbox", true);
	}
?> 
Запускаем stunnel и пробуем подключиться из консоли:
  openssl s_client -connect my.perfect.mail:993
  
Когда соединение успешно проходит, отправляем команду авторизации:
 1 LOGIN my@perfect.mail someSecretPassword
  
На этом этапе меня ожидало жестокое разочарование: соединение успешно поднимается, авторизация проходит но тут же разрывается. В журнал ошибок nginx в это время выводится сообщение о неожиданном ответе upstream-сервера, в котором перед «OK» выводится список поддерживаемых расширений «CAPABILITIES». Что с этим беспокойным хозяйством делать — я не знаю, поэтому делаю откат. Возможно, кого-то тема заинтересует. Если вы, вдруг, найдете решение этого вопроса, буду рад, если расскажете мне об этом на alik [at] ibice.ru (не смотрите на дату публикации, если не убрал — значит решение еще не найдено).
Кто делает неправильно — не знаю. То ли это mail.ru дает ответ не в том порядке, в котором это предусмотрено протоколом (но тогда почему ни один клиент на это не ругается,
 а все работает стабильно?), то ли nginx производит авторизацию в неправильной очередности (тогда почему с другими серверами все работает отлично?). 
								
								
									
									
									
								 
								 
							 |