-
-
Save bilby91/22d5cc5db0e6118f06d6d35051c32cc6 to your computer and use it in GitHub Desktop.
SSH Reverse Tunnel
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <libssh/callbacks.h> | |
#include <libssh/libssh.h> | |
#include <libssh/server.h> | |
#include <errno.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
/** | |
* @brief The default ssh user | |
* | |
*/ | |
#define SSHD_USER "libssh" | |
/** | |
* @brief The default ssh password | |
* | |
*/ | |
#define SSHD_PASSWORD "password" | |
/** | |
* @brief sshd address | |
* | |
*/ | |
static char *sshd_address = "0.0.0.0"; | |
/** | |
* @brief sshd port | |
* | |
*/ | |
static char *sshd_port = "2000"; | |
/** | |
* @brief Remote forward address | |
* | |
*/ | |
static char *remote_address = "0.0.0.0"; | |
/** | |
* @brief Remote forward port | |
* | |
*/ | |
static int remote_port = 2000; | |
/** | |
* @brief libssh log level. 3 is the most verbose one | |
* | |
*/ | |
static char *log_verbosity = "3"; | |
/** | |
* @brief Hardcoded web server response | |
* | |
*/ | |
static char *http_response = | |
"" | |
"HTTP/1.1 200 OK\n" | |
"Content-Type: text/html\n" | |
"Content-Length: 113\n" | |
"\n" | |
"<html>\n" | |
" <head>\n" | |
" <title>Hello, World!</title>\n" | |
" </head>\n" | |
" <body>\n" | |
" <h1>Hello, World!</h1>\n" | |
" </body>\n" | |
"</html>\n"; | |
/** | |
* @brief Configure the ssh_session | |
* | |
* @param session | |
*/ | |
static void configure_session(ssh_session session) { | |
ssh_options_set(session, SSH_OPTIONS_HOST, sshd_address); | |
ssh_options_set(session, SSH_OPTIONS_PORT_STR, sshd_port); | |
ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &log_verbosity); | |
} | |
/** | |
* @brief Connect to the sshd using default configurations | |
* | |
* @return ssh_session | |
*/ | |
static ssh_session connect_ssh_server() { | |
ssh_session session = ssh_new(); | |
configure_session(session); | |
if (session == NULL) { | |
return NULL; | |
} | |
if (ssh_connect(session)) { | |
fprintf(stderr, "Connection failed: %s\n", ssh_get_error(session)); | |
ssh_disconnect(session); | |
return NULL; | |
} | |
return session; | |
} | |
/** | |
* @brief Authenticate user with default user and password | |
* | |
* @param session | |
* @return int | |
*/ | |
static int authenticate(ssh_session session) { | |
switch (ssh_userauth_password(session, SSHD_USER, SSHD_PASSWORD)) { | |
case SSH_AUTH_SUCCESS: | |
return 0; | |
case SSH_AUTH_DENIED: | |
fprintf(stderr, "Authentication failed\n"); | |
return 1; | |
default: | |
return 1; | |
} | |
} | |
/** | |
* @brief Make global request for forwarding and wait for channel. | |
* | |
* @param session | |
* @return ssh_channel | |
*/ | |
static ssh_channel open_reverse_channel(ssh_session session) { | |
int port; | |
if (ssh_channel_listen_forward(session, remote_address, remote_port, NULL)) { | |
return NULL; | |
} | |
ssh_channel channel = ssh_channel_accept_forward(session, 100000, &port); | |
return channel; | |
} | |
/** | |
* @brief Forward channel to upstream and respond to channel back. | |
* | |
* @param session | |
* @param channel | |
* @return int | |
*/ | |
int forward_channel(ssh_session session, ssh_channel channel) { | |
char buffer[256]; | |
int r_bytes, w_bytes, sz_response; | |
while (1) { | |
r_bytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0); | |
if (r_bytes < 0) { | |
return SSH_ERROR; | |
} | |
if (strncmp(buffer, "GET /", 5)) | |
continue; | |
sz_response = strlen(http_response); | |
w_bytes = ssh_channel_write(channel, http_response, sz_response); | |
if (w_bytes != sz_response) { | |
return SSH_ERROR; | |
} | |
return 0; | |
} | |
} | |
int main(void) { | |
ssh_session session; | |
ssh_channel channel; | |
session = connect_ssh_server(); | |
if (session == NULL) { | |
return 1; | |
} | |
if (authenticate(session)) { | |
return 1; | |
} | |
channel = open_reverse_channel(session); | |
if (channel == NULL) { | |
fprintf(stderr, "Error opening reverse forward channel: %s\n", ssh_get_error(session)); | |
ssh_channel_close(channel); | |
ssh_disconnect(session); | |
return 1; | |
} | |
if(forward_channel(session, channel)) { | |
fprintf(stderr, "Error during channel forwarding: %s\n", ssh_get_error(session)); | |
ssh_channel_close(channel); | |
ssh_disconnect(session); | |
} | |
ssh_channel_send_eof(channel); | |
ssh_channel_close(channel); | |
ssh_disconnect(session); | |
ssh_channel_free(channel); | |
ssh_free(session); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <libssh/callbacks.h> | |
#include <libssh/libssh.h> | |
#include <libssh/server.h> | |
#include <errno.h> | |
#include <poll.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
/** | |
* @brief The default ssh user | |
* | |
*/ | |
#define SSHD_USER "libssh" | |
/** | |
* @brief The default ssh password | |
* | |
*/ | |
#define SSHD_PASSWORD "password" | |
/** | |
* @brief The default ssh key | |
* | |
*/ | |
#define RSA_KEY "/Users/bilby91/.ssh/id_rsa" | |
/** | |
* @brief Bind address for sshd | |
* | |
*/ | |
static char *listen_address = "0.0.0.0"; | |
/** | |
* @brief Bind port for sshd | |
* | |
*/ | |
static char *listen_port = "2000"; | |
/** | |
* @brief libssh log level. 3 is the most verbose one | |
* | |
*/ | |
static char *log_verbosity = "3"; | |
/** | |
* @brief Authenticate the user using hardcoded user/pass | |
* | |
* @param user | |
* @param password | |
* @return 0 if verified | |
* @return 1 if not verified | |
*/ | |
static int verify_password(const char *user, const char *password) { | |
if (strcmp(user, SSHD_USER)) | |
return 1; | |
if (strcmp(password, SSHD_PASSWORD)) | |
return 1; | |
return 0; | |
} | |
/** | |
* @brief Authentication callback | |
* | |
* @param session | |
* @param user | |
* @param password | |
* @param userdata | |
* @return int | |
*/ | |
static int handle_authentication_request(ssh_session session, const char *user, const char *password, void *userdata) { | |
if (verify_password(user, password)) { | |
return SSH_AUTH_DENIED; | |
} | |
return SSH_AUTH_SUCCESS; | |
} | |
static int pty_request(ssh_session session, ssh_channel channel, const char *term, int x, int y, int px, int py, | |
void *userdata) { | |
printf("Allocated terminal\n"); | |
return 0; | |
} | |
static int shell_request(ssh_session session, ssh_channel channel, void *userdata) { | |
printf("Allocated shell\n"); | |
return 0; | |
} | |
struct ssh_channel_callbacks_struct channel_callbacks = {.channel_pty_request_function = pty_request, | |
.channel_shell_request_function = shell_request}; | |
/** | |
* @brief Open channel request callback | |
* | |
* @param session | |
* @param userdata | |
* @return ssh_channel | |
*/ | |
static ssh_channel handle_open_channel_request(ssh_session session, void *userdata) { | |
printf("FOOO\n"); | |
ssh_channel channel = ssh_channel_new(session); | |
ssh_callbacks_init(&channel_callbacks); | |
ssh_set_channel_callbacks(channel, &channel_callbacks); | |
return channel; | |
} | |
/** | |
* @brief Service request callback | |
* | |
* @param session | |
* @param service | |
* @param userdata | |
* @return int | |
*/ | |
static int handle_service_request(ssh_session session, const char *service, void *userdata) { | |
printf("HERE\n"); | |
return 0; | |
} | |
/** | |
* @brief Global request callback | |
* | |
* @param session | |
* @param message | |
* @param userdata | |
*/ | |
static void handle_global_request(ssh_session session, ssh_message message, void *userdata) { | |
ssh_message_global_request_reply_success(message, 8080); | |
} | |
struct ssh_callbacks_struct callbacks = {.userdata = NULL, .global_request_function = handle_global_request}; | |
struct ssh_server_callbacks_struct server_cb = {.userdata = NULL, | |
.auth_password_function = handle_authentication_request, | |
.service_request_function = handle_service_request, | |
.channel_open_request_session_function = handle_open_channel_request}; | |
/** | |
* @brief Set default configurations to ssh_bind | |
* | |
* @param sshbind | |
*/ | |
static void configure_ssh_binding(ssh_bind sshbind) { | |
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY, RSA_KEY); | |
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, listen_port); | |
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDADDR, listen_address); | |
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY_STR, log_verbosity); | |
} | |
int main(int argc, char **argv) { | |
ssh_bind sshbind = ssh_bind_new(); | |
ssh_session session = ssh_new(); | |
configure_ssh_binding(sshbind); | |
if (ssh_bind_listen(sshbind) < 0) { | |
printf("Error listening to socket: %s\n", ssh_get_error(sshbind)); | |
return 1; | |
} | |
if (ssh_bind_accept(sshbind, session) < 0) { | |
printf("Error accepting a connection: %s\n", ssh_get_error(sshbind)); | |
return 1; | |
} | |
ssh_callbacks_init(&server_cb); | |
ssh_set_server_callbacks(session, &server_cb); | |
ssh_callbacks_init(&callbacks); | |
ssh_set_callbacks(session, &callbacks); | |
if (ssh_handle_key_exchange(session)) { | |
printf("ssh_handle_key_exchange: %s\n", ssh_get_error(session)); | |
return 1; | |
} | |
ssh_set_auth_methods(session, SSH_AUTH_METHOD_PASSWORD); | |
ssh_event next_event = ssh_event_new(); | |
ssh_event_add_session(next_event, session); | |
int status; | |
do { | |
status = ssh_event_dopoll(next_event, 1000); | |
} while (status == SSH_OK || status == SSH_AGAIN); | |
switch (status) { | |
case SSH_ERROR: | |
printf("Disconnecting with error:: %s\n", ssh_get_error(session)); | |
break; | |
} | |
ssh_disconnect(session); | |
ssh_free(session); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment