====== mail_moduleによるMail Proxy ======
===== このページについて =====
Nginxのsmtp proxyは送信用としては利用可能ですが、**自ドメイン宛のメール受信には利用できません**。((つか、してはならない))
詳しくはQiitaに書いてみました[[http://qiita.com/Toshinori_Hayashi/items/825248e5d4641fb5e8c7|Nginxでsmtp proxyをしてはいけない]]
===== install =====
[[serverapps:nginx|Nginxのインストールはこちら]]を参照ください
なお、以下のオプションをONにしています。
* MAIL_IMAP
* MAIL_POP3
* MAIL_SMTP
===== /usr/local/etc/nginx/nginx.conf =====
mail {
auth_http authserver/mailauth/auth.php ;
proxy on;
proxy_pass_error_message on;
#ssl_certificate /usr/local/etc/acme/SSL/fullchain.pem;
#ssl_certificate_key /usr/local/etc/acme/SSL/privkey.pem;
#ssl_protocols TLSv1.2;
#ssl_session_cache shared:MAIL:10m;
smtp_capabilities PIPELINING 8BITMIME "SIZE 20480000" DSN;
#pop3_capabilities TOP USER UIDL;
#imap_capabilities IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE AUTH=LOGIN;
smtp_auth plain login;
# SMTP
server {
listen 25;
protocol smtp;
xclient off;
auth_http_header PORT 25;
error_log /var/log/nginx/mail-error.log;
}
}
===== 認証:auth.php =====
587,
"pop3" => 110,
"imap" => 143,
);
// protocol map
$protomap = array(
"995" => "pops",
"993" => "imaps",
"110" => "pop",
"143" => "imap",
"587" => "smtp",
"465" => "smtps",
);
// MySQL DB
$dbhost = "DBHOST";
$dbname = "postfix";
$dbuser = "postfix";
$dbpass = "DBPASSW0RD";
$dsn = "mysql:host=$dbhost;dbname=$dbname;charset=utf8";
$user = rtrim($env['user']) ;
$passwd = rtrim($env['passwd']) ;
$proxyhost = getenv('SERVER_ADDR');
$myaddr = getenv('SERVER_ADDR');
$proxyport = $portmap[$env['proto']];
// DB Access
try {
$pdo = new PDO($DSN, $dbuser, $dbpass,array(PDO::ATTR_EMULATE_PREPARES => false));
} catch (PDOException $e) {
$log = 'Dadabase connection failure. '.$e->getMessage();
openlog("nginx-proxy-auth", LOG_PID , LOG_MAIL);
syslog(LOG_INFO,"$log");
closelog();
exit($log);
}
$sql="SELECT password FROM mailbox WHERE username = '$user' AND active=1;";
$stmt = $pdo->query($sql);
$row = $stmt -> fetch();
$hashpass = $row["password"];
$cmd = "/usr/local/bin/doveadm pw -p '$passwd' -t '$hashpass' | /usr/bin/sed -r 's/.*(verified))$/\\1/'";
$result = rtrim(shell_exec($cmd));
$log = sprintf('user=%s, client=%s, proto=%s', $user, $env['client'], $env['proto']);
if ( $result === 'verified' ) {
$log = sprintf('proxy=successful, %s, connect=%s:%s', $log, $proxyhost, $proxyport);
header('Content-type: text/html');
header('Auth-Status: OK') ;
header("Auth-Server: $myaddr") ;
header("Auth-Port: $proxyport") ;
} else {
$log = sprintf('proxy=failure, %s, passwd=%s', $log, $passwd);
header('Content-type: text/html');
header('Auth-Status: Invalid login') ;
}
// write syslog
openlog("nginx-proxy-auth", LOG_PID , LOG_MAIL);
syslog(LOG_INFO,"$log");
closelog();
?>
やっていることはシンプルで、Nginxから引き渡されたユーザ名やPasswordを使用してDBのPassと照合、マッチしていれば'Auth-Status: OK'とメールサーバをかえします。
ここでは、DBですがLDAPなどでも流れは一緒です。
===== メールの受信 =====
メールの送信はできましたので、ここで受信側を考えます。\\
当然ほかのメールサーバはログインのための情報を持っていませんので、別ポートで認証なしで受信できるよう設定します。\\
通常の場合Postfixは認証を経ていなくても、自ドメイン宛のメールについては受け入れるという設定がされています。\\
しかしながら、今回のケースではNginx経由での接続が**適切な認証を経たものかをPostfix側で知ることはできません**。
よって、前段で書いた通りPostfixはこの別ポートからの接続を**認証を経たものとして無条件に受け入れます**。\\
受信用ポートを通して接続された場合、Postfixは認証を経たものとして無条件に受け入れるため、結果として自ドメイン以外宛のメールであっても受け入れてしまいます。
**オープンリレー**の出来上がりです。orz\\
===== 参考 =====
[[https://www.nginx.com/resources/admin-guide/mail-proxy/|CONFIGURING NGINX AS A MAIL PROXY SERVER]]
[[http://qiita.com/ma3ki/items/ce458f010a732af00179|nginxでメールサービス(SMTP,POP,IMAP)をproxyする]]
[[http://irico.net/memo/articles/20150107-nginx-mail-proxy.html|nginxをSMTP Proxyとして使う - まっしろなめも帳]]