Debian – Strange telnet client behavior when not specifying a port

debianphp5telnet

On Debian Jessie, using php5.6 and telnet version:

$ dpkg -l | grep telnet
ii  telnet                         0.17-36                      amd64        The telnet client

I have written a php script to listen on port 23 for incoming tcp connections. For testing, I telnet into it, however I have noticed that it actually makes a difference wither I telnet into it like this:

$ telnet localhost 23

vs like this:

$ telnet localhost

But according to man telnet, it should not make a difference:

port Specifies a port number or service name to contact. If not specified, the telnet port (23) is used.

If I do not specify the port, then I get some weird noise on the line. Or maybe its not noise? But if I do specify the port then I do not get this noise on the line. The noise is the following set of ascii characters:

<FF><FD><03><FF><FB><18><FF><FB><1F><FF><FB><20><FF><FB><21><FF><FB><22><FF><FB><27><FF><FD><05>

And just in case this is due to a bug in my server-side code, here is a cut down version of the script, which does exhibit the noise (though I don't think there are any bugs in the code, I just include this because someone is bound to ask):

#!/usr/bin/php
<?php

set_time_limit(0); // infinite execution time for this script
define("LISTEN_ADDRESS", "127.0.0.1");

$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option($sock, SOL_SOCKET, SO_RCVTIMEO, array('sec' => 30, 'usec' => 0)); // timeout after 30 sec
socket_bind($sock, LISTEN_ADDRESS, 23); // port = 23
socket_listen($sock);
echo "waiting for a client to connect...\n";

// accept incoming requests and handle them as child processes
// block for 30 seconds or until there is a connection.
$client = socket_accept($sock); //get the handle to this client
echo "got a connection. client handle is $client\n";

$raw_data = socket_read($client, 1024);
$human_readable_data = human_str($raw_data);
echo "raw data: [$raw_data], human readable data: [$human_readable_data]\n";

echo "closing the connection\n";
socket_close($client);
socket_close($sock);

function human_str($str)
{
    $strlen = strlen($str);
    $new_str = ""; // init
    for($i = 0; $i < $strlen; $i++)
    {
        $new_str .= sprintf("<%02X>", ord($str[$i]));
    }
    return $new_str;
}

?>

And the output from the script (from connecting like so: telnet localhost) is:

waiting for a client to connect...
got a connection. client handle is Resource id #5
raw data: [�������� ��!��"��'��], human readable data: [<FF><FD><03><FF><FB><18><FF><FB><1F><FF><FB><20><FF><FB><21><FF><FB><22><FF><FB><27><FF><FD><05>]
closing the connection

But when connecting like telnet localhost 23 (and issuing the word hi) the output is:

waiting for a client to connect...
got a connection. client handle is Resource id #5
raw data: [hi
], human readable data: [<68><69><0D><0A>]
closing the connection

So my question is whether this is expected behavior from the telnet client, or whether this is noise? It is very consistent – its always the same data – so it could be some kind of handshake?

Here is the "noise" string again with spaces and without spaces, in case its more useful:

FFFD03FFFB18FFFB1FFFFB20FFFB21FFFB22FFFB27FFFD05
FF FD 03 FF FB 18 FF FB 1F FF FB 20 FF FB 21 FF FB 22 FF FB 27 FF FD 05

Best Answer

telnet is not netcat. The telnet protocol is more than raw TCP. Among other things it can have a number of options, and the "noise" you're seeing is the negotiation of these options between your client and the server. When you specify a port you don't see any noise because according to the manual:

When connecting to a non-standard port, telnet omits any automatic initiation of TELNET options. When the port number is preceded by a minus sign, the initial option negotiation is done.

So apparently your implementation of telnet disables option negotiation when you specify a port (even when the port is 23), and re-enables it when the port is preceded by a minus sign.

On a more general note, it's generally safe to forget about telnet these days. Use netcat instead if you need a simple plain TCP client (or server, for that matter).

Related Question