An exchange I had a few months ago went something like this:

Me: Weird, my requests aren’t getting through, but I can ping the server just fine.

Coworker: I can’t telnet to the port… the firewall is probably blocking your traffic.


Me (to myself): 🤨 wtf does telnet do?

telnet came up again as I was reading Compute Networking: A Top Down Approach. It demonstarted using telnet to interact with a mail server using SMTP. I decided it was time to dig in to telnet, and the rest of this post will describe what I found.

The Gist

I’ve included a bunch of links in the Resources section at the bottom, but I’ll summarize what I found. telnet opens a TCP connection on a specific port and then drops you into a shell where every key you press is sent over the TCP connection to the remote host1. It came before SSH and was the way to connect to remote machines and execute commands. It’s not secure by default so is mostly not used, but it comes in handy to check if a port is accepting TCP connections on a host.

Telnet interface example: NASA JPL Horizons

Aside from checking if a port is accessible, and networking textbooks, the only other time I could remember thinking about telnet was when I wanted to calculate the phase of the moon and wanted to know its ephemerides2. It turns out NASA provides this as a service called Horizons that has a telnet interface!

If you click this link: telnet:// you can play around with it (it opens a terminal window for me with some warning prompts). It can send you email and tell you about positions of all kinds of objects.

Alternatively, as I was poking around about scripting telnet connections, I came up with the following expect script (another tool I have just learned about). This script will print out some moon facts:

#!/usr/bin/env expect

spawn telnet 6775
expect "Horizons> "

# The Moon
send "301\n"

# Exit out
expect " Select"
send "\n"
expect "Horizons> "
send "quit"

Some other fun telnet sites are:

  • telnet – Star Wars: A New Hope in ASCII
  • telnet - An ASCII map of the world, fully zoomable

HTTP via Telnet

Telnet also allows manually typing out text based protocols that use TCP like HTTP! I couldn’t remember the exact HTTP syntax, so I ran the following curl command to print out an HTTP request:

$ curl -v
* Connected to ( port 80 (#0)
> GET / HTTP/1.1
> Host:
> User-Agent: curl/7.55.1
> Accept: */*

I could recreate this with telnet by typing just the first two lines3:

$telnet 80
Connected to
Escape character is '^]'.
GET / HTTP/1.1

HTTP/1.1 301 Moved Permanently
Content-Type: text/html; charset=UTF-8
Date: Mon, 11 Jun 2018 00:18:29 GMT
Expires: Wed, 11 Jul 2018 00:18:29 GMT
Cache-Control: public, max-age=2592000
Server: gws
Content-Length: 219
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN

<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<H1>301 Moved</H1>
The document has moved
<A HREF="">here</A>.

Ping vs. Telnet

Now the question is, why did telnet uncover that the firewall was blocking traffic but ping didn’t? On ping’s man page, it says:

ping uses the ICMP protocol’s mandatory ECHO_REQUEST datagram to elicit an ICMP ECHO_RESPONSE from a host or gateway

Notably, since ping operates at the ICMP level, it doesn’t have ports. If a firewall is only filtering based on ports accessed, it wouldn’t drop the ICMP packet, but it would not allow the telnet connection to succeed.



  • Where does most firewall enforcement happen? Is it slotted somewhere in between IP and TCP/UDP? Or does this firewall just happen to not block ICMP Echo from ping?
  • How was SSH developed and adopted? Were most remote connections like the Horizons interface or was there a something more similar to how we use SSH today?

  1. I checked this out by doing telnet 80 while running sudo tcpdump "port 80" and seeing every key I press get emitted as a line in tcpdump ↩︎

  2. An ephemerisis gives the position of an object like the moon at a particular time. ↩︎

  3. Typing just the first line followed the redirect and gave the actual contents of, HTML, JS and all. This is the same output if I had curl follow redirects with -L↩︎