Service testing redux

My previous post on Service Testing has become a favourite of mine. I often find myself looking up details of how to check a particular service (and particularly how to use OpenSSL’s s_client). That post is now 7½ years old and I thought it due for a refresh.

HTTP

It’s still possible to type raw HTTP into a terminal and receive a webpage in response from a server. This only works with HTTP/1.0 and HTTP/1.1 (which are plain-text protocols); newer versions are binary protocols that are less scrutable.

The most important difference between the two text protocols is that HTTP/1.1 requires a Host: header. The older protocol only allows a server to host a single domain and so is less popular.

$ telnet example.com 80
Trying 93.184.216.34...
Connected to example.com.
Escape character is '^]'.
$ GET / HTTP/1.1
$ Host: example.com
$
HTTP/1.1 200 OK
Age: 438726
Cache-Control: max-age=604800
Content-Type: text/html; charset=UTF-8
Date: Sat, 13 Feb 2021 18:56:23 GMT
Etag: "3147526947+ident"
Expires: Sat, 20 Feb 2021 18:56:23 GMT
Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT
Server: ECS (nyb/1D20)
Vary: Accept-Encoding
X-Cache: HIT
Content-Length: 1256

<!doctype html>
<html>
<head>
    <title>Example Domain</title>
...

You can replace the first / in the GET command with any request path, and add additional request headers if desired.

HTTPS

HTTP communication can be encrypted via TLS. Secure HTTP is usually hosted on port 443, and we can use OpenSSL‘s s_client to connect:

$ openssl s_client -connect example.com:443 -crlf -quiet
depth=2 C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert Global Root CA
verify return:1
depth=1 C = US, O = DigiCert Inc, CN = DigiCert TLS RSA SHA256 2020 CA1
verify return:1
depth=0 C = US, ST = California, L = Los Angeles, O = Internet Corporation for Assigned Names and Numbers, CN = www.example.org
verify return:1
$ GET / HTTP/1.1
$ Host: example.com
$
HTTP/1.1 200 OK
...

SMTP

The venerable Simple Mail Transfer Protocol is nearly 40 years old but (after several extensions) remains the standard way to send email between machines on the Internet.

Plain SMTP

Mail is still commonly sent as plain text. Let’s try it:

$ telnet example.com 25
Trying 1.2.3.4...
Connected to example.com.
Escape character is '^]'.
220 example.com ESMTP Postfix

Say “hello” and check it responds:

$ EHLO example.com
250-example.com
250-PIPELINING
250-SIZE 20480000
250-ETRN
250-STARTTLS
250-ENHANCEDSTATUSCODES
250-8BITMIME
250-DSN
250-SMTPUTF8
250 CHUNKING

Try sending a message to a local user:

$ MAIL FROM: <nobody@example.com>
250 2.1.0 Ok
$ RCPT TO: <somebody@example.com>
250 2.1.5 Ok
$ DATA
354 End data with <CR><LF>.<CR><LF>
$ To: <somebody@example.com>
$ From: <nobody@example.com>
$ Subject: Test message
$
$ Test message content
$ .
$
250 2.0.0 Ok: queued as 49B47827F2
$ QUIT
221 2.0.0 Bye
Connection closed by foreign host.

STARTTLS

Mail can be sent encrypted (using TLS). After connecting to a server, the STARTTLS command triggers negotiation of a secure transport. This isn’t something we can do ourselves, but s_client supports this:

$ openssl s_client -connect example.com:25 -crlf -starttls smtp -quiet
depth=2 O = Digital Signature Trust Co., CN = DST Root CA X3
verify return:1
depth=1 C = US, O = Let's Encrypt, CN = R3
verify return:1
depth=0 CN = example.com
verify return:1
250 CHUNKING
$ EHLO ...

Logging in

In order to relay mail (send it on to another destination) it’s necessary to log in to the remote server. You can log in wherever you see AUTH in the response to the EHLO command. We’ve not seen this yet because it’s common to use a dedicated port (587) for message submission (leaving port 25 for receiving messages destined for the server itself).

