Skip to content
This repository was archived by the owner on Apr 5, 2018. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion lib/session.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,26 @@ function Session (server, session) {
})
}.bind(this)

session.onGlobalRequest = function (message) {
if (this._server._options.debug)
console.log('global request', message)

// if no "tcpipforward" listeners exist return failure
// otherwise assume success unless listener explicitly sends "replyDefault"
if (this.listeners('tcpipforward').length === 0)
message.replyDefault()

// tcpipforward, canceltcpipforward, etc
return this.emit(message.subtype, message)
}.bind(this)

session.onClose = function () {
if (this._server._options.debug)
console.log('onClose')

return this.emit('close')
}.bind(this)

EventEmitter.call(this)
}

Expand All @@ -39,4 +59,9 @@ Session.prototype.setAuthMethods = function (methods) {
return this
}

module.exports = Session
Session.prototype.openReverseForward = function (remotehost, remoteport, sourcehost, localport) {
var channel = this._session.openReverseForward(remotehost, remoteport, sourcehost, localport)
return new Channel(this._server, channel)
}

module.exports = Session
2 changes: 2 additions & 0 deletions src/channel.cc
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,8 @@ bool Channel::TryRead () {

int len;
do {
if (closed)
break;
char buf[1024];
len = ssh_channel_read_nonblocking(channel, buf, sizeof(buf), 0);
if (len > 0) {
Expand Down
22 changes: 22 additions & 0 deletions src/message.cc
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ void Message::Init () {
NODE_SET_PROTOTYPE_METHOD(tpl, "replyDefault", ReplyDefault);
NODE_SET_PROTOTYPE_METHOD(tpl, "replyAuthSuccess", ReplyAuthSuccess);
NODE_SET_PROTOTYPE_METHOD(tpl, "replySuccess", ReplySuccess);
NODE_SET_PROTOTYPE_METHOD(tpl, "replyGlobalMessageSuccess", ReplyGlobalMessageSuccess);
NODE_SET_PROTOTYPE_METHOD(tpl, "comparePublicKey", ComparePublicKey);
NODE_SET_PROTOTYPE_METHOD(tpl, "scpAccept", ScpAccept);
NODE_SET_PROTOTYPE_METHOD(tpl, "sftpAccept", SftpAccept);
Expand Down Expand Up @@ -184,6 +185,14 @@ v8::Handle<v8::Object> Message::NewInstance (
instance->Set(NanSymbol("ptyHeight"),
v8::Integer::New(ssh_message_channel_request_pty_height(message)));
}
} else if (type == SSH_REQUEST_GLOBAL) {
if (subtype == SSH_GLOBAL_REQUEST_TCPIP_FORWARD) {
const char *requestAddress = ssh_message_global_request_address(message);
if (requestAddress)
instance->Set(NanSymbol("requestAddress"), v8::String::New(requestAddress));
instance->Set(NanSymbol("requestPort"),
v8::Integer::New(ssh_message_global_request_port(message)));
}
}

return scope.Close(instance);
Expand Down Expand Up @@ -231,6 +240,19 @@ NAN_METHOD(Message::ReplyAuthSuccess) {
NanReturnUndefined();
}

NAN_METHOD(Message::ReplyGlobalMessageSuccess) {
NanScope();

//TODO: async
Message* m = node::ObjectWrap::Unwrap<Message>(args.This());

int port = 0;
if (args.Length() >= 1 && args[0]->IsNumber()) port = args[0]->Int32Value();
ssh_message_global_request_reply_success(m->message, port);

NanReturnUndefined();
}

NAN_METHOD(Message::ComparePublicKey) {
NanScope();

Expand Down
1 change: 1 addition & 0 deletions src/message.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class Message : public node::ObjectWrap {
static NAN_METHOD(ReplyDefault);
static NAN_METHOD(ReplyAuthSuccess);
static NAN_METHOD(ReplySuccess);
static NAN_METHOD(ReplyGlobalMessageSuccess);
static NAN_METHOD(ComparePublicKey);
static NAN_METHOD(ScpAccept);
static NAN_METHOD(SftpAccept);
Expand Down
147 changes: 129 additions & 18 deletions src/session.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <libssh/keys.h>
#include <libssh/socket.h>
#include <libssh/poll.h>
#include <libssh/messages.h>
#include <string.h>
#include "session.h"
#include "message.h"
Expand Down Expand Up @@ -54,6 +55,38 @@ void Session::OnNewChannel (v8::Handle<v8::Object> channel) {
}
}

void Session::OnGlobalRequest (v8::Handle<v8::Object> message) {
NanScope();

v8::Local<v8::Value> callback = NanObjectWrapHandle(this)
->Get(NanSymbol("onGlobalRequest"));

if (callback->IsFunction()) {
v8::TryCatch try_catch;
v8::Handle<v8::Value> argv[] = { message };
callback.As<v8::Function>()->Call(NanObjectWrapHandle(this), 1, argv);

if (try_catch.HasCaught())
node::FatalException(try_catch);
}
}

void Session::OnClose () {
NanScope();

v8::Local<v8::Value> callback = NanObjectWrapHandle(this)
->Get(NanSymbol("onClose"));

if (callback->IsFunction()) {
v8::TryCatch try_catch;
v8::Handle<v8::Value> argv[] = { };
callback.As<v8::Function>()->Call(NanObjectWrapHandle(this), 0, argv);

if (try_catch.HasCaught())
node::FatalException(try_catch);
}
}

void Session::ChannelClosedCallback (Channel *channel, void *userData) {
Session* s = static_cast<Session*>(userData);

Expand Down Expand Up @@ -213,6 +246,8 @@ void Session::Close () {
//ssh_disconnect(session);
if (NSSH_DEBUG)
std::cout << "Stopped polling session, " << channels.size() << " channels open\n";

OnClose();
}

void Session::SetAuthMethods (int methods) {
Expand All @@ -221,57 +256,93 @@ void Session::SetAuthMethods (int methods) {
std::cout << "Changed auth methods to " << methods << "\n";
}

ssh_channel Session::OpenReverseForward(const char *remotehost, int remoteport,
const char *sourcehost, int localport) {

if (NSSH_DEBUG)
std::cout << "ssh_channel_open_reverse_forward" << std::endl;

ssh_channel chan;
int rc;

chan = ssh_channel_new(session);
if (chan == NULL) {
return NULL;
}

if (sourcehost == NULL) sourcehost = "";

// TODO: make this asynchronous?
do {
rc = ssh_channel_open_reverse_forward(chan, remotehost, remoteport, sourcehost, localport);
} while (rc == SSH_AGAIN);

if (rc < 0) {
ssh_channel_free(chan);
chan = NULL;
}

return chan;
}

// a client callback (I think)
int SessionAuthCallback (const char *prompt, char *buf, size_t len,
int Session::AuthCallback (const char *prompt, char *buf, size_t len,
int echo, int verify, void *userdata) {

if (NSSH_DEBUG)
std::cout << "SessionAuthCallback\n";
std::cout << "Session::AuthCallback! " << std::endl;
return 0;
}

void SessionLogCallback (ssh_session session, int priority,
void Session::LogCallback (ssh_session session, int priority,
const char *message, void *userdata) {

if (NSSH_DEBUG)
std::cout << "SessionLogCallback " << priority << message
std::cout << "Session::LogCallback! " << priority << ", " << message
<< std::endl;
}

// not sure if this gets used
void SessionGlobalRequestCallback (ssh_session session, ssh_message message,
void *userdata) {
void Session::GlobalRequestCallback (ssh_session session, ssh_message message,
void *userData) {

int type = ssh_message_type(message);
int subtype = ssh_message_subtype(message);

if (NSSH_DEBUG)
std::cout << "SessionGlobalRequestCallback!\n";
std::cout << "Session::GlobalRequestCallback! " << type << ", " << subtype << std::endl;

Session* s = static_cast<Session*>(userData);
if (type == SSH_REQUEST_GLOBAL) {
s->OnGlobalRequest(Message::NewInstance(s->session, NULL, message));
}
}

// not used as far as I can tell
int Session::SessionMessageCallback (ssh_session session, ssh_message message, void *data) {
int Session::MessageCallback (ssh_session session, ssh_message message, void *data) {
if (NSSH_DEBUG)
std::cout << "SessionMessageCallback!\n";
std::cout << "Session::MessageCallback! " << std::endl;

return 1;
}

void SessionStatusCallback (void *userdata, float status) {
void Session::StatusCallback (void *userdata, float status) {
if (NSSH_DEBUG)
std::cout << "SessionStatusCallback: " << status << std::endl;
std::cout << "Session::StatusCallback! " << status << std::endl;
}


void Session::Start () {
/*

callbacks = new ssh_callbacks_struct;
callbacks->auth_function = SessionAuthCallback;
callbacks->log_function = SessionLogCallback;
callbacks->global_request_function = SessionGlobalRequestCallback;
callbacks->connect_status_function = SessionStatusCallback;
callbacks->auth_function = NULL; // Session::AuthCallback;
callbacks->log_function = NULL; // Session::LogCallback;
callbacks->global_request_function = Session::GlobalRequestCallback;
callbacks->connect_status_function = NULL; // Session::StatusCallback;
callbacks->userdata = this;
ssh_callbacks_init(callbacks);
ssh_set_callbacks(session, callbacks);
ssh_set_message_callback(session, SessionMessageCallback, this);
*/
// ssh_set_message_callback(session, Session::MessageCallback, this);

ssh_options_set(session, SSH_OPTIONS_TIMEOUT, "0");
ssh_options_set(session, SSH_OPTIONS_TIMEOUT_USEC, "1");
Expand Down Expand Up @@ -303,6 +374,8 @@ void Session::Init () {
tpl->SetClassName(NanSymbol("Session"));
tpl->InstanceTemplate()->SetInternalFieldCount(1);
NODE_SET_PROTOTYPE_METHOD(tpl, "close", Close);
NODE_SET_PROTOTYPE_METHOD(tpl, "setAuthMethods", SetAuthMethods);
NODE_SET_PROTOTYPE_METHOD(tpl, "openReverseForward", OpenReverseForward);
}

v8::Handle<v8::Object> Session::NewInstance (ssh_session session) {
Expand Down Expand Up @@ -354,4 +427,42 @@ NAN_METHOD(Session::SetAuthMethods) {
NanReturnUndefined();
}

NAN_METHOD(Session::OpenReverseForward) {
NanScope();

char *remotehost = NULL, *sourcehost = NULL;
int remoteport = 0, localport = 0;

if (args.Length() >= 1 && args[0]->IsString()) remotehost = NanFromV8String(args[0]);
if (args.Length() >= 2 && args[1]->IsNumber()) remoteport = args[1]->Int32Value();
if (args.Length() >= 3 && args[2]->IsString()) sourcehost = NanFromV8String(args[2]);
if (args.Length() >= 4 && args[3]->IsNumber()) localport = args[3]->Int32Value();

Session *s = ObjectWrap::Unwrap<Session>(args.This());

ssh_message message = ssh_message_get(s->session);

if (NSSH_DEBUG)
std::cout << "message loop " << (!message) << " status=" << ssh_get_status(s->session) << std::endl;

ssh_channel chan = s->OpenReverseForward(remotehost, remoteport, sourcehost, localport);
if (!chan) {
NanReturnNull();
}

v8::Handle<v8::Object> channel = Channel::NewInstance(
s->session
, chan
, ChannelClosedCallback
, s
);

s->channels.push_back(node::ObjectWrap::Unwrap<Channel>(channel));
if (NSSH_DEBUG)
std::cout << "OpenReverseForward channel" << node::ObjectWrap::Unwrap<Channel>(channel)->myid << std::endl;
s->OnNewChannel(channel);

NanReturnValue(channel);
}

} // namespace nssh
11 changes: 10 additions & 1 deletion src/session.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,22 @@ class Session : public node::ObjectWrap {
void Start ();
void Close ();
void SetAuthMethods (int methods);
ssh_channel OpenReverseForward (const char *remotehost, int remoteport, const char *sourcehost, int localport);

void OnMessage (v8::Handle<v8::Object> message);
void OnNewChannel (v8::Handle<v8::Object> channel);
void OnError (std::string error);
void OnGlobalRequest (v8::Handle<v8::Object> message);
void OnClose ();

private:
static void SocketPollCallback (uv_poll_t* handle, int status, int events);
static void ChannelClosedCallback (Channel *channel, void *user);
static int SessionMessageCallback (ssh_session session, ssh_message message, void *data);
static int MessageCallback (ssh_session session, ssh_message message, void *data);
static int AuthCallback (const char *prompt, char *buf, size_t len, int echo, int verify, void *userdata);
static void LogCallback (ssh_session session, int priority, const char *message, void *userdata);
static void GlobalRequestCallback (ssh_session session, ssh_message message, void *userData);
static void StatusCallback (void *userdata, float status);

ssh_session session;
uv_poll_t *poll_handle;
Expand All @@ -49,6 +57,7 @@ class Session : public node::ObjectWrap {
static NAN_METHOD(New);
static NAN_METHOD(Close);
static NAN_METHOD(SetAuthMethods);
static NAN_METHOD(OpenReverseForward);
};

} // namespace nssh
Expand Down