I use the following repo to connect via ssh to some system.
I was able to do it ,( I got client ready and on data event )
Now I want to see the folders of the app which I do ssh to it ,
any idea how I can do it ?
when I use the ssh via command line I was able to connect to the app
and simple by doing ls I can see the application folders etc
I use the following repo and this sample code
https://github.com/mscdex/ssh2
var conn = new Client();
conn.on('ready', function() {
console.log('Client :: ready');
conn.shell(function(err, stream) {
if (err) throw err;
stream.on('close', function() {
console.log('Stream :: close');
conn.end();
}).on('data', function(data) {
console.log('STDOUT: ' + data);
}).stderr.on('data', function(data) {
console.log('STDERR: ' + data);
});
stream.end('ls -l\nexit\n');
});
}).connect({
host: '192.168.100.100',
port: 22,
username: 'frylock',
privateKey: require('fs').readFileSync('/here/is/my/key')
});
Related
I have installed ssh2 in order to be able to connect from my Node.js server to MongoDB. First, when I run the code provided by documentation I take this Module not found: Error: Can't resolve 'cpu-features' in 'C:\Users\chris\Desktop\abot\node_modules\ssh2\lib\protocol' and this
Module not found: Error: Can't resolve './crypto/build/Release/sshcrypto.node' in 'C:\Users\chris\Desktop\abot\node_modules\ssh2\lib\protocol'
With a little resarch I understand that this module not found errors are for optional modules and do not have some impact. Second, I am trying to connect with this code provided by the documentation:
const { Client } = require('ssh2');
const conn = new Client();
conn.on('ready', () => {
console.log('Client :: ready');
conn.forwardOut('my local ip', 8000, '127.0.0.1', 27017, (err, stream) => {
if (err) throw err;
stream.on('close', () => {
console.log('TCP :: CLOSED');
conn.end();
}).on('data', (data) => {
console.log('TCP :: DATA: ' + data);
}).end([
'HEAD / HTTP/1.1',
'User-Agent: curl/7.27.0',
'Host: 127.0.0.1',
'Accept: */*',
'Connection: close',
'',
''
].join('\r\n'));
});
}).connect({
host: 'ip of the mongo server',
port: ssh port,
username: 'my user name',
password: 'my password'
});
Let me note that the server is configured to connect without providing the public key.
When I am running the code, I take these messages:
Client :: ready
TCP :: CLOSED
Note number 2. I can connect with ssh tunnel through python, but now I need to connect through node also but without results.
I have two backends. Backend A and Backend B.
Backend B sends and receives info using a socket server running at port 4243.
Then, with Backend A, I need to catch that info and save it. But I have to also have a socket server on Backend A running at port 4243.
The problem is that, when I run Backend A after running Backend B I receive the error "EADDRINUSE", because I'm using the same host:port on both apps.
If, for Backend A I use Python, the problem dissapear because I have a configuration for sockets that's called SO_REUSEADDR.
Here we have some examples:
https://www.programcreek.com/python/example/410/socket.SO_REUSEADDR
https://subscription.packtpub.com/book/networking-and-servers/9781849513463/1/ch01lvl1sec18/reusing-socket-addresses
But, I want to use JavaScript for coding my Backend A, so I was using the net package for coding the sockets, and I can't get it to work, because of the "EADDRINUSE" error.
The NodeJS documentation says that "All sockets in Node set SO_REUSEADDR already", but it doesn't seem to work for me...
This is my code so far:
// Step 0: Create the netServer and the netClient
console.log(`[DEBUG] Server will listen to: ${HOST}:${PORT}`);
console.log(`[DEBUG] Server will register with: ${AGENT_ID}`);
const netServer = net.createServer((c) => {
console.log('[netServer] Client connected');
c.on('message', (msg) => {
console.log('[netServer] Received `message`, MSG:', msg.toString());
});
c.on('*', (event, msg) => {
console.log('[netServer] Received `*`, EVENT:', event);
console.log('[netServer] Received `*`, MSG:', msg);
});
}).listen({
host: HOST, // 'localhost',
port: PORT, // 4243,
family: 4, // ipv4, same as socket.AF_INET for python
});
// Code copied from nodejs documentation page (doesn't make any difference)
netServer.on('error', function (e) {
if (e.code == 'EADDRINUSE') {
console.log('Address in use, retrying...');
setTimeout(function () {
netServer.close();
netServer.listen(PORT, HOST);
}, 1000);
}
});
const netClient = net.createConnection(PORT, HOST, () => {
console.log('[netClient] Connected');
});
// Step 1: Register to instance B of DTN with agent ID 'bundlesink'
netClient.write(serializeMessage({
messageType: AAPMessageTypes.REGISTER,
eid: AGENT_ID,
}));
With this code, I get the following output in the terminal:
But, with the Python code, the socket connects successfully:
I don't know what to do :(
I hope I get some help here.
Edit 1
By the way, the lsof command, throws me this output for the JavaScript backend:
And this other output for the Python backend:
Edit 2
It really seems to be a problem with JavaScript. I also found this snippet:
var net = require('net');
function startServer(port, host, callback) {
var server = net.createServer();
server.listen(port, host, function() {
callback(undefined, server);
});
server.on('error', function(error) {
console.error('Ah damn!', error);
callback(error);
});
}
startServer(4000, '0.0.0.0', function(error, wildcardServer) {
if (error) return;
startServer(4000, '127.0.0.1', function(error, localhostServer) {
if (error) return;
console.log('Started both servers!');
});
});
From this post:
https://medium.com/#eplawless/node-js-is-a-liar-sometimes-8a28196d56b6
As the author says:
Well, that prints “Started both servers!” which is exactly what we don’t want.
But for me, instead of printing that, I get an error:
Ah damn! Error: listen EADDRINUSE: address already in use 127.0.0.1:4000
at Server.setupListenHandle [as _listen2] (node:net:1319:16)
at listenInCluster (node:net:1367:12)
at doListen (node:net:1505:7)
at processTicksAndRejections (node:internal/process/task_queues:84:21) {
code: 'EADDRINUSE',
errno: -98,
syscall: 'listen',
address: '127.0.0.1',
port: 4000
}
I really cannot make it to run and print "Started both servers!".
Because that's what I want my code to do.
Edit 3
This is the Python server socket: https://gitlab.com/d3tn/ud3tn/-/blob/master/tools/aap/aap_receive.py
This is the important part:
addr = (args.tcp[0], int(args.tcp[1])) # args.tcp[0] = "localhost", args.tcp[1] = "4243"
with AAPTCPClient(address=addr) as aap_client:
aap_client.register(args.agentid) # args.agentid = "bundlesink"
run_aap_recv(aap_client, args.count, args.verify_pl)
It creates an AAPTCPClient, and the only thing that AAPTCPClient does, is the following:
def __init__(self, socket, address):
self.socket = socket
self.address = address
self.node_eid = None
self.agent_id = None
def register(self, agent_id=None):
"""Attempt to register the specified agent identifier.
Args:
agent_id: The agent identifier to be registered. If None,
uuid.uuid4() is called to generate one.
"""
self.agent_id = agent_id or str(uuid.uuid4())
logger.info(f"Sending REGISTER message for '{agent_id}'...")
msg_ack = self.send(
AAPMessage(AAPMessageType.REGISTER, self.agent_id)
)
assert msg_ack.msg_type == AAPMessageType.ACK
logger.info("ACK message received!")
def send(self, aap_msg):
"""Serialize and send the provided `AAPMessage` to the AAP endpoint.
Args:
aap_msg: The `AAPMessage` to be sent.
"""
self.socket.send(aap_msg.serialize())
return self.receive()
def receive(self):
"""Receive and return the next `AAPMessage`."""
buf = bytearray()
msg = None
while msg is None:
data = self.socket.recv(1)
if not data:
logger.info("Disconnected")
return None
buf += data
try:
msg = AAPMessage.parse(buf)
except InsufficientAAPDataError:
continue
return msg
I don't see any bind, and I don't understand why the python code can call "socket.recv", but in my JavaScript code I can't do "netServer.listen". I think it should be the same.
There are things to clarify.
1.) The client uses the bind syscall where the kernel selects the source port automatically.
It does so by checking sys local_portrange sysctl settings.
1.) If you want to bind the client to a static source port, be sure to select a TCP port outside the local_portrange range !
2.) You cannot subscribe to event "*", instead you've to subscribe to the event "data" to receive messages.
For best practice you should also subscribe to the "error" event in case of errors !
These links will get you started right away:
How do SO_REUSEADDR and SO_REUSEPORT differ?
https://idea.popcount.org/2014-04-03-bind-before-connect/
So, for all beginners, who want to dig deeper into networking using node.js…
A working server example:
// Step 0: Create the netServer and the netClient
//
var HOST = 'localhost';
var PORT = 4243;
var AGENT_ID = 'SO_REUSEADDR DEMO';
var net = require('net');
console.log(`[DEBUG] Server will listen to: ${HOST}:${PORT}`);
console.log(`[DEBUG] Server will register with: ${AGENT_ID}`);
const netServer = net.createServer((c) => {
console.log('[netServer] Client connected');
c.on('data', (msg) => {
console.log('[netServer] Received `message`, MSG:', msg.toString());
});
c.on('end', () => {
console.log('client disconnected');
});
c.on('error', function (e) {
console.log('Error: ' + e.code);
});
c.write('hello\r\n');
c.pipe(c);
}).listen({
host: HOST,
port: PORT,
family: 4, // ipv4, same as socket.AF_INET for python
});
// Code copied from nodejs documentation page (doesn't make any difference)
netServer.on('error', function (e) {
console.log('Error: ' + e.code);
if (e.code == 'EADDRINUSE') {
console.log('Address in use, retrying...');
setTimeout(function () {
netServer.close();
netServer.listen(HOST, PORT);
}, 1000);
}
if ( e.code = 'ECONNRESET' ){
console.log('Connection reset by peer...');
setTimeout(function () {
netServer.close();
netServer.listen(HOST, PORT);
}, 1000);
}
});
The Client:
/* Or use this example tcp client written in node.js. (Originated with
example code from
http://www.hacksparrow.com/tcp-socket-programming-in-node-js.html.) */
var net = require('net');
var HOST = 'localhost';
var PORT = 4243;
var client = new net.Socket();
client.setTimeout(3000);
client.connect(PORT, HOST, function() {
console.log("Connected to " + client.address().address + " Source Port: " + client.address().port + " Family: " + client.address().family);
client.write('Hello, server! Love, Client.');
});
client.on('data', function(data) {
console.log('Received: ' + data);
client.end();
});
client.on('error', function(e) {
console.log('Error: ' + e.code);
});
client.on('timeout', () => {
console.log('socket timeout');
client.end();
});
client.on('close', function() {
console.log('Connection closed');
});
Best Hannes
Steffen Ullrich was completely right.
In my JavaScript code, I was trying to create a server to listen to the port 4243.
But you don't need to have a server in order to listen to some port, you can listen with a client too! (At least that's what I understood)
You can create a client connection as following:
const netClient = net.createConnection(PORT, HOST, () => {
console.log('[netClient] Connected');
});
netClient.on('data', (data) => {
console.log('[netClient] Received data:', data.toString('utf8'));
});
And with "client.on", then you can receive messages as well, as if it were a server.
I hope this is useful to someone else.
I'm running a javascript test that checks some remote file details using the nodejs package ssh2.
My current code works Ok, and the tests completes in a matter of seconds;
var Client = require('ssh2').Client;
var conn = new Client();
conn.on('ready', function() {
console.log('Client :: ready');
conn.sftp(function(err, sftp) {
if (err) throw err;
sftp.readdir('parkersreviewcontent/', function(err, list) {
if (err) throw err;
.... run some assertion...
conn.end();
});
});
})
.connect({
host: '******',
port: **,
user: '****',
password: '****',
});
The next step is for me to run this test as part of my nightwatchjs test suite, using a tag.
var Client = require('ssh2').Client;
var conn = new Client();
module.exports = {
'#tags': ['bugs']
};
conn.on('ready', function() {
console.log('Client :: ready');
conn.sftp(function(err, sftp) {
if (err) throw err;
sftp.readdir('parkersreviewcontent/', function(err, list) {
if (err) throw err;
.... run some assertion...
conn.end();
});
});
})
.connect({
host: '******',
port: **,
user: '****',
password: '****',
});
However, when I now run the test (with the tag added) via the tag it takes about 5 minutes to run (i.e. for the command prompt to be available again, the actual test again takes 1-2 seconds to perform).
Have I placed the tag command in the wrong place in the script?
Or, is there a command that I need to add that will 'close' the test once its run when using the tag?
Any help would be greatly appreciated. Thanks.
I am establishing a good connection with my Linux server. What I want to do now is running some shell commands after I got the connection with the server like doing automation for example cd images after that mkdir newFolder etc.
The main idea of this is to connect to a Linux server from a webpage and when I click some buttons it will establish a connection to that server and some work like restarting Apache or bouncing the application by running a script.
var fs = require('fs');
var path = require('path');
var server = require('http').createServer(onRequest);
var io = require('socket.io')(server);
var SSHClient = require('ssh2').Client;
// Load static files into memory
var staticFiles = {};
var basePath = path.join(require.resolve('xterm'), '..');
staticFiles['/xterm.css'] = fs.readFileSync(path.join(basePath, '../css/xterm.css'));
staticFiles['/xterm.js'] = fs.readFileSync(path.join(basePath, 'xterm.js'));
basePath = path.join(require.resolve('xterm-addon-fit'), '..');
staticFiles['/xterm-addon-fit.js'] = fs.readFileSync(path.join(basePath, 'xterm-addon-fit.js'));
staticFiles['/'] = fs.readFileSync('index.html');
// Handle static file serving
function onRequest(req, res) {
var file;
if (req.method === 'GET' && (file = staticFiles[req.url])) {
res.writeHead(200, {
'Content-Type': 'text/'
+ (/css$/.test(req.url)
? 'css'
: (/js$/.test(req.url) ? 'javascript' : 'html'))
});
return res.end(file);
}
res.writeHead(404);
res.end();
}
io.on('connection', function(socket) {
var conn = new SSHClient();
conn.on('ready', function() {
socket.emit('data', '\r\n*** SSH CONNECTION ESTABLISHED ***\r\n');
conn.shell(function(err, stream) {
if (err)
return socket.emit('data', '\r\n*** SSH SHELL ERROR: ' + err.message + ' ***\r\n');
socket.on('data', function(data) {
stream.write(data);
});
stream.on('data', function(d) {
socket.emit('data', d.toString('binary'));
}).on('close', function() {
conn.end();
});
});
}).on('close', function() {
socket.emit('data', '\r\n*** SSH CONNECTION CLOSED ***\r\n');
}).on('error', function(err) {
socket.emit('data', '\r\n*** SSH CONNECTION ERROR: ' + err.message + ' ***\r\n');
}).connect({
host: '192.168.560.1',
port: 22,
username: 'USER',
password: 'anything'
});
});
let port = 8000;
console.log('Listening on port', port)
server.listen(port);
To execute the linux commands on the so created ssh terminal do as below:
Before this snippet:
socket.on('data', function(data) {
stream.write(data);
});
Add stream.write('ls');
I have a working node.js Server that uses a socket.io websocket connection and ssh2 connection to open a shell and return it to a react client in the browser that uses xterm-for-react. I'm now trying to also tunnel a port over the same ssh connection but am having some difficulty. The code is below and the commented out part is where I've been trying to do the port forwarding - equivalent to
ssh -L 2233:192.168.2.1:80 test#192.168.0.65
const socketIO = require("socket.io");
const sshClient = require("ssh2").Client;
const utf8 = require("utf8");
const fs = require("fs");
class SocketServiceFwd {
constructor() {
this.socket = null;
this.pty = null;
this.devicesList = [
{
name: "Device 1",
host: "192.168.0.65",
port: "22",
username: "test",
password: "test12345",
},
];
attachServer(server) {
if (!server) {
throw new Error("Server not found...");
}
const io = socketIO(server, {cors: {origin: "*",},});
console.log("Created socket server. Waiting for client connection.");
// "connection" event happens when any client connects to this io instance.
io.on("connection", (socket) => {
console.log("Client connect to socket.", socket.id);
this.socket = socket;
const ssh = new sshClient();
this.socket.on("devices", (cb) => {
console.log("Get devices list from " + socket.id);
return cb(null,this.devicesList.map((d) => ({ name: d.name }))
);
});
this.socket.on("connectToDevice", (deviceName) => {
console.log(socket.id + " connecting to device " + deviceName);
const selectedDevice = this.devicesList.find(
(d) => d.name === deviceName
);
if (selectedDevice) {
ssh.on("ready", function () {
console.log(socket.id + " successfully connected to " + deviceName);
socket.emit("output", "\r\n*** SSH CONNECTION ESTABLISHED ***\r\n");
// ssh.forwardOut("127.0.0.1", 2233, "192.168.2.1", 80,
// (err, stream) => {
// console.log(
// "ssh forwardOut '127.0.0.1:2233' '192.168.2.1:80'"
// );
// if (err)
// return socket.emit(
// "output",
// "\r\n*** SSH FORWARDOUT ERROR: " + err.message + " ***\r\n"
// );
// }
// );
ssh.shell(function (err, stream) {
if (err)
return socket.emit(
"output",
"\r\n*** SSH SHELL ERROR: " + err.message + " ***\r\n"
);
socket.on("input", function (data) {
stream.write(data);
});
stream.on("data", function (d) {
socket.emit("output", utf8.decode(d.toString("binary")));
});
stream.on("close", function () {
console.log(socket.id + " terminal stream close");
ssh.end();
});
});
});
ssh.on("close", function () {
console.log(socket.id + " ssh connection closed to " + deviceName);
socket.emit("output", "\r\n*** SSH CONNECTION CLOSED ***\r\n");
socket.removeListener("input", () => {});
});
ssh.on("error", function (err) {
console.log(err);
socket.emit("output","\r\n*** SSH CONNECTION ERROR: " + err.message + " ***\r\n");
});
ssh.connect(selectedDevice);
}
});
this.socket.on("disconnectFromDevice", () => {
console.log(socket.id + " disconnecting from device");
ssh.destroy();
});
});
}
}
module.exports = SocketServiceFwd;
***** EDITED *****
It would be great if someone could please provide some advice :-) I have been pushing ahead but still need some assistance...
I have had a little more success using the npm "tunnel-ssh" module. The tunnel does open long enough for me to view the website but shortly after that, the tunnel stops working. Is there something else I'm supposed to be doing after opening the tunnel?
The code below goes where the commented out section above is. I have tried to follow the examples I've seen online - can anyone please advise me what I'm doing wrong?
I'm running DEBUG=* in my npm start and see the following :
tunnel-ssh sshConnection:ready +3s
tunnel-ssh sshConnection:ready +1ms
tunnel-ssh sshStream:create +19ms
tunnel-ssh sshStream:create +0ms
TCP :: ERROR: read ECONNRESET
TCP :: ERROR: read ECONNRESET
So It's clear that the tunnel starts up but then an error occurs. Often the connection recovers and I can continue browsing the website through the tunnel, but eventually an unrecoverable error occurs. So the tunnel is unstable. If i run the tunnel using openssh it is stable. Therefore my question really now boils down to a request for assistance in determining reasons for the instability. Am I not handling something in my code or my configuration correctly? Please Help! Note also, that despite this my shell session continues to work without any problem.
const tunnel = require("tunnel-ssh");
const tnl = tunnel({host: '192.168.0.65', username: 'test', password: 'test12345',
dstHost: '192.168.2.1', dstPort: 80, localHost: '127.0.0.1',
localPort: 2233}, (er, stream) => {
if(er) {
console.log("something went wrong " + er.message);
stream.close();
}
stream.on("data", (data) => {
console.log("TCP :: DATA: " + data);
});
stream.on("error", (error) => {
console.log("TCP :: ERROR: " + error.message);
});
});