293 lines
10 KiB
JavaScript
293 lines
10 KiB
JavaScript
// https://www.npmjs.com/package/another-telnet-client
|
|
(function () {
|
|
"use strict";
|
|
|
|
var util = require('util');
|
|
var events = require('events');
|
|
var net = require('net');
|
|
|
|
|
|
// define a constructor (object) and inherit EventEmitter functions
|
|
function Telnet() {
|
|
events.EventEmitter.call(this);
|
|
if (false === (this instanceof Telnet)) {
|
|
return new Telnet();
|
|
}
|
|
}
|
|
|
|
util.inherits(Telnet, events.EventEmitter);
|
|
|
|
Telnet.prototype.connect = function (opts) {
|
|
var self = this;
|
|
var host = (typeof opts.host !== 'undefined' ? opts.host : '127.0.0.1');
|
|
var port = (typeof opts.port !== 'undefined' ? opts.port : 23);
|
|
this.timeout = (typeof opts.timeout !== 'undefined' ? opts.timeout : 500);
|
|
this.shellPrompt = (typeof opts.shellPrompt !== 'undefined' ? opts.shellPrompt : /(?:\/ )?#\s/);
|
|
this.loginPrompt = (typeof opts.loginPrompt !== 'undefined' ? opts.loginPrompt : /login[: ]*$/i);
|
|
this.passwordPrompt = (typeof opts.passwordPrompt !== 'undefined' ? opts.passwordPrompt : /Password: /i);
|
|
this.username = (typeof opts.username !== 'undefined' ? opts.username : 'root');
|
|
this.password = (typeof opts.password !== 'undefined' ? opts.password : 'guest');
|
|
this.enable = (typeof opts.enable !== 'undefined' ? opts.enable : false);
|
|
this.enablePrompt = (typeof opts.enablePrompt !== 'undefined' ? opts.enablePrompt : /Password: /i);
|
|
this.enablePassword = (typeof opts.enablePassword !== 'undefined' ? opts.enablePassword : 'enablepass');
|
|
this.irs = (typeof opts.irs !== 'undefined' ? opts.irs : '\r\n');
|
|
this.ors = (typeof opts.ors !== 'undefined' ? opts.ors : '\n');
|
|
this.echoLines = (typeof opts.echoLines !== 'undefined' ? opts.echoLines : 1);
|
|
this.pageSeparator = (typeof opts.pageSeparator !== 'undefined' ? opts.pageSeparator : '---- More');
|
|
this.ignoreOutput = (typeof opts.ignoreOutput !== 'undefined' ? opts.ignoreOutput : false);
|
|
this.ignoreOutputTimeout = (typeof opts.ignoreOutputTimeout !== 'undefined' ? opts.ignoreOutputTimeout : 1000);
|
|
this.response = '';
|
|
this.telnetState = null;
|
|
|
|
this.telnetSocket = net.createConnection({
|
|
port: port,
|
|
host: host
|
|
}, function () {
|
|
self.telnetState = 'start';
|
|
self.stringData = '';
|
|
self.emit('connect');
|
|
});
|
|
|
|
this.telnetSocket.setTimeout(this.timeout, function () {
|
|
if (self.telnetSocket._connecting === true) {
|
|
// info: cannot connect; emit error and destroy
|
|
self.emit('error', 'Cannot connect');
|
|
|
|
self.telnetSocket.destroy();
|
|
}
|
|
else {
|
|
self.emit('timeout');
|
|
}
|
|
});
|
|
|
|
this.telnetSocket.on('data', function (data) {
|
|
parseData(data, self);
|
|
});
|
|
|
|
this.telnetSocket.on('error', function (error) {
|
|
self.emit('error', error);
|
|
});
|
|
|
|
this.telnetSocket.on('end', function () {
|
|
self.emit('end');
|
|
});
|
|
|
|
this.telnetSocket.on('close', function () {
|
|
self.emit('close');
|
|
});
|
|
};
|
|
|
|
Telnet.prototype.exec = function (cmd, opts, callback) {
|
|
var self = this;
|
|
cmd += this.ors;
|
|
|
|
if (opts && opts instanceof Function) {
|
|
callback = opts;
|
|
}
|
|
else if (opts && opts instanceof Object) {
|
|
self.shellPrompt = opts.shellPrompt || self.shellPrompt;
|
|
self.loginPrompt = opts.loginPrompt || self.loginPrompt;
|
|
self.timeout = opts.timeout || self.timeout;
|
|
self.irs = opts.irs || self.irs;
|
|
self.ors = opts.ors || self.ors;
|
|
self.echoLines = opts.echoLines || self.echoLines;
|
|
self.ignoreOutput = opts.ignoreOutput || self.ignoreOutput;
|
|
self.ignoreOutputTimeout = opts.ignoreOutputTimeout || self.ignoreOutputTimeout;
|
|
}
|
|
|
|
if (this.telnetSocket.writable) {
|
|
this.telnetSocket.write(cmd, function () {
|
|
self.telnetState = 'response';
|
|
self.emit('writedone');
|
|
|
|
if (self.ignoreOutput === true) {
|
|
setTimeout(function () {
|
|
self.ignoreOutput = false;
|
|
callback(null);
|
|
}, self.ignoreOutputTimeout);
|
|
} else {
|
|
self.once('responseready', function () {
|
|
if (callback && self.cmdOutput !== undefined) {
|
|
callback(self.cmdOutput.join('\n'));
|
|
}
|
|
else if (callback && self.cmdOutput === undefined) {
|
|
callback(null);
|
|
}
|
|
|
|
// reset stored response
|
|
self.stringData = '';
|
|
});
|
|
}
|
|
|
|
});
|
|
} else {
|
|
callback(new Error("Socket not writable"));
|
|
}
|
|
};
|
|
|
|
Telnet.prototype.end = function () {
|
|
this.telnetSocket.end();
|
|
};
|
|
|
|
Telnet.prototype.destroy = function () {
|
|
this.telnetSocket.destroy();
|
|
};
|
|
|
|
function parseData(chunk, telnetObj) {
|
|
var promptIndex = '';
|
|
var tempStringData = '';
|
|
|
|
if (chunk[0] === 255 && chunk[1] !== 255) {
|
|
telnetObj.stringData = '';
|
|
var negReturn = negotiate(telnetObj, chunk);
|
|
|
|
if (negReturn === undefined) {
|
|
return;
|
|
}
|
|
else {
|
|
chunk = negReturn;
|
|
}
|
|
}
|
|
|
|
if (telnetObj.ignoreOutput === true) {
|
|
telnetObj.stringData = '';
|
|
return;
|
|
}
|
|
|
|
if (telnetObj.telnetState === 'start') {
|
|
telnetObj.telnetState = 'getprompt';
|
|
}
|
|
|
|
if (telnetObj.telnetState === 'getprompt') {
|
|
tempStringData = chunk.toString();
|
|
promptIndex = tempStringData.search(telnetObj.shellPrompt);
|
|
|
|
if (promptIndex !== -1) {
|
|
telnetObj.shellPrompt = tempStringData.substring(promptIndex);
|
|
telnetObj.telnetState = 'sendcmd';
|
|
telnetObj.stringData = '';
|
|
telnetObj.emit('ready', telnetObj.shellPrompt);
|
|
}
|
|
else if (tempStringData.search(telnetObj.loginPrompt) !== -1) {
|
|
telnetObj.telnetState = 'login';
|
|
login(telnetObj, 'username');
|
|
}
|
|
else if (tempStringData.search(telnetObj.passwordPrompt) !== -1) {
|
|
telnetObj.telnetState = 'login';
|
|
login(telnetObj, 'password');
|
|
}
|
|
}
|
|
else if (telnetObj.telnetState === 'enable') {
|
|
tempStringData = chunk.toString();
|
|
|
|
if (tempStringData.search(telnetObj.enablePrompt) !== -1) {
|
|
telnetObj.telnetState = 'login';
|
|
login(telnetObj, 'enablePassword');
|
|
}
|
|
}
|
|
else if (telnetObj.telnetState === 'getenprompt') {
|
|
tempStringData = chunk.toString();
|
|
|
|
if (tempStringData.search(telnetObj.shellPrompt) !== -1) {
|
|
telnetObj.telnetState = 'login';
|
|
login(telnetObj, 'enable');
|
|
}
|
|
}
|
|
else if (telnetObj.telnetState === 'response') {
|
|
tempStringData = chunk.toString();
|
|
telnetObj.stringData += tempStringData;
|
|
promptIndex = tempStringData.search(telnetObj.shellPrompt);
|
|
|
|
if (promptIndex === -1 && tempStringData.length !== 0) {
|
|
if (tempStringData.search(telnetObj.pageSeparator) !== -1) {
|
|
telnetObj.telnetSocket.write(Buffer('20', 'hex'));
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
telnetObj.cmdOutput = telnetObj.stringData.split(telnetObj.irs);
|
|
|
|
for (var i = 0; i < telnetObj.cmdOutput.length; i++) {
|
|
if (telnetObj.cmdOutput[i].search(telnetObj.pageSeparator) !== -1) {
|
|
telnetObj.cmdOutput.splice(i, 1);
|
|
}
|
|
}
|
|
|
|
if (telnetObj.echoLines === 1) {
|
|
telnetObj.cmdOutput.shift();
|
|
}
|
|
else if (telnetObj.echoLines > 1) {
|
|
telnetObj.cmdOutput.splice(0, telnetObj.echoLines);
|
|
}
|
|
|
|
// remove prompt
|
|
telnetObj.cmdOutput.pop();
|
|
|
|
telnetObj.emit('responseready');
|
|
}
|
|
}
|
|
|
|
function login(telnetObj, handle) {
|
|
if (handle === 'username') {
|
|
if (telnetObj.telnetSocket.writable) {
|
|
telnetObj.telnetSocket.write(telnetObj.username + telnetObj.ors, function () {
|
|
telnetObj.telnetState = 'getprompt';
|
|
});
|
|
}
|
|
}
|
|
else if (handle === 'password') {
|
|
if (telnetObj.telnetSocket.writable) {
|
|
telnetObj.telnetSocket.write(telnetObj.password + telnetObj.ors, function () {
|
|
if (telnetObj.enable) {
|
|
telnetObj.telnetState = 'getenprompt';
|
|
} else {
|
|
telnetObj.telnetState = 'getprompt';
|
|
}
|
|
});
|
|
}
|
|
}
|
|
else if (handle === 'enable') {
|
|
if (telnetObj.telnetSocket.writable) {
|
|
telnetObj.telnetSocket.write("en" + telnetObj.ors, function () {
|
|
telnetObj.telnetState = 'enable';
|
|
});
|
|
}
|
|
}
|
|
else if (handle === 'enablePassword') {
|
|
if (telnetObj.telnetSocket.writable) {
|
|
telnetObj.telnetSocket.write(telnetObj.enablePassword + telnetObj.ors, function () {
|
|
telnetObj.telnetState = 'getprompt';
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
function negotiate(telnetObj, chunk) {
|
|
// info: http://tools.ietf.org/html/rfc1143#section-7
|
|
// refuse to start performing and ack the start of performance
|
|
// DO -> WONT; WILL -> DO
|
|
var packetLength = chunk.length, negData = chunk, cmdData, negResp;
|
|
|
|
for (var i = 0; i < packetLength; i += 3) {
|
|
if (chunk[i] !== 255) {
|
|
negData = chunk.slice(0, i);
|
|
cmdData = chunk.slice(i);
|
|
break;
|
|
}
|
|
}
|
|
|
|
negResp = negData.toString('hex').replace(/fd/g, 'fc').replace(/fb/g, 'fd');
|
|
|
|
if (telnetObj.telnetSocket.writable) {
|
|
telnetObj.telnetSocket.write(Buffer(negResp, 'hex'));
|
|
}
|
|
|
|
if (cmdData !== undefined) {
|
|
return cmdData;
|
|
}
|
|
}
|
|
|
|
module.exports = Telnet;
|
|
}());
|