$ openssl s_client -connect example:587 -crlf -starttls smtp -quiet
depth=2 O = Digital Signature Trust Co., CN = DST Root CA X3
verify return:1
depth=1 C = US, O = Let's Encrypt, CN = R3
verify return:1
depth=0 CN = example.com
verify return:1
250 CHUNKING
$ EHLO example.com
250-example.com
250-PIPELINING
250-SIZE 20480000
250-ETRN
250-AUTH PLAIN LOGIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250-DSN
250-SMTPUTF8
250 CHUNKING

This server supports login via two mechanisms: PLAIN and LOGIN.

PLAIN

This login mechanism concatenates the username and password together and encodes them.

$ echo -ne '\000username\000password' | base64  # in a shell
AHVzZXJuYW1lAHBhc3N3b3Jk

$ AUTH PLAIN  # in an SMTP session
334
$ AHVzZXJuYW1lAHBhc3N3b3Jk
235 2.7.0 Authentication successful

You’ll obviously need to replace “username” and “password” with real values. After authentication it should be possible to send mail to anywhere on the Internet.

LOGIN

For this mechanism we send the username and password separately.

$ echo -n 'username' | base64
dXNlcm5hbWU=
$ echo -n 'password' | base64
cGFzc3dvcmQ=

$ AUTH LOGIN
334 VXNlcm5hbWU6
dXNlcm5hbWU=
334 UGFzc3dvcmQ6
cGFzc3dvcmQ=
235 2.7.0 Authentication successful

If you base64-decode the server’s responses above you’ll find these are “Username:” and “Password:” respectively.

SMTPS

It used to be common to host SMTP over an entirely encrypted connection on port 465. s_client can connect to this too:

$ openssl s_client -connect example.com:465 -crlf -quiet
depth=2 O = Digital Signature Trust Co., CN = DST Root CA X3
verify return:1
depth=1 C = US, O = Let's Encrypt, CN = R3
verify return:1
depth=0 CN = example.com
verify return:1
250 CHUNKING
$ EHLO ...

IMAP

Plain IMAP (usually on port 143) isn’t as common as IMAPS (port 993). Again we use s_client. If you need to talk unencrypted IMAP then just use telnet.

$ openssl s_client -connect example.com:993 -quiet
depth=2 O = Digital Signature Trust Co., CN = DST Root CA X3
verify return:1
depth=1 C = US, O = Let's Encrypt, CN = R3
verify return:1
depth=0 CN = example.com
verify return:1
* OK [CAPABILITY IMAP4rev1 SASL-IR LOGIN-REFERRALS ID ENABLE IDLE LITERAL+ AUTH=PLAIN AUTH=LOGIN]

Log in:

$ a1 LOGIN "username" "password"
a1 OK [CAPABILITY IMAP4rev1 SASL-IR LOGIN-REFERRALS ID ENABLE IDLE SORT SORT=DISPLAY THREAD=REFERENCES THREAD=REFS THREAD=ORDEREDSUBJECT MULTIAPPEND URL-PARTIAL CATENATE UNSELECT CHILDREN NAMESPACE UIDPLUS LIST-EXTENDED I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARCHRES WITHIN CONTEXT=SEARCH LIST-STATUS BINARY MOVE SNIPPET=FUZZY PREVIEW=FUZZY LITERAL+ NOTIFY SPECIAL-USE] Logged in

List some folders:

$ a2 LIST "" "*"
... lots of stuff

Find what’s in the Inbox:

$ a3 EXAMINE INBOX
* FLAGS (\Answered \Flagged \Deleted \Seen \Draft Junk NonJunk $Forwarded)
* OK [PERMANENTFLAGS ()] Read-only mailbox.
* 135 EXISTS
* 0 RECENT
* OK [UNSEEN 6] First unseen.
* OK [UIDVALIDITY 1345668496] UIDs valid
* OK [UIDNEXT 50898] Predicted next UID
* OK [HIGHESTMODSEQ 132256] Highest
a3 OK [READ-ONLY] Examine completed (0.001 + 0.000 secs).

Exit:

$ a4 LOGOUT
* BYE Logging out
a4 OK Logout completed (0.001 + 0.000 secs).

This entry was posted in Uncategorized. Bookmark the permalink. Trackbacks are closed, but you can post a comment.

Post a Comment

Your email is never published nor shared. Required fields are marked *

You may use these HTML tags and attributes <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*
*