GithubHelp home page GithubHelp logo

telnet-client's Introduction

telnet-client

Latest Version on Packagist Software License Build Status Coverage Status Quality Score Total Downloads

A telnet client written in PHP

Install

Via Composer

composer require graze/telnet-client

Usage

Instantiating a client

Use the factory method to return a TelnetClientInterface instance:

$client = Graze\TelnetClient\TelnetClient::factory();

Issuing commands

Connect to the remote endpoint using the connect method:

$dsn = '127.0.0.1:23';
$client->connect($dsn);

Once connected, the execute method can be used to write $command to the socket:

$command = 'Open the pod bay doors, HAL';
$resp = $client->execute($command);

Responses

Once a command has been sent, the socket is read until a specific sequence is encountered. This is a line ending immediately preceded by either a prompt, or an error prompt. At this point the execute method returns a TelnetResponseInterface object:

/**
 * Whether an error prompt was encountered.
 *
 * @return bool
 */
public function isError();

/**
 * Any response from the server up until a prompt is encountered.
 *
 * @return string
 */
public function getResponseText();

/**
 * The portion of the server's response that caused execute() to return.
 *
 * @return array
 */
public function getPromptMatches();

A success response object might look like:

Graze\TelnetClient\TelnetResponse {#2
  #isError: false
  #responseText: "Affirmative, Dave"
  #promptMatches: array:1 [
    0 => "$"
  ]
}

Or if the server responded with an error:

Graze\TelnetClient\TelnetResponse {#2
  #isError: true
  #responseText: " I'm sorry, Dave. I'm afraid I can't do that"
  #promptMatches: array:1 [
    0 => "ERROR"
  ]
}

Note: responseText and promptMatches are trimmed of line endings.

Client configuration

The client uses the following defaults:

  • standard prompt $
  • error prompt ERROR
  • line endings \n

Custom configuration can be passed to the connect method like so:

$dsn = '127.0.0.1:23';
$prompt = 'OK';
$promptError = 'ERR';
$lineEnding = "\r\n";
$client->connect($dsn, $prompt, $promptError, $lineEnding);

The client's global $prompt can be temporarily overridden on a per-execute basis:

$command = 'login';
$prompt = 'Username:';
$resp = $client->execute($command, $prompt);

Complex prompts

Some operations may respond with a more complex prompt. These instances can be handled by using a regular expression to match the prompt. For instance, a server may respond with ERROR n (where n is an integer) when an error condition is encountered. The client could be configured as such:

$dsn = '127.0.0.1:23';
$promptError = 'ERROR [0-9]';
$client->connect($dsn, null, $promptError);

An error response would look like:

Graze\TelnetClient\TelnetResponse {#2
  #isError: true
  #responseText: "unknown command"
  #promptMatches: array:1 [
    0 => "ERROR 6"
  ]
}

We can take the regex one further by using a named capturing group, this makes the error code easily available to us in the $promptMatches array.

$dsn = '127.0.0.1:23';
$promptError = 'ERROR (?<errorNum>[0-9])';
$client->connect($dsn, null, $promptError);

which gives us:

Graze\TelnetClient\TelnetResponse {#2
  #isError: true
  #responseText: "unknown command"
  #promptMatches: array:3 [
    0 => "ERROR 6",
    "errorNum" => "6",
    1 => "6"
  ]
}

Note: it's important to escape any characters in your regex that may have special meaning when interpreted by preg_match.

Socket settings

For timeouts and more, PHP's socket_set_option is exposed via

$client->getSocket()->setOption();

See clue/php-socket-raw and socket_set_option for more info.

Change log

Please see CHANGELOG for more information what has changed recently.

Testing

make test

Contributing

Please see CONTRIBUTING for details.

Security

If you discover any security related issues, please email [email protected] instead of using the issue tracker.

Inspired by

Based on bestnetwork/Telnet.

Credits

License

The MIT License (MIT). Please see License File for more information.

telnet-client's People

Contributors

biggianteye avatar brendankay avatar john-n-smith avatar kinekt4 avatar rokasdevelopment avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

telnet-client's Issues

Propose execute() should accept $promptError parameter

According to the current design, execute() only accepts one parameter: $prompt

This assumes that $promptError is static, and $prompt is dynamic.

Hence, $promptError can only be set on initialisation where $prompt can be set on every call to execute()

I propose that $promptError should be treated the same as $prompt, in that it can be set dynamically.

