Handle global requests and reverse forwarding
Этот коммит содержится в:
родитель
c4356531f7
Коммит
26d40b5354
@ -193,6 +193,12 @@ enum ssh_channel_requests_e {
|
||||
SSH_CHANNEL_REQUEST_WINDOW_CHANGE
|
||||
};
|
||||
|
||||
enum ssh_global_requests_e {
|
||||
SSH_GLOBAL_REQUEST_UNKNOWN=0,
|
||||
SSH_GLOBAL_REQUEST_TCPIP_FORWARD,
|
||||
SSH_GLOBAL_REQUEST_CANCEL_TCPIP_FORWARD,
|
||||
};
|
||||
|
||||
enum ssh_publickey_state_e {
|
||||
SSH_PUBLICKEY_STATE_ERROR=-1,
|
||||
SSH_PUBLICKEY_STATE_NONE=0,
|
||||
|
@ -47,6 +47,13 @@ struct ssh_service_request {
|
||||
char *service;
|
||||
};
|
||||
|
||||
struct ssh_global_request {
|
||||
int type;
|
||||
uint8_t want_reply;
|
||||
char *bind_address;
|
||||
uint16_t bind_port;
|
||||
};
|
||||
|
||||
struct ssh_channel_request {
|
||||
int type;
|
||||
ssh_channel channel;
|
||||
@ -75,11 +82,13 @@ struct ssh_message_struct {
|
||||
struct ssh_channel_request_open channel_request_open;
|
||||
struct ssh_channel_request channel_request;
|
||||
struct ssh_service_request service_request;
|
||||
struct ssh_global_request global_request;
|
||||
};
|
||||
|
||||
SSH_PACKET_CALLBACK(ssh_packet_channel_open);
|
||||
SSH_PACKET_CALLBACK(ssh_packet_service_request);
|
||||
SSH_PACKET_CALLBACK(ssh_packet_userauth_request);
|
||||
SSH_PACKET_CALLBACK(ssh_packet_global_request);
|
||||
|
||||
int ssh_message_handle_channel_request(ssh_session session, ssh_channel channel, ssh_buffer packet,
|
||||
const char *request, uint8_t want_reply);
|
||||
|
@ -158,6 +158,9 @@ LIBSSH_API int ssh_message_auth_set_methods(ssh_message msg, int methods);
|
||||
LIBSSH_API int ssh_message_service_reply_success(ssh_message msg);
|
||||
LIBSSH_API char *ssh_message_service_service(ssh_message msg);
|
||||
|
||||
LIBSSH_API int ssh_message_global_request_reply_success(ssh_message msg,
|
||||
uint16_t bound_port);
|
||||
|
||||
LIBSSH_API void ssh_set_message_callback(ssh_session session,
|
||||
int(*ssh_bind_message_callback)(ssh_session session, ssh_message msg, void *data),
|
||||
void *data);
|
||||
@ -183,6 +186,12 @@ LIBSSH_API char *ssh_message_channel_request_command(ssh_message msg);
|
||||
|
||||
LIBSSH_API char *ssh_message_channel_request_subsystem(ssh_message msg);
|
||||
|
||||
LIBSSH_API char *ssh_message_global_request_address(ssh_message msg);
|
||||
LIBSSH_API int ssh_message_global_request_port(ssh_message msg);
|
||||
|
||||
LIBSSH_API int ssh_channel_open_reverse_forward(ssh_channel channel, const char *remotehost,
|
||||
int remoteport, const char *sourcehost, int localport);
|
||||
|
||||
/* deprecated functions */
|
||||
SSH_DEPRECATED LIBSSH_API int ssh_accept(ssh_session session);
|
||||
|
||||
|
@ -41,6 +41,9 @@
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/misc.h"
|
||||
#include "libssh/messages.h"
|
||||
#if WITH_SERVER
|
||||
#include "libssh/server.h"
|
||||
#endif
|
||||
|
||||
#define WINDOWBASE 128000
|
||||
#define WINDOWLIMIT (WINDOWBASE/2)
|
||||
@ -2503,6 +2506,74 @@ int ssh_channel_select(ssh_channel *readchans, ssh_channel *writechans,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
#if WITH_SERVER
|
||||
/**
|
||||
* @brief Open a TCP/IP reverse forwarding channel.
|
||||
*
|
||||
* @param[in] channel An allocated channel.
|
||||
*
|
||||
* @param[in] remotehost The remote host to connected (host name or IP).
|
||||
*
|
||||
* @param[in] remoteport The remote port.
|
||||
*
|
||||
* @param[in] sourcehost The source host (your local computer). It's optional
|
||||
* and for logging purpose.
|
||||
*
|
||||
* @param[in] localport The source port (your local computer). It's optional
|
||||
* and for logging purpose.
|
||||
*
|
||||
* @return SSH_OK on success, SSH_ERROR if an error occured.
|
||||
*
|
||||
* @warning This function does not bind the local port and does not automatically
|
||||
* forward the content of a socket to the channel. You still have to
|
||||
* use channel_read and channel_write for this.
|
||||
*/
|
||||
int ssh_channel_open_reverse_forward(ssh_channel channel, const char *remotehost,
|
||||
int remoteport, const char *sourcehost, int localport) {
|
||||
ssh_session session = channel->session;
|
||||
ssh_buffer payload = NULL;
|
||||
ssh_string str = NULL;
|
||||
int rc = SSH_ERROR;
|
||||
|
||||
enter_function();
|
||||
|
||||
payload = ssh_buffer_new();
|
||||
if (payload == NULL) {
|
||||
goto error;
|
||||
}
|
||||
str = ssh_string_from_char(remotehost);
|
||||
if (str == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (buffer_add_ssh_string(payload, str) < 0 ||
|
||||
buffer_add_u32(payload,htonl(remoteport)) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
ssh_string_free(str);
|
||||
str = ssh_string_from_char(sourcehost);
|
||||
if (str == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (buffer_add_ssh_string(payload, str) < 0 ||
|
||||
buffer_add_u32(payload,htonl(localport)) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = channel_open(channel, "forwarded-tcpip", 64000, 32000, payload);
|
||||
|
||||
error:
|
||||
ssh_buffer_free(payload);
|
||||
ssh_string_free(str);
|
||||
|
||||
leave_function();
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* @} */
|
||||
|
||||
/* vim: set ts=4 sw=4 et cindent: */
|
||||
|
@ -39,6 +39,9 @@
|
||||
#include "libssh/keys.h"
|
||||
#include "libssh/dh.h"
|
||||
#include "libssh/messages.h"
|
||||
#if WITH_SERVER
|
||||
#include "libssh/server.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @defgroup libssh_messages The SSH message functions
|
||||
@ -64,6 +67,85 @@ static ssh_message ssh_message_new(ssh_session session){
|
||||
return msg;
|
||||
}
|
||||
|
||||
SSH_PACKET_CALLBACK(ssh_packet_global_request){
|
||||
ssh_message msg = NULL;
|
||||
ssh_string request_s=NULL;
|
||||
char *request=NULL;
|
||||
ssh_string bind_addr_s=NULL;
|
||||
char *bind_addr=NULL;
|
||||
uint32_t bind_port;
|
||||
uint8_t want_reply;
|
||||
(void)user;
|
||||
(void)type;
|
||||
(void)packet;
|
||||
|
||||
request_s = buffer_get_ssh_string(packet);
|
||||
if (request_s != NULL) {
|
||||
request = ssh_string_to_char(request_s);
|
||||
ssh_string_free(request_s);
|
||||
}
|
||||
|
||||
buffer_get_u8(packet, &want_reply);
|
||||
|
||||
ssh_log(session,SSH_LOG_PROTOCOL,"Received SSH_MSG_GLOBAL_REQUEST packet");
|
||||
|
||||
msg = ssh_message_new(session);
|
||||
msg->type = SSH_REQUEST_GLOBAL;
|
||||
|
||||
if(!strcmp(request, "tcpip-forward")) {
|
||||
bind_addr_s = buffer_get_ssh_string(packet);
|
||||
if (bind_addr_s != NULL) {
|
||||
bind_addr = ssh_string_to_char(bind_addr_s);
|
||||
ssh_string_free(bind_addr_s);
|
||||
}
|
||||
|
||||
buffer_get_u32(packet, &bind_port);
|
||||
bind_port = ntohl(bind_port);
|
||||
|
||||
msg->global_request.type = SSH_GLOBAL_REQUEST_TCPIP_FORWARD;
|
||||
msg->global_request.want_reply = want_reply;
|
||||
msg->global_request.bind_address = bind_addr;
|
||||
msg->global_request.bind_port = bind_port;
|
||||
|
||||
ssh_log(session, SSH_LOG_PROTOCOL, "Received SSH_MSG_GLOBAL_REQUEST %s %d %s:%d", request, want_reply, bind_addr, bind_port);
|
||||
|
||||
if(ssh_callbacks_exists(session->callbacks, global_request_function)) {
|
||||
ssh_log(session, SSH_LOG_PROTOCOL, "Calling callback for SSH_MSG_GLOBAL_REQUEST %s %d %s:%d", request, want_reply, bind_addr, bind_port);
|
||||
session->callbacks->global_request_function(session, msg, session->callbacks->userdata);
|
||||
} else {
|
||||
ssh_message_reply_default(msg);
|
||||
}
|
||||
} else if(!strcmp(request, "cancel-tcpip-forward")) {
|
||||
bind_addr_s = buffer_get_ssh_string(packet);
|
||||
if (bind_addr_s != NULL) {
|
||||
bind_addr = ssh_string_to_char(bind_addr_s);
|
||||
ssh_string_free(bind_addr_s);
|
||||
}
|
||||
buffer_get_u32(packet, &bind_port);
|
||||
bind_port = ntohl(bind_port);
|
||||
|
||||
msg->global_request.type = SSH_GLOBAL_REQUEST_CANCEL_TCPIP_FORWARD;
|
||||
msg->global_request.want_reply = want_reply;
|
||||
msg->global_request.bind_address = bind_addr;
|
||||
msg->global_request.bind_port = bind_port;
|
||||
|
||||
ssh_log(session, SSH_LOG_PROTOCOL, "Received SSH_MSG_GLOBAL_REQUEST %s %d %s:%d", request, want_reply, bind_addr, bind_port);
|
||||
|
||||
if(ssh_callbacks_exists(session->callbacks, global_request_function)) {
|
||||
session->callbacks->global_request_function(session, msg, session->callbacks->userdata);
|
||||
} else {
|
||||
ssh_message_reply_default(msg);
|
||||
}
|
||||
} else {
|
||||
ssh_log(session, SSH_LOG_PROTOCOL, "UNKNOWN SSH_MSG_GLOBAL_REQUEST %s %d", request, want_reply);
|
||||
}
|
||||
|
||||
SAFE_FREE(msg);
|
||||
SAFE_FREE(request);
|
||||
SAFE_FREE(bind_addr);
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
|
||||
SSH_PACKET_CALLBACK(ssh_packet_service_request){
|
||||
ssh_string service = NULL;
|
||||
char *service_c = NULL;
|
||||
@ -763,6 +845,8 @@ int ssh_message_subtype(ssh_message msg) {
|
||||
return msg->channel_request_open.type;
|
||||
case SSH_REQUEST_CHANNEL:
|
||||
return msg->channel_request.type;
|
||||
case SSH_REQUEST_GLOBAL:
|
||||
return msg->global_request.type;
|
||||
}
|
||||
|
||||
return -1;
|
||||
@ -798,6 +882,9 @@ void ssh_message_free(ssh_message msg){
|
||||
case SSH_REQUEST_SERVICE:
|
||||
SAFE_FREE(msg->service_request.service);
|
||||
break;
|
||||
case SSH_REQUEST_GLOBAL:
|
||||
SAFE_FREE(msg->global_request.bind_address);
|
||||
break;
|
||||
}
|
||||
ZERO_STRUCTP(msg);
|
||||
SAFE_FREE(msg);
|
||||
|
@ -85,7 +85,7 @@ ssh_packet_callback default_packet_handlers[]= {
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL, // 62-79
|
||||
NULL, // SSH2_MSG_GLOBAL_REQUEST 80
|
||||
ssh_packet_global_request, // SSH2_MSG_GLOBAL_REQUEST 80
|
||||
ssh_request_success, // SSH2_MSG_REQUEST_SUCCESS 81
|
||||
ssh_request_denied, // SSH2_MSG_REQUEST_FAILURE 82
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL,// 83-89
|
||||
|
58
src/server.c
58
src/server.c
@ -890,6 +890,54 @@ int ssh_message_service_reply_success(ssh_message msg) {
|
||||
return packet_send(msg->session);
|
||||
}
|
||||
|
||||
int ssh_message_global_request_reply_success(ssh_message msg, uint16_t bound_port) {
|
||||
ssh_log(msg->session, SSH_LOG_FUNCTIONS, "Accepting a global request");
|
||||
|
||||
if (msg->global_request.want_reply) {
|
||||
if (buffer_add_u8(msg->session->out_buffer
|
||||
, SSH2_MSG_REQUEST_SUCCESS) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if(msg->global_request.type == SSH_GLOBAL_REQUEST_TCPIP_FORWARD
|
||||
&& msg->global_request.bind_port == 0) {
|
||||
if (buffer_add_u32(msg->session->out_buffer, htonl(bound_port)) < 0) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
return packet_send(msg->session);
|
||||
}
|
||||
|
||||
if(msg->global_request.type == SSH_GLOBAL_REQUEST_TCPIP_FORWARD
|
||||
&& msg->global_request.bind_port == 0) {
|
||||
ssh_log(msg->session, SSH_LOG_PACKET,
|
||||
"The client doesn't want to know the remote port!");
|
||||
}
|
||||
|
||||
return SSH_OK;
|
||||
error:
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
static int ssh_message_global_request_reply_default(ssh_message msg) {
|
||||
ssh_log(msg->session, SSH_LOG_FUNCTIONS, "Refusing a global request");
|
||||
|
||||
if (msg->global_request.want_reply) {
|
||||
if (buffer_add_u8(msg->session->out_buffer
|
||||
, SSH2_MSG_REQUEST_FAILURE) < 0) {
|
||||
goto error;
|
||||
}
|
||||
return packet_send(msg->session);
|
||||
}
|
||||
ssh_log(msg->session, SSH_LOG_PACKET,
|
||||
"The client doesn't want to know the request failed!");
|
||||
|
||||
return SSH_OK;
|
||||
error:
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
int ssh_message_reply_default(ssh_message msg) {
|
||||
if (msg == NULL) {
|
||||
return -1;
|
||||
@ -904,6 +952,8 @@ int ssh_message_reply_default(ssh_message msg) {
|
||||
return ssh_message_channel_request_reply_default(msg);
|
||||
case SSH_REQUEST_SERVICE:
|
||||
return ssh_message_service_request_reply_default(msg);
|
||||
case SSH_REQUEST_GLOBAL:
|
||||
return ssh_message_global_request_reply_default(msg);
|
||||
default:
|
||||
ssh_log(msg->session, SSH_LOG_PACKET,
|
||||
"Don't know what to default reply to %d type",
|
||||
@ -1063,6 +1113,14 @@ char *ssh_message_channel_request_subsystem(ssh_message msg){
|
||||
return msg->channel_request.subsystem;
|
||||
}
|
||||
|
||||
char *ssh_message_global_request_address(ssh_message msg){
|
||||
return msg->global_request.bind_address;
|
||||
}
|
||||
|
||||
int ssh_message_global_request_port(ssh_message msg){
|
||||
return msg->global_request.bind_port;
|
||||
}
|
||||
|
||||
/** @brief defines the SSH_MESSAGE callback
|
||||
* @param session the current ssh session
|
||||
* @param[in] ssh_message_callback_ a function pointer to a callback taking the
|
||||
|
Загрузка…
x
Ссылка в новой задаче
Block a user