Fix bidirectional tunnel for wssshc client

- Modified handle_tunnel_request() to connect to local SSH server (localhost:22)
- Added forward_ws_to_local() function for WebSocket to local SSH forwarding
- Updated handle_tunnel_data() to properly route data to correct socket
- wssshc now establishes bidirectional forwarding between WebSocket and local SSH server
- Fixed tunnel blocking issue by implementing proper data flow in both directions
- Added thread for handling data from local SSH server back to WebSocket
parent 28431321
......@@ -98,7 +98,9 @@ int frame_buffer_consume(frame_buffer_t *fb, size_t len) {
void handle_tunnel_request(SSL *ssl, const char *request_id, int debug) {
pthread_mutex_lock(&tunnel_mutex);
if (active_tunnel) {
if (active_tunnel->sock >= 0) {
close(active_tunnel->sock);
}
free(active_tunnel);
}
active_tunnel = malloc(sizeof(tunnel_t));
......@@ -108,12 +110,40 @@ void handle_tunnel_request(SSL *ssl, const char *request_id, int debug) {
return;
}
active_tunnel->sock = -1; // Not connected yet
// Connect to local SSH/SCP server (localhost:22)
struct sockaddr_in local_addr;
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("Local socket creation failed");
free(active_tunnel);
active_tunnel = NULL;
pthread_mutex_unlock(&tunnel_mutex);
return;
}
memset(&local_addr, 0, sizeof(local_addr));
local_addr.sin_family = AF_INET;
local_addr.sin_port = htons(22); // Default SSH port
local_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
if (connect(sock, (struct sockaddr *)&local_addr, sizeof(local_addr)) < 0) {
perror("Connection to local SSH server failed");
close(sock);
free(active_tunnel);
active_tunnel = NULL;
pthread_mutex_unlock(&tunnel_mutex);
return;
}
active_tunnel->sock = sock;
strcpy(active_tunnel->request_id, request_id);
active_tunnel->active = 1;
active_tunnel->ssl = ssl;
active_tunnel->outgoing_buffer = NULL; // wssshc doesn't use buffer
pthread_mutex_unlock(&tunnel_mutex);
if (debug) {
printf("[DEBUG] Tunnel %s prepared (not connected yet)\n", request_id);
printf("[DEBUG] Tunnel %s connected to local SSH server\n", request_id);
}
// Send tunnel_ack back to server
......@@ -124,21 +154,20 @@ void handle_tunnel_request(SSL *ssl, const char *request_id, int debug) {
printf("[DEBUG] Sending tunnel_ack: %s\n", ack_msg);
}
char frame[512];
frame[0] = 0x81; // FIN + text opcode
int msg_len = strlen(ack_msg);
frame[1] = 0x80 | msg_len; // MASK + length
char mask_key[4];
for (int i = 0; i < 4; i++) {
mask_key[i] = rand() % 256;
frame[2 + i] = mask_key[i];
}
for (int i = 0; i < msg_len; i++) {
frame[6 + i] = ack_msg[i] ^ mask_key[i % 4];
}
int frame_len = 6 + msg_len;
if (SSL_write(ssl, frame, frame_len) <= 0) {
if (!send_websocket_frame(ssl, ack_msg)) {
fprintf(stderr, "Send tunnel_ack failed\n");
return;
}
// Start bidirectional forwarding thread
thread_args_t *thread_args = malloc(sizeof(thread_args_t));
if (thread_args) {
thread_args->ssl = ssl;
thread_args->debug = debug;
pthread_t thread;
pthread_create(&thread, NULL, forward_ws_to_local, thread_args);
pthread_detach(thread);
}
}
......@@ -275,12 +304,109 @@ void *forward_tcp_to_ws(void *arg) {
return NULL;
}
void *forward_ws_to_local(void *arg) {
thread_args_t *args = (thread_args_t *)arg;
SSL *ssl = args->ssl;
int debug = args->debug;
char buffer[BUFFER_SIZE];
int bytes_read;
fd_set readfds;
struct timeval tv;
while (1) {
pthread_mutex_lock(&tunnel_mutex);
if (!active_tunnel || !active_tunnel->active) {
pthread_mutex_unlock(&tunnel_mutex);
break;
}
int sock = active_tunnel->sock; // Use sock for wssshc (local SSH server connection)
char request_id[37];
strcpy(request_id, active_tunnel->request_id);
pthread_mutex_unlock(&tunnel_mutex);
// Use select to wait for data on local socket (from SSH server)
FD_ZERO(&readfds);
FD_SET(sock, &readfds);
tv.tv_sec = 0; // 0 seconds
tv.tv_usec = 50000; // 50ms timeout
int retval = select(sock + 1, &readfds, NULL, NULL, &tv);
if (retval == -1) {
if (debug) {
perror("[DEBUG] select on local socket failed");
fflush(stdout);
}
break;
} else if (retval == 0) {
// Timeout, continue loop
continue;
}
if (FD_ISSET(sock, &readfds)) {
bytes_read = recv(sock, buffer, sizeof(buffer), 0);
if (bytes_read <= 0) {
if (debug) {
printf("[DEBUG] Local SSH connection closed or error\n");
fflush(stdout);
}
break;
}
if (debug) {
printf("[DEBUG] Forwarding %d bytes from local SSH to WebSocket\n", bytes_read);
fflush(stdout);
}
// Convert to hex
char hex_data[bytes_read * 2 + 1];
for (int i = 0; i < bytes_read; i++) {
sprintf(hex_data + i * 2, "%02x", (unsigned char)buffer[i]);
}
hex_data[bytes_read * 2] = '\0';
// Send as tunnel_response (from target back to initiator)
char message[BUFFER_SIZE];
snprintf(message, sizeof(message),
"{\"type\":\"tunnel_response\",\"request_id\":\"%s\",\"data\":\"%s\"}",
request_id, hex_data);
if (!send_websocket_frame(ssl, message)) {
if (debug) {
printf("[DEBUG] Failed to send WebSocket frame\n");
fflush(stdout);
}
break;
}
}
}
if (debug) {
printf("[DEBUG] WebSocket to local forwarding thread exiting\n");
fflush(stdout);
}
free(args);
return NULL;
}
void handle_tunnel_data(SSL *ssl __attribute__((unused)), const char *request_id, const char *data_hex, int debug __attribute__((unused))) {
pthread_mutex_lock(&tunnel_mutex);
if (!active_tunnel || strcmp(active_tunnel->request_id, request_id) != 0) {
pthread_mutex_unlock(&tunnel_mutex);
return;
}
int target_sock;
if (active_tunnel->outgoing_buffer) {
// wsscp: Use local_sock
target_sock = active_tunnel->local_sock;
} else if (active_tunnel->sock >= 0) {
// wssshc: Use sock (local SSH server connection)
target_sock = active_tunnel->sock;
} else {
// wsssh: Use local_sock
target_sock = active_tunnel->local_sock;
}
pthread_mutex_unlock(&tunnel_mutex);
// Decode hex data
......@@ -303,8 +429,8 @@ void handle_tunnel_data(SSL *ssl __attribute__((unused)), const char *request_id
}
pthread_mutex_unlock(&tunnel_mutex);
} else {
// wsssh: Send directly to local socket
send(active_tunnel->local_sock, data, data_len, 0);
// wsssh/wssshc: Send directly to target socket
send(target_sock, data, data_len, 0);
}
free(data);
}
......
......@@ -52,6 +52,7 @@ int frame_buffer_append(frame_buffer_t *fb, const char *data, size_t len);
int frame_buffer_consume(frame_buffer_t *fb, size_t len);
void *forward_tcp_to_ws(void *arg);
void *forward_ws_to_local(void *arg);
void *tunnel_thread(void *arg);
void handle_tunnel_request(SSL *ssl, const char *request_id, int debug);
void handle_tunnel_data(SSL *ssl, const char *request_id, const char *data_hex, int debug);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment