Диагностика почтовых протоколов
Эта статья о методах диагностики почтовых протоколов. Она предназначена для начинающих администраторов, желающих больше узнать об инструментах для быстрого тестирования авторизации/отправки/приема почтовых сообщений как сервером, так и клиентом. Но также может служить хорошей памяткой соответствующих команд и для более опытных администраторов.
Материал разбит следующим образом:
1. Введение
2. Примеры сессий
3. Проверка авторизации на сервере (LOGIN, PLAIN, CRAM-MD5), Base64
4. Проверка шифрования SSL/TLS
5. Анализ почтового трафика при помощи tshark. Расшифровка SSL/TLS
6. Ссылки на материалы
В сети достаточно материалов по отдельным пунктам, но все разбросано по разным местам и, когда возникает необходимость выполнить ту или иную операцию, приходится по разным ресурсам вспоминать нюансы авторизации, способы быстрой кодировки в base64, ключи к openssl и tshark. Здесь все собрано вместе, а также добавлена информация о дешифровке SSL/TLS трафика.
Обозначения
$ — приглашение в обычном шелле, указанная после него команда выполняется от обычного пользователя
# — приглашение в рутовом шелле, указанная после него команда выполняется с правами администратора
## — строка с комментарием
Запрос клиента в почтовых сессиях выделен жирным шрифтом.
Почтовые порты
Основные порты, использующиеся в работе почтовых серверов по RFC (документы, регламентирующие работу сети интернет и ее основных компонентов): SMTP
- 25/tcp SMTP (стандартный порт)
- 465/tcp SMTPS (устаревший)
- 587/tcp submission (порт для обслуживания клиентов)
POP3
- 110/tcp POP3 (стандартный порт)
- 995/tcp POP3S (порт с предварительной установкой SSL/TLS соединения)
IMAP
- 143/tcp IMAP (стандартный порт)
- 993/tcp IMAPS (порт с предварительной установкой SSL/TLS соединения)
Здесь перечислены только основные, помимо них разные реализации серверов могут использовать другие порты для своих служебных целей, для пользовательского и административного веб-интерфейса, общения узлов кластера и т.д.
Используемые и рекомендуемые утилиты
В статье используются telnet, openssl, tshark. Для наглядности взаимодействия сервера и клиента, использования команд протокола. На регулярной основе и для автоматизации каких-то процессов можно использовать утилиты, которые скрывают от нас все эти детали, но которые проще включаются в скрипты. Из таких утилит могу порекомендовать скрипт на perl smtp-cli, (http://www.logix.cz/michal/devel/smtp-cli/) обладающий широкой функциональностью, в том числе и возможностью SMTP авторизации. Также рекомендую утилиту imtest из состава cyrus-clients, которой можно протестировать IMAP протокол. smtp-sink, утилиту из состава postfix, которая эмулирует почтовый сервер. С ее помощью можно отлаживать работу почтового клиента в том случае, если нет ни доступа к существующим почтовым серверам, ни возможности включения в настройках клиента подробного журналирования.
При помощи nmap можно быстро проверить, доступны ли порты снаружи, то есть, слушаются ли они программами и не закрыты ли при этом файерволом:
# nmap -v -p25,110,143,465,587,993,995 127.0.0.1
Starting Nmap 4.11 ( http://www.insecure.org/nmap/ ) at 2014-10-31 15:59 MSK
Initiating SYN Stealth Scan against localhost.localdomain (127.0.0.1) [7 ports] at 15:59
Discovered open port 25/tcp on 127.0.0.1
Discovered open port 465/tcp on 127.0.0.1
Discovered open port 143/tcp on 127.0.0.1
Discovered open port 993/tcp on 127.0.0.1
The SYN Stealth Scan took 0.00s to scan 7 total ports.
Host localhost.localdomain (127.0.0.1) appears to be up ... good.
Interesting ports on localhost.localdomain (127.0.0.1):
PORT STATE SERVICE
25/tcp open smtp
110/tcp closed pop3
143/tcp open imap
465/tcp open smtps
587/tcp closed submission
993/tcp open imaps
995/tcp closed pop3s
Nmap finished: 1 IP address (1 host up) scanned in 0.004 seconds
Raw packets sent: 7 (308B) | Rcvd: 17 (724B)
По этому выводу видно, что на сервере доступны SMTP/IMAP порты, но недоступны порты для
POP3 протокола.
Через netstat можно посмотреть не только прослушиваемые и используемые порты, как часто предполагают, но и процессы, связанные с этими портами. Вот вывод netstat для этого же почтового сервера:
# netstat -lnpvut (и -anpvut, если необходимо посмотреть текущие соединения по портам)
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:143 0.0.0.0:* LISTEN 477/dovecot
tcp 0 0 0.0.0.0:2000 0.0.0.0:* LISTEN 477/dovecot
tcp 0 0 0.0.0.0:465 0.0.0.0:* LISTEN 603/master
tcp 0 0 127.0.0.1:53 0.0.0.0:* LISTEN 430/unbound
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 10042/sshd
tcp 0 0 0.0.0.0:25 0.0.0.0:* LISTEN 603/master
tcp 0 0 0.0.0.0:1025 0.0.0.0:* LISTEN 603/master
tcp 0 0 0.0.0.0:993 0.0.0.0:* LISTEN 477/dovecot
tcp 0 0 127.0.0.1:1953 0.0.0.0:* LISTEN 430/unbound
tcp 0 0 127.0.0.1:1026 0.0.0.0:* LISTEN 603/master
tcp 0 0 127.0.0.1:2025 0.0.0.0:* LISTEN 603/master
tcp 0 0 :::22 :::* LISTEN 10042/sshd
udp 0 0 127.0.0.1:53 0.0.0.0:* 430/unbound
В этом примере в качестве SMTP сервера используется postfix и dovecot в качестве IMAP. POP3 в списке отсутствует, так как в настройках dovecot этот протокол отключен, как неиспользуемый.
В современных дистрибутивах пакет net-tools уже часто не ставится, считается устаревшим. В качестве замены испольуется утилита ss из состава iproute. Это более узко заточенная и в свой области, вероятно, более функциональная утилита с возможностью настройки фильтров как в tcpdump/tshark. Но мне, например, не нравится, как у нее отформатирован вывод информации. Чтобы чуть это исправить, можно использовать sed:
# ss -lntp | sed -r 's/\t/ /g'
Recv-Q Send-Q Local Address:Port Peer Address:Port
0 0 *:143 *:* users:(("dovecot",477,6),("imap-login",14400,4),("imap-login",15370,4),("imap-login",15372,4))
0 0 *:2000 *:* users:(("dovecot",477,8),("managesieve-log",10229,4),("managesieve-log",10230,4),("managesieve-log",21149,4))
0 0 *:465 *:* users:(("master",603,31))
0 0 127.0.0.1:53 *:* users:(("unbound",430,4))
0 0 *:22 *:* users:(("sshd",10042,4))
0 0 *:25 *:* users:(("master",603,19))
0 0 *:1025 *:* users:(("master",603,12))
0 0 *:993 *:* users:(("dovecot",477,7),("imap-login",14400,5),("imap-login",15370,5),("imap-login",15372,5))
0 0 127.0.0.1:1953 *:* users:(("unbound",430,5))
0 0 127.0.0.1:1026 *:* users:(("master",603,16))
0 0 127.0.0.1:2025 *:* users:(("master",603,28))
0 0 :::22 :::* users:(("sshd",10042,3))
*) для удобства использования можно поместить следующую bash функцию в ~/.bashrc
ss() { /sbin/ss $@ | sed -r 's/\t/ /g'; }
Здесь приведены примеры сессий по SMTP/IMAP/POP3 протоколам. Для соединения используется клиент телнет, который либо в системе установлен по-умолчанию, либо устанавливается из репозиториев: Debian/Ubuntu
# apt-cache search telnet
# apt-get install telnet
RHEL/CentOS/Fedora
# yum search telnet
# yum install telnet
Вводимые команды в тексте выделены жирным шрифтом.
SMTP
$ telnet 127.0.0.1 25
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
220 mailserver at mail.server.net greets you. Make love not war!
HELO localhost.localdomain
250 mail.server.net
MAIL FROM:<>
250 2.1.0 Ok
RCPT TO:
250 2.1.5 Ok
DATA
354 End data with .
FROM: root@localhost.localdomain
TO: user@mail.server.net
SUBJECT: test mail from test subject
test body
.
250 2.0.0 Ok: queued as 1CF5FC0AAE
QUIT
221 2.0.0 Bye
Connection closed by foreign host.
IMAP
$ telnet 127.0.0.1 143
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
* OK IMAP Server at mail.server.net ready
001 LOGIN user@mail.server.net testpass
001 OK completed
002 CAPABILITY
* CAPABILITY IMAP4 IMAP4REV1 ACL NAMESPACE UIDPLUS IDLE LITERAL+ QUOTA ID MULTIAPPEND LISTEXT CHILDREN BINARY LOGIN-REFERRALS STARTTLS AUTH=LOGIN AUTH=PLAIN AUTH=CRAM-MD5 AUTH=DIGEST-MD5 AUTH=MSN
002 OK completed
003 SELECT Inbox
* FLAGS (\Answered \Flagged \Deleted \Seen \Draft $MDNSent)
* OK [PERMANENTFLAGS (\Answered \Flagged \Deleted \Seen \Draft $MDNSent)] limited
* 7214 EXISTS
* 0 RECENT
* OK [UIDVALIDITY 306349424] UIDs valid
* OK [UNSEEN 1] message 1 is first unseen
003 OK [READ-WRITE] SELECT completed
004 FETCH 7214 body[header]
* 7214 FETCH (BODY[header] {639}
Return-Path: <>
X-Antispam-passed: yes
X-Antispam: yes
X-Real-To: user@mail.server.net
Received: from [127.0.0.1] (HELO mail.server.net)
by mail.server.net ( SMTP 4.1.8)
with ESMTP id 22561074 for user@mail.server.net; Sat, 01 Nov 2014 03:21:16 +0300
Received: from localhost.localdomain (localhost [127.0.0.1])
by mail.server.net (Postfix) with SMTP id 1CF5FC0AAE
for ; Sat, 1 Nov 2014 03:20:09 +0300 (MSK)
FROM: root@localhost.localdomain
TO: user@mail.server.net
SUBJECT: test mail from test subject
Message-Id: <20141101002009.1CF5FC0AAE@mail.server.net>
Date: Sat, 1 Nov 2014 03:20:09 +0300 (MSK)
FLAGS (\Seen))
004 OK completed
004 FETCH 7214 body
* 7214 FETCH (BODY ("text" "plain" NIL NIL NIL "8bit" 13 2))
004 OK completed
004 FETCH 7214 body[]
* 7214 FETCH (BODY[] {652}
Return-Path: <>
X-Antispam-passed: yes
X-Antispam: yes
X-Real-To: user@mail.server.net
Received: from [127.0.0.1] (HELO mail.server.net)
by mail.server.net ( SMTP 4.1.8)
with ESMTP id 22561074 for user@mail.server.net; Sat, 01 Nov 2014 03:21:16 +0300
Received: from localhost.localdomain (localhost [127.0.0.1])
by mail.server.net (Postfix) with SMTP id 1CF5FC0AAE
for ; Sat, 1 Nov 2014 03:20:09 +0300 (MSK)
FROM: root@localhost.localdomain
TO: user@mail.server.net
SUBJECT: test mail from test subject
Message-Id: <20141101002009.1CF5FC0AAE@mail.server.net>
Date: Sat, 1 Nov 2014 03:20:09 +0300 (MSK)
test body
)
004 OK completed
005 LOGOUT
* BYE IMAP closing connection
005 OK completed
Connection closed by foreign host.
POP3
$ telnet 127.0.0.1 110
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
+OK POP3 Server 4.1.8 ready <137.1414802293@mail.server.net>
USER test@mail.server.net
+OK please send the PASS
PASS testpass
+OK 7214 messages (174404489 bytes)
NOOP
+OK cool
TOP 7214
+OK message follows
Return-Path: <>
X-Antispam-passed: yes
X-Antispam: yes
X-Real-To: test@mail.server.net
Received: from [127.0.0.1] (HELO mail.server.net)
by mail.server.net ( SMTP 4.1.8)
with ESMTP id 22561074 for test@mail.server.net; Sat, 01 Nov 2014 03:21:16 +0300
Received: from localhost.localdomain (localhost [127.0.0.1])
by mail.server.net (Postfix) with SMTP id 1CF5FC0AAE
for ; Sat, 1 Nov 2014 03:20:09 +0300 (MSK)
FROM: root@localhost.localdomain
TO: test@mail.server.net
SUBJECT: test mail from test subject
Message-Id: <20141101002009.1CF5FC0AAE@mail.server.net>
Date: Sat, 1 Nov 2014 03:20:09 +0300 (MSK)
.
RETR 7214
+OK 652 bytes will follow
Return-Path: <>
X-Antispam-passed: yes
X-Antispam: yes
X-Real-To: test@mail.server.net
Received: from [127.0.0.1] (HELO mail.server.net)
by mail.server.net ( SMTP 4.1.8)
with ESMTP id 22561074 for test@mail.server.net; Sat, 01 Nov 2014 03:21:16 +0300
Received: from localhost.localdomain (localhost [127.0.0.1])
by mail.server.net (Postfix) with SMTP id 1CF5FC0AAE
for ; Sat, 1 Nov 2014 03:20:09 +0300 (MSK)
FROM: root@localhost.localdomain
TO: test@mail.server.net
SUBJECT: test mail from test subject
Message-Id: <20141101002009.1CF5FC0AAE@mail.server.net>
Date: Sat, 1 Nov 2014 03:20:09 +0300 (MSK)
test body
.
DELE 7214
+OK marked deleted
QUIT
+OK POP3 Server connection closed
Connection closed by foreign host.
Существующие способы авторизации: LOGIN, PLAIN, CRAM-MD5, DIGEST-MD5, GSSAPI, NTLM/MSN, EXTERNAL. Перечень их еще шире, мы же рассмотрим только наиболее распространенные, а именно LOGIN, PLAIN и CRAM-MD5.
В первую очередь необходимо узнать список методов, поддерживаемых сервером. Для каждого из почтовых протоколов есть команды, позволяющие получить эти данные наряду с другой информацией о доступных расширениях протокола. Обратите внимание, что в зависимости от настроек почтового сервера, LOGIN и PLAIN, передающие данные в открытом виде, могут быть недоступны без предварительной инициализации шифрования через SSL/TLS
Итак, вывод доступных способов авторизации:
Протокол SMTP
Команда EHLO domainname
$ telnet 127.0.0.1 25
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
220 mailserver ESMTP ready.
EHLO localhost.localdomain
250-mal.server.net
250-PIPELINING
250-SIZE 104857600
250-ETRN
250-STARTTLS
250-AUTH PLAIN LOGIN DIGEST-MD5 CRAM-MD5
250-AUTH=PLAIN LOGIN DIGEST-MD5 CRAM-MD5
250-ENHANCEDSTATUSCODES
250 8BITMIME
^]
telnet> quit
Connection closed.
Протокол IMAP
Команда 001 CAPABILITY
Какие-то почтовые сервера могут выводить эту информацию в «приветствии сервера», например dovecot.
$ telnet 127.0.0.1 143
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
* OK [CAPABILITY IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE STARTTLS AUTH=PLAIN AUTH=LOGIN AUTH=DIGEST-MD5 AUTH=CRAM-MD5] Dovecot ready.
001 CAPABILITY
* CAPABILITY IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE SORT SORT=DISPLAY THREAD=REFERENCES THREAD=REFS MULTIAPPEND UNSELECT IDLE CHILDREN NAMESPACE UIDPLUS LIST-EXTENDED I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARCHRES WITHIN CONTEXT=SEARCH LIST-STATUS XEXEC QUOTA STARTTLS AUTH=PLAIN AUTH=LOGIN AUTH=DIGEST-MD5 AUTH=CRAM-MD5
001 OK Capability completed.
002 LOGOUT
* BYE Logging out
002 OK Logout completed.
Connection closed by foreign host.
Протокол POP3
Команды AUTH или CAPA
$ telnet pop.mail.ru 110
Trying 217.69.139.74...
Connected to pop.mail.ru.
Escape character is '^]'.
+OK
AUTH
+OK methods supported:
LOGIN
PLAIN
.
CAPA
+OK Capability list follows
TOP
USER
LOGIN-DELAY 120
EXPIRE NEVER
UIDL
IMPLEMENTATION Mail.Ru
SASL LOGIN PLAIN
STLS
.
QUIT
+OK POP3 server at signing off
Connection closed by foreign host.
Примеры авторизации и используемый формат
LOGIN
Протокол SMTP
$ telnet 127.0.0.1 25
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
220 mail.server.net ESMTP Server
EHLO client.server.net
250-mail.server.net Hello client.server.net
250-AUTH LOGIN PLAIN CRAM-MD5 DIGEST-MD5 GSSAPI
250-ENHANCEDSTATUSCODES
250 STARTTLS
AUTH LOGIN
334 VXNlcm5hbWU6
dGVzdA==
334 UGFzc3dvcmQ6
dGVzdHBhc3M=
235 2.7.0 Authentication successful
QUIT
221 2.0.0 Bye
Где 'dGVzdA== ' — логин и 'dGVzdHBhc3M=' пароль в формате base64. О нем чуть ниже. Обратите внимание, что и логин и пароль должны кодироваться без перевода строки.
PLAIN
Протокол SMTP
$ telnet 127.0.0.1 25
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
220 mail.server.net ESMTP Server
EHLO client.server.net
250-mail.server.net Hello client.server.net
250-AUTH LOGIN PLAIN CRAM-MD5 DIGEST-MD5 GSSAPI
250-ENHANCEDSTATUSCODES
250 STARTTLS
AUTH PLAIN dGVzdAB0ZXN0AHRlc3RwYXNz
235 2.7.0 Authentication successful
QUIT
221 2.0.0 Bye
Где 'dGVzdAB0ZXN0AHRlc3RwYXNz' это логинпароль в base64 формате. Чуть ниже будут рассмотрены варианты конвертации в base64 формат и обратно.
CRAM-MD5
В отличии от предыдущих способов авторизации CRAM-MD5 пароль не передается в открытом виде, вместо этого используется сравнение хэшей. Ручная проверка этого способа авторизации может быть проблемой, так как нужно будет выполнить несколько преобразований, а время на введение команд ограничено. Для упрощения процесса ниже приведен простой perl скрипт, который принимает на вход имя пользователя, пароль и «кодовое слово» (выдаваемое сервером), и конвертирует их в строку в base64 формате.
Для скрипта понадобится дополнительный модуль perl «Digest-HMAC». В Debian/Ubuntu его можно найти и установить следующим образом:
# apt-cache search perl | grep -i digest
# apt-get install libdigest-hmac-perl
Для RHEL/CentOS/Fedora:
# yum search perl | grep -i digest
# yum install perl-Digest-HMAC
В тех дистрибутивах, в чьих репозиториях нет этого пакета (что маловероятно), можно использовать установку модуля из CPAN.
Скрипт и пример сессии с его использованием:
#!/usr/bin/perl -W
use strict;
use MIME::Base64 qw(encode_base64 decode_base64);
use Digest::HMAC_MD5;
die "Usage: $0 username password ticket\n" unless $#ARGV == 2;
my ($username, $password, $ticket64) = @ARGV;
my $ticket = decode_base64($ticket64) or
die ("Unable to decode Base64 encoded string '$ticket64'\n");
my $password_md5 = Digest::HMAC_MD5::hmac_md5_hex($ticket, $password);
print encode_base64 ("$username $password_md5", "");
Протокол SMTP
$ telnet 127.0.0.1 25
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
220 mail.server.net ESMTP Server
EHLO client.server.net
250-mail.server.net Hello client.server.net
250-AUTH LOGIN PLAIN CRAM-MD5 DIGEST-MD5 GSSAPI
250-ENHANCEDSTATUSCODES
250 STARTTLS
AUTH CRAM-MD5
## кодовое слово, выдаваемое сервером:
PDMzMjE2NDkzMTA1OTExNDQuMTQxNDc5NTExOUBtYWlsLnNlcnZlci5uZXQ+
dGVzdCAxNTU0YTQwNzA1NTgxZjUwZmI1MmNjZDhlZDhjM2EyYg==
235 2.7.0 Authentication successful
QUIT
221 2.0.0 Bye
# ./md5cram.pl test testpass PDMzMjE2NDkzMTA1OTExNDQuMTQxNDc5NTExOUBtYWlsLnNlcnZlci5uZXQ+
dGVzdCAxNTU0YTQwNzA1NTgxZjUwZmI1MmNjZDhlZDhjM2EyYg==
Протокол IMAP
$ telnet 127.0.0.1 143
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
* OK [CAPABILITY IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE STARTTLS AUTH=PLAIN AUTH=LOGIN AUTH=DIGEST-MD5 AUTH=CRAM-MD5] Dovecot ready.
01 AUTHENTICATE CRAM-MD5
+ PDgxOTAyMjA2NTYwNzcyMzEuMTQxNDc5NzA3MkBtYWlsLnNlcnZlci5uZXQ+
dGVzdCA1YTZlNjYwMDlmZGJlZWNjYWRlNDY5M2FlMjU5YTA2ZQ==
01 OK [CAPABILITY IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE SORT SORT=DISPLAY THREAD=REFERENCES THREAD=REFS MULTIAPPEND UNSELECT IDLE CHILDREN NAMESPACE UIDPLUS LIST-EXTENDED I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARCHRES WITHIN CONTEXT=SEARCH LIST-STATUS XEXEC QUOTA] Logged in
02 LOGOUT
* BYE Logging out
02 OK Logout completed.
Connection closed by foreign host.
# ./md5cram.pl test testpass PDgxOTAyMjA2NTYwNzcyMzEuMTQxNDc5NzA3MkBtYWlsLnNlcnZlci5uZXQ+
dGVzdCA1YTZlNjYwMDlmZGJlZWNjYWRlNDY5M2FlMjU5YTA2ZQ==
Cпособы конвертации текста в и из base64
Авторизация предполагает обмен строками, закодированными в base64. Для Linux cуществует много утилит для конвертации в base64 и обратно. Мы укажем несколько, включая способ их запуска. Для Windows можно использовать кроссплатформенные perl, python, php, по ним также будут привидены примеры.
Утилита (пакет)
base64 (coreutils)
$ printf 'test\0test\0testpass' | base64
dGVzdAB0ZXN0AHRlc3RwYXNz
$ echo dGVzdAB0ZXN0AHRlc3RwYXNz | base64 -d
testtesttestpass
uueencode/uudecode (sharutils)
$ printf 'test\0test\0testpass' | uuencode -m -
begin-base64 644 -
dGVzdAB0ZXN0AHRlc3RwYXNz
====
Чтобы раскодировать, потребуется добавить первую и последнюю строку. Это можно сделать, например, следующими способами;
printf 'begin-base64 644 -\ndGVzdAB0ZXN0AHRlc3RwYXNz\n====' | uudecode
или
$ uudecode<
mmencode (xemacs21-bin)
$ printf 'test\0test\0testpass' | mmencode
dGVzdAB0ZXN0AHRlc3RwYXNz
$ echo dGVzdAB0ZXN0AHRlc3RwYXNz | mmencode -u
testtesttestpass
python (python)
$ printf 'test\0test\0testpass' | python -m base64
dGVzdAB0ZXN0AHRlc3RwYXNz
$ echo dGVzdAB0ZXN0AHRlc3RwYXNz | python -m base64 -d
php (php-cli)
$ printf 'test\0test\0testpass' | php -r 'echo base64_encode(fgets(STDIN));'
dGVzdAB0ZXN0AHRlc3RwYXNz
$ php -r 'echo base64_decode($argv[1]);' dGVzdAB0ZXN0AHRlc3RwYXNz
testtesttestpass
perl (perl)
Модуль MMIME: Base64 стандартно идет в комплекте.
$ perl -MMIME::Base64 -e 'print encode_base64("test\0test\0testpass")'
dGVzdAB0ZXN0AHRlc3RwYXNz
$ perl -MMIME::Base64 -e 'print decode_base64("dGVzdAB0ZXN0AHRlc3RwYXNz")'
testtesttestpass
openssl (openssl)
$ printf 'test\0test\0testpass' | openssl base64
dGVzdAB0ZXN0AHRlc3RwYXNz
$ echo dGVzdAB0ZXN0AHRlc3RwYXNz | openssl base64 -d
testtesttestpass
Для шифрования трафика в почтовых протоколах между клиентом и сервером используется SSL/TLS в двух вариантах. Использование специальных портов, при соединении с которым сначала осуществляется установка SSL/TLS, после чего уже поверх него идет обычный почтовый трафик. Этот метод, кстати, признан устаревшим (deprecated), относительно SMTP точно. Второй вариант, более предпочтительный — соединение с обычным портом для сервиса и переход сессии в зашифрованный вид с использованием расширения STARTTLS.
Для проверки работы почтового сервера поверх SSL/TLS можно использовать утилиту openssl, дальше действуя, как при обычной сессии через telnet.
SMTP
$ openssl s_client -starttls smtp -crlf -connect mail.truevds.ru:25
$ openssl s_client -starttls smtp -crlf -connect mail.truevds.ru:587
$ openssl s_client -crlf -connect mail.truevds.ru:465
POP3
$ openssl s_client -connect mail.truevds.ru:995
$ openssl s_client -starttls pop3 -crlf -connect mail.truevds.ru:110
IMAP
$ openssl s_client -crlf -connect mail.truevds.ru:993
$ openssl s_client -starttls imap -crlf -connect mail.truevds.ru:143
Можно явным образом указать, что использовать для шифрования, ssl3 или tls1, а также конкретные алгоритмы:
$ openssl s_client -ssl3 -starttls smtp -crlf -connect mail.truevds.ru:25
Посмотреть перечень поддерживаемых протоколов в вашей версии openssl:
$ openssl ciphers -ssl3
$ openssl ciphers -tls1
Ниже, в главе про tshark, эта возможность будет использована в практических целях.
При необходимости более сложной диагностики в том случае, когда журналы не дают достаточно информации о проблемах в работе сервера или клиента, можно использовать tcpdump/wireshark для анализа непосредственно самой сессии между клиентом и сервером. Как в реальном времени, так и сохранив дамп сессии для последующего анализа. Для быстрого анализа удобно использовать консольный вариант wireshark — tshark. Для его работы потребуются права root.
Tshark предоставляет информацию в понятном виде и в использовании довольно прост.
SMTP
# tshark -i eth0 -f "port 25" -R smtp
IMAP
# tshark -i eth0 -f "port 143" -R imap
POP3
# tshark -i eth0 -f "port 110" -R pop
Запись трафика для последующего анализа при помощи утилит tcpdump|dumpcap (из состава wireshark):
# tcpdump -s0 -nn -i eth0 -w smtps.pcap port 465 and host HOSTIP
# dumpcap -s0 -i eth0 -w smtp.pcap -f 'port 25 and host HOSTIP'
где HOSTIP является IP-адресом противоположной стороны, сервера или клиента, сессию с которым мы анализируем. И последующее чтение:
# tshark -n -r smtp.pcap -R smtp
Во многих случаях в почтовых протоколах активно используется шифрование и таким способом сессию уже не посмотреть. Тем не менее, этот вопрос в целом также решаем. tshark может дешифровать SSL/TLS трафик «со стороны сервера» при наличии доступа к приватному ключу сервера.(Для клиента есть вариант с использованием Master-Key, подробнее wiki.wireshark.org/SSL) К счастью или к сожалению, wireshark с приватным ключем может дешифровать не все использвуемые алгоритмы. Например DHE-* EXP-*, EDH-* не работают. Возможно, какие-то из этих алгоритмов добавлены в более поздних версиях программы.
В процессе тестирования использовалась утилита openssl с явным указанием при соединении с конкретных алгоритмов. Проверенные варианты, с которыми дешифровка трафика прошла успешно:
- ssl3: RC4-SHA, RC4-MD5, DES-CBC-SHA, AES128-SHA
- tls1: RC4-MD5, AES256-SHA, DES-CBC-SHA, DES-CBC3-SHA
Посмотреть перечень поддерживаемых протоколов в вашей версии openssl:
# openssl ciphers -ssl3
# openssl ciphers -tls1
Для анализа реальной сессии можно отключить в конфигурации почтового сервера (только на время тестирования!) всех алгоритмов, кроме заведомо рабочих.
Tshark запускается на сервере, там, где есть ключ, а клиент openssl на локальном компьютере. Но, это, конечно, необязательно, вполне можно tshark запускать на клиенте в другой консоли, просто это потребует копирования приватного ключа на локальный компьютер. А openssl можно запускать в screen в соседнем с tshark окне.
Итак запускаем:
# tshark -i eth0 -n -o "ssl.keys_list:94.127.66.53,25,smtp,/etc/pki/tls/private/server.key" -R smtp
$ printf "EHLO RC4-MD5\nEXIT" | openssl s_client -starttls smtp -crlf -tls1 -cipher RC4-MD5 -connect mail.truevds.ru:25
# tshark -i eth0 -n -o "ssl.keys_list:94.127.66.53,465,smtp,/etc/pki/tls/private/server.key" -R smtp
$ printf "EHLO RC4-MD5\nEXIT" | openssl s_client -ssl3 -cipher RC4-SHA -connect mail.truevds.ru:465
# tshark -i eth0 -n -o "ssl.keys_list:94.127.66.53,143,imap,/etc/pki/tls/private/server.key" -R imap
$ printf "* CAPABILITY\nLOGOUT" | openssl s_client -starttls imap -crlf -tls1 -cipher RC4-MD5 -connect mail.truevds.ru:143
# tshark -i eth0 -n -o "ssl.keys_list:94.127.66.53,993,imap,/etc/pki/tls/private/server.key" -R imap
$ printf "* CAPABILITY\nLOGOUT" | openssl s_client -crlf -ssl3 -cipher RC4-MD5 -connect mail.truevds.ru:993
# tshark -i eth0 -n -o "ssl.keys_list:94.127.66.53,110,pop,/etc/pki/tls/private/server.key" -R pop
$ printf "USER RC4-MD5\nEXIT" | openssl s_client -starttls pop -crlf -tls1 -cipher RC4-MD5 -connect mail.truevds.ru:110
# tshark -i eth0 -n -o "ssl.keys_list:94.127.66.53,995,pop,/etc/pki/tls/private/server.key" -R pop
$ printf "USER RC4-MD5\nEXIT" | openssl s_client -crlf -ssl3 -cipher RC4-MD5 -connect mail.truevds.ru:995
Здесь 94.127.66.53
— ip адрес сервера, с которым соединяется клиент, /etc/pki/tls/private/server.key
— путь до приватного ключа сервера. Приватный ключ, как правило, размещается в /etc/pki
или /etc/ssl
, в зависимости от сервера. Эту информацию можно посмотреть в настройках самого почтового сервера.
Пример для postfix:
$ grep key_file /etc/postfix/main.cf
smtpd_tls_key_file = /etc/pki/tls/private/server.key
smtp_tls_key_file = /etc/pki/tls/private/server.key
Для портов, где используется starttls вместо порта в официальной документации рекомендуется использовать start_tls. Например, ssl.keys_list:94.127.66.53,start_tls,smtp,/etc/pki/tls/private/server.key
вместо ssl.keys_list:94.127.66.53,25,smtp,/etc/pki/tls/private/server.key
. Но у меня этот вариант не сработал, показывался трафик только до инициализации шифрования.
Для отладки процесса SSL/TLS дешифровки используется опция -o "ssl.debug_file: /tmp/debug.log"
Пример вывода дешифрованного трафика:
# tshark -i eth0 -n -o "ssl.keys_list:94.127.66.53,25,smtp,/etc/pki/tls/private/server.key" -R "smtp"
Running as user "root" and group "root". This could be dangerous.
Capturing on eth0
0.178964 94.127.66.21 -> 94.127.66.53 SMTP C: EHLO RC4-MD5 | EXIT
0.179357 94.127.66.53 -> 94.127.66.21 SMTP 250-mail.truevds.ru | 250-PIPELINING | 250-SIZE 104857600 | 250-ETRN |
Удачи в решении почтовых проблем!