====== 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として使う - まっしろなめも帳]]