Effectively, I'm proposing execute() should accept another parameter $promptError

public function execute($command, $prompt = null, $promptError = null)
{
    ...
    return $this->getResponse($prompt, $promptError);
    ...

Consequently, getResponse() will also have to accept one more parameter

protected function getResponse($prompt = null, $promptError = null)
{
    ...
    $promptError = isset($promptError) ? $promptError : $this->promptError;
    if ($this->promptMatcher->isMatch($promptError, $buffer, $this->lineEnding)) {
    ...

What are your thoughts?

How to login?

I connected to server that requires authentication. Raw output is like this:

Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Ubuntu 16.04.2 LTS
wapmorgan-10HYS04800 login: 

How to authentication with your library?
I tried this, but it hangs up for a while:

$telnet = Graze\TelnetClient\TelnetClient::factory();
$telnet->connect('127.0.0.1:23');
var_dump($telnet->execute('wapmorgan', 'wapmorgan-10HYS04800 login:'));

The execute method doesn't work

I'm trying to connect Memcached server on localhost:11211 and run the get command.

$prompt = 'OK';
$promptError = 'ERROR';
$lineEnding = "\r\n";
$this->telnet->connect("localhost:11211", $prompt, $promptError, $lineEnding);
$resp = $this->telnet->execute("get some_key");
var_dump($resp->getResponseText());

I run this code via phpunit from PowerShell but it doesnt do anything. No error shown but also no any other output. And the console looks like it still executing.

image

The same result if I try run any other Memcached command. However these commands works fine from Powershell telnet and from Putty.

Any thoughts?

Timeouts in different places

Hi Again.

We're connecting to a server and doing the same sequence of commands and interactions, I've been receiving a number of timeout exceptions but they are in different places of the telnet client.

//Timeout on this line, once in the last 24hrs. TelnetClient.php at line 223
if (in_array($character, [$this->NULL, $this->DC1])) {
    break;
}
//Timeout on this method, once in the last 24hrs. Socket.php at line 243
public function read($length, $type = PHP_BINARY_READ) {
//Timeout on this method, 3 times in the last 24hrs. TelnetClient.php at line 239
if ($this->promptMatcher->isMatch($this->promptError, $buffer, $this->lineEnding)) {
//Timeout on this method, 2 times in the last 24hrs. PromptMatcher.php at line 39
if (!is_null($lineEnding) && substr($subject, -1 * strlen($lineEnding)) != $lineEnding) {
//Timeout on this method, 5 times in the last 24hrs. Socket.php at line 245
$data = @socket_read($this->resource, $length, $type);

Now I'm pretty sure because of how random it is it must be something to do with the host server but wanted to know if you've ever come across this or how I could handle it?
It usually happens after a successful interaction so do I need to close the connection manually? You've already doing that in the destructor though

Thanks for any help you can provide.

Use for port 25?

Hi,

I need to Telnet to port 25. Is there a way to do it with this?

What I do wrong?

$telnet = \Graze\TelnetClient\TelnetClient::factory();
$telnet->connect('ip:23', 'User name:');
$resp = $telnet->execute('admin', 'User password:');

what wrong???

Graze\TelnetClient\Exception\UndefinedCommandException
1. in /vendor/graze/telnet-client/src/InterpretAsCommand.phpat line 89
808182838485868788899091 
            if (in_array($command, [$this->WILL, $this->WONT])) {
                $socket->write($this->IAC . $this->DONT . $option);
                return true;
            }
        } catch (Exception $e) {
            throw new TelnetException('failed negotiating IAC', 0, $e);
        }
 
        throw new UndefinedCommandException($command);
    }
}
2. in /vendor/graze/telnet-client/src/TelnetClient.php at line 240– Graze\TelnetClient\InterpretAsCommand::interpret('', Socket\Raw\Socket)
234235236237238239240241242243244245246            }
 
            if (in_array($character, [$this->NULL, $this->DC1])) {
                break;
            }
 
            if ($this->interpretAsCommand->interpret($character, $this->socket)) {
                continue;
            }
 
            $buffer .= $character;
 
            // check for prompt
3. in /vendor/graze/telnet-client/src/TelnetClient.php at line 199– Graze\TelnetClient\TelnetClient::getResponse('User password:', null)
193194195196197198199200201202203204205    {
        if (!$this->socket) {
            throw new TelnetException('attempt to execute without a connection - call connect first');
        }
 
        $this->write($command);
        return $this->getResponse($prompt, $promptError);
    }
 
    /**
     * @param string $command
     *
     * @return void
4. in /index.php at line 170– Graze\TelnetClient\TelnetClient::execute('admin', 'User password:')

How to set connection timeout

Hi!

I have a question about setting a connection timeout. I played a litte with your documented "$client->getSocket()->setOption()" but I think this way only works if the socket was created successfully?

Greetings,
Sebastian

Login gateway timeout

I am trying to use the telnet-client to display a cli replica output. Below is the commands I need to execute but I don't appear to get a connection.

<?php
require "vendor/autoload.php";
$client = Graze\TelnetClient\TelnetClient::factory();

 $dsn = "00.00.00.000:23";
 $client->connect($dsn, "login:");

 $command1 = "LOGIN";
 $prompt = "password:";
 $resp1 = $client->execute($command1, $prompt);

 var_dump($resp1);

 $command2 = "PASSWORD";
 $prompt = "FOC-LABS-02>";
 $resp2 = $client->execute($command2, $prompt);

 var_dump($resp2);

 $command3 = "bridge show";
 $prompt = "<SPACE> for next page, <CR> for next line, A for all, Q to quit";
 $resp3 = $client->execute($command3, $prompt);

 var_dump($resp3);

 $command4 = "a";
 $prompt = "[0-9] Bridge Interfaces displayed"; // this is the last word displayed after all data is returned
 $resp4 = $client->execute($command4, $prompt);

 var_dump($resp4);
```

When I just run the connect code 
```
$dsn = "10.45.10.100:23";
$client->connect($dsn);

echo "<pre>";
print_r($client);
echo "</pre>";
```
```
The response is
Graze\TelnetClient\TelnetClient Object
(
    [socketFactory:protected] => Socket\Raw\Factory Object
        (
        )

    [promptMatcher:protected] => Graze\TelnetClient\PromptMatcher Object
        (
            [matches:protected] => Array
                (
                )

            [responseText:protected] => 
        )

    [interpretAsCommand:protected] => Graze\TelnetClient\InterpretAsCommand Object
        (
            [WILL:protected] => �
            [WONT:protected] => �
            [DO:protected] => �
            [DONT:protected] => �
            [IAC:protected] => �
        )

    [prompt:protected] => \$
    [promptError:protected] => ERROR
    [lineEnding:protected] => 

    [maxBytesRead:protected] => 0
    [socket:protected] => Socket\Raw\Socket Object
        (
            [resource:Socket\Raw\Socket:private] => Socket Object
                (
                )

        )

    [buffer:protected] => 
    [NULL:protected] => 
    [DC1:protected] => �
    [IAC:protected] => 
)
```
I'm not sure what to look for, any ideas?

Undefined constant "Socket\Raw\AF_INET"

I am getting this error
Undefined constant "Socket\Raw\AF_INET"
in file
\vendor\clue\socket-raw\src\Factory.php:78

Code

$host = "aspmx.l.google.com";
    $port = 25;

    $client = Graze\TelnetClient\TelnetClient::factory();
    $dsn = $host.":".$port;
    $client->connect($dsn);

Can't get login to work on MS Telnet

I can't seem to get this to work with MS Telnet Server. The program just hangs

This is an output of a successful connection:

Trying 192.168.50.59...
Connected to 192.168.50.59.
Escape character is '^]'.
Welcome to Microsoft Telnet Service

login: erick
password:

*===============================================================
Microsoft Telnet Server.
*===============================================================

This is the code I'm using:

$host = '192.168.50.59';
$port = 23;
$telnet = TelnetClient::factory();
$telnet->connect("$host:$port");
var_dump($telnet->execute('erick', 'password:'));

This is what I get when I var_dump the buffer:

string(47) "Welcome to Microsoft Telnet Service

login: "

So the connection seems to be working as the buffer is loading but then it just hangs when I try to log in

Error prompt not detected if prompt is set to empty string

If $prompt is set to an empty string ("") and $promptError is set as non-empty (eg. "ERROR") then any error condition is never detected.

Using the example from the README, this is what would happen:

Graze\TelnetClient\TelnetResponse {#188
  #isError: false
  #responseText: "I'm sorry, Dave. I'm afraid I can't do that\nERROR"
  #promptMatches: array:1 [
    0 => ""
  ]
}

The reason that this happens is that prompt checking (getResponse() in Graze\TelnetClient\TelnetClient) happens before error checking. In the case of an empty prompt it always matches and so the error prompt check never happens.

Some thoughts on fixes:

  • Change the ordering such that error prompt checking happens first.
  • Don't attempt any matching if a prompt is an empty string

Login Password only

Based on #9 and #15, I'm trying to login to my VLC Telnet socket with the following code:

use Graze\TelnetClient\TelnetClient;

class MyTelNet {

    function __construct

        // Get Client
        $this->c = TelnetClient::factory();

        // Connect
        $this->c->setLineEnding("\r\n");
        $this->c->connect('127.0.0.1:4212');

        // Authenticate
        $resp = $this->c->execute("myfancypasswordi\r\n", "Password: ");
        var_dump($resp);
    }
}

From which I receive the following error:

Socket\Raw\Exception: Socket operation failed: Connection refused (SOCKET_ECONNREFUSED)

Please suggest any other login attempt, the other issues doen't work. (Using localhost instead off 127.0.0.1 gives the same output)

A CLI successful login looks as follows:

pi@raspberrypi:~ $ telnet 127.0.0.1 4212
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
VLC media player 3.0.11 Vetinari
Password:
Welcome, Master
>

End sequence not found causing infinite loop in getResponse()

Running the following on the command line:

LOGIN:::01::UN=user01,PWD=pass01;

Results in a response similar to this:

\r\n
\n
   0 2018-11-11 11:11:11\r\n
M  01 COMPLD\r\n
   EN=0   ENDESC=Succeeded.\r\n
;

Running the following just hangs:

$client = Graze\TelnetClient\TelnetClient::factory();
$dsn = '127.0.0.1:23';
$client->connect($dsn);
$command = 'LOGIN:::01::UN=user01,PWD=pass01;';
$resp = $client->execute($command, ';');
var_dump($resp);

I get the full response when I dump out the buffer, but the script just hangs and does not print a response.

Environment

  • I believe the Telnet server is a windows machine

Background

  • I'm sending TL1 commands (Telecom)

Escape error

Package working but how to socket exit code send ? Escape character how to send telnet ?

I can't get the response

I am trying to access a Juniper Router
This is an output of a successful connection:

**************************************************************************************
                                 NOTICE TO USERS

 WARNING: YOU ARE LOGGED IN A XXX XXX SYSTEM. ALL INFORMATION IN THIS
SYSTEM IS CONFIDENTIAL. USE OF THIS SYSTEM BY ANY USER, AUTHORIZED OR
UNAUTHORIZED, CONSTITUTES EXPRESS CONSENT TO THIS MONITORING.
To protect the system from unauthorized use and to ensure that the system is
functioning properly, activities on this system are monitored and recorded
and subject to audit. Use of this system is expressed consent to such
monitoring and recording. Any unauthorized access or use of this Automated
Information System is prohibited and could be subject to criminal and civil
penalties.

 .......................

ADVERTENCIA: ESTA A PUNTO DE INGRESAR A UN SISTEMA DE XXX XXX. TODA LA
INFORMACION QUE SE ENCUENTRA EN ESTE SISTEMA ES CONFIDENCIAL. EL USO DE ESTE
SISTEMA POR CUALQUIER USUARIO, AUTORIZADO O NO, CONSTITUYE UN CONSENTIMIENTO
EXPRESO PARA SER MONITOREADO.
Para proteger este sistema de uso no autorizado y asegurar su buen
funcionamiento, todas las actividades estßn siendo monitoreadas y almacenadas
para efecto de auditoria. Cualquier acceso no autorizado y/o uso inadecuado
de este sistema estß prohibido y puede ser causa de acciones penales.

*************************************************************************************

HOSTNAME (ttyp0)

login: username
Password:

--- JUNOS 10.4R3.4 built 2011-03-19 21:36:24 UTC
{master}
username@HOSTNAME>

This is the code I'm using:

    $host = Host::find(3);
    $client = Graze\TelnetClient\TelnetClient::factory();

    $client->setLineEnding(null);
    $client->connect("{$host->ipaddress}:23", "username@{$host->name}>");

    $resp = $client->execute("\r\n", "login: ");
    var_dump($resp);
    $resp1 = $client->execute("username\r\n", "Password: ");
    var_dump($resp1);
    $resp2 = $client->execute("secret\r\n");
    var_dump($resp2);
    $resp3 = $client->execute("show version | no-more\r\n\r\n");
    var_dump($resp3);
    $resp4 = $client->execute("show version | no-more\r\n\r\n");
    var_dump($resp4);

This is what I get when I var_dump the buffer:

var_dump($resp);

object(Graze\TelnetClient\TelnetResponse)#319 (3) {
  ["isError":protected]=>
  bool(false)
  ["responseText":protected]=>
  string(0) ""
  ["promptMatches":protected]=>
  array(0) {
  }
}

var_dump($resp1);

object(Graze\TelnetClient\TelnetResponse)#320 (3) {
  ["isError":protected]=>
  bool(false)
  ["responseText":protected]=>
  string(0) ""
  ["promptMatches":protected]=>
  array(0) {
  }
}

var_dump($resp2);

object(Graze\TelnetClient\TelnetResponse)#323 (3) {
  ["isError":protected]=>
  bool(false)
  ["responseText":protected]=>
  string(0) ""
  ["promptMatches":protected]=>
  array(0) {
  }
}

var_dump($resp3);

object(Graze\TelnetClient\TelnetResponse)#303 (3) {
  ["isError":protected]=>
  bool(false)
  ["responseText":protected]=>
  string(91) "

login: login: Password:

--- JUNOS 10.4R3.4 built 2011-03-19 21:36:24 UTC
{master}
"
  ["promptMatches":protected]=>
  array(1) {
    [0]=>
    string(25) "username@HOSTNAME>"
  }
}

var_dump($resp4);

object(Graze\TelnetClient\TelnetResponse)#315 (3) {
  ["isError":protected]=>
  bool(false)
  ["responseText":protected]=>
  string(1034) " show version | no-more 
Hostname: HOSTNAME
Model: m20
JUNOS Base OS boot [10.4R3.4]
...
{master}
"
  ["promptMatches":protected]=>
  array(1) {
    [0]=>
    string(25) "username@HOSTNAME>"
  }
}

for some reason the first variables don't show me the server's response #

unable to create socket connection

When attempting to run the initial tests the following fault appears:

"unable to create socket connection to [127.0.0.1:23]"

The development machine has permission released on port 23 for telnet access.
I could not get a resolution of the problem, can you help me?

How to check for prompt and include it in response text

Thanks for the great package,

My response is XML and I'm able to get the response (and avoid the endless loop #17 ) by using the below command

$response = $client->execute($command,preg_quote('</response>','/'));

I'm waiting for </response>

However getResponseText() returns everything but the </response> invalidating the xml.

How do I keep the end sequence in the response please?

Thank you!

Issue when command returns nothing apart from Prompt

I'm sending Telnet commands to a Draytek router. My setup is as follows:

$port = 23;
$host = '192.168.1.1';
$username = REMOVED;
$password = REMOVED;
$verbosity = 0;
$debug = 1;
$loginPrompt = 'Account:';
$passPrompt = 'Password: ';
$prompt = 'Tek> ';
$pruneCtrlSeq = true;

When I send a "object schedule view 2" command, I get a response:

Array
(
    [0] => object schedule view 2
    [1] => Index No.2
    [2] => 
    [3] => --------------------------------------------------
    [4] => 
[v] Enable Schedule Setup
    [5] =>         Comment [ TV Inpromptu ]
    [6] =>         Start Date (yyyy-mm-dd)  [ 2021 ]-[ 10 ]-[ 30 ]
    [7] =>         Start Time (hh:mm)       [ 17 ]:[ 15 ]
    [8] =>         Duration Time (hh:mm)    [  1 ]:[  3 ]
    [9] =>         Action                   [ Force On ]
    [10] =>         Idle Timeout             [   0 ] minute(s).(max. 255, 0 for default)
    [11] =>         --------------------------------------------------------------------
    [12] =>         How Often
    [13] => 
         [v] Once
    [14] => 
DrayTek> 
)

Set commands return nothing other than the command prompt. So 'object schedule set 2 -d "1 0"' just returns "Draytek >"

If I send a "object schedule view 2" command after sending the set command things start getting a bit weird and I don't get proper replies.
First time I get:

Array
(
    [0] => bject schedule set 2 -d "1 3"
)

Second time I get:

Array
(
    [0] => 
    [1] => 
DrayTek> 
)

Is this a bug in TelnetClient.php or am I doing something wrong?

Thank you!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.