= Drop telnet for openSSL

The https://www.redhat.com/sysadmin/telnet-netcat-troubleshooting[telnet] command is one of the most popular network troubleshooting tools available to both systems administrators and networking hobbyists.
In the early years of networked computing, telnet was used to connect to a remote system.
You could use telnet to access a port on a remote system, log in, and run commands on that host.

Due to its lack of encryption, however, telnet has been largely replaced by OpenSSH for this job.
Its relevance persisted (and arguably persists in some cases even today) as a sort of intelligent `ping`.
While the `ping` command is a great way to probe a host for responsiveness, that's _all_ it can do, but telnet not only confirms an active port, it also has the possibility of interacting with a service on that port.
Even so, most modern network services are encrypted.
This potentially makes telnet far less useful, depending on what you're trying to achieve.

== OpenSSL s_client

For most tasks that once required telnet, I now use OpenSSL's `s_client` command.
(There are some tasks for which I use https://opensource.com/downloads/curl-command-cheat-sheet[`curl`], but those cases are almost always times I wouldn't have used telnet anyway.)
Most people understand that OpenSSL is a library and framework for encryption, but not everyone realizes it's a command as well.
The `s_client` component of the `openssl` command implements a generic SSL or TLS client, helping you to connect to a remote most using SSL or TLS.
It's intended for testing and, internally at least, uses the same functionality of the library itself.

== Installing

OpenSSL may already be installed on your Linux system, but if not you can install it with your distribution's package manager:

[source,bash]
----
$ sudo dnf install openssl
----

On Debian or similar:

[source,bash]
----
$ sudo apt install openssl
----

Once it's installed, verify that it responds as expected:

[source,bash]
----
$ openssl version
OpenSSL x.y.z FIPS
----

== Verifying port access

Probably the most basic telnet usage is a task something like this:

[source,bash]
----
$ telnet mail.example.com 25
Trying 98.76.54.32...
Connected to example.com.
Escape character is '^]'.
----

This opens an interactive session with, in this example, whatever service is listening on port 25 (probably a mail server).
As long as access is gained, you could communicate with the service.

Should port 25 be inaccessible, the connection is refused.

OpenSSL is similar, although usually less interactive.
To verify access to a port:

[source,bash]
----
$ openssl s_client -connect example.com:80
CONNECTED(00000003)
140306897352512:error:1408F10B:SSL [...]

no peer certificate available

No client certificate CA names sent

SSL handshake has read 5 bytes and written 309 bytes
Verification: OK

New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
----

This is little more than a targeted ping, though.
As you can see from the output, no SSL certificate has been exchanged, and so the connection is immediately terminated.
To get the most out of `openssl s_client`, you must target the encrypted port.

== Interactive OpenSSL

Web browsers and web servers interact such that traffic directed at port 80 is actually forwarded to 443, the port reserved for encrypted HTTP traffic.
Knowing this, you can navigate to encrypted ports with the `openssl` command and interact with whatever web service is running on it.

First, make a connection to a port using SSL. Using the `-showcerts` option causes the SSL certificate to print to your terminal, making the initial output a lot more verbose than telnet:

[source,bash]
----
$ openssl s_client -connect example.com:443 -showcerts
[...]
   0080 - 52 cd bd 95 3d 8a 1e 2d-3f 84 a0 e3 7a c0 8d 87   R...=..-?...z...
   0090 - 62 d0 ae d5 95 8d 82 11-01 bc 97 97 cd 8a 30 c1   b.............0.
   00a0 - 54 78 5c ad 62 5b 77 b9-a6 35 97 67 65 f5 9b 22   Tx\.b[w..5.ge.."
   00b0 - 18 8a 6a 94 a4 d9 7e 2f-f5 33 e8 8a b7 82 bd 94   ..j...~/.3......

   Start Time: 1619661100
   Timeout   : 7200 (sec)
   Verify return code: 0 (ok)
   Extended master secret: no
   Max Early Data: 0

----

You're left in an interactive session.
Eventually, this session will be closed, but if you act promptly, you can send HTTP signals to the server:

[source,bash]
----
[...]
GET / HTTP/1.1
HOST: example.com
----

Press *Return* twice, and you receive the data for `example.com/index.html`:

[source,bash]
----
[...]
<body>
<div>
   <h1>Example Domain</h1>
   <p>This domain is for use in illustrative examples in documents. You may use this
   domain in literature without prior coordination or asking for permission.</p>
   <p><a href="https://www.iana.org/domains/example">More information...</a></p>
</div>
</body>
</html>
----

=== Email server

You can also use OpenSSL's `s_client` to test an encrypted email server.
For this to work, you must first have your test user's username and password encoded in Base64.
Here's an easy way to do this:

[source,bash]
----
$ perl -MMIME::Base64 -e 'print encode_base64("username");'
$ perl -MMIME::Base64 -e 'print encode_base64("password");'
----

Once you have those values recorded, you can connect to a mail server over SSL, usually on port 587:

[source,bash]
----
$ openssl s_client -starttls smtp \
-connect email.example.com:587
> ehlo example.com
> auth login
##paste your user base64 string here##
##paste your password base64 string here##

> mail from: [email protected]
> rcpt to: [email protected]
> data
> Subject: Test 001
This is a test email.