Version 1.6.5: Flexible data encoding support for wsssht

- Added --enc option to wsssht with hex/base64/bin encoding modes
- Updated tunnel request messages to include encoding specification
- Enhanced wssshc to parse and handle different encoding formats
- Added configuration file support for encoding option
- Updated documentation, man pages, and changelog
- Maintained backward compatibility with hex encoding as default
parent 13104c97
...@@ -5,6 +5,35 @@ All notable changes to this project will be documented in this file. ...@@ -5,6 +5,35 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.6.5] - 2025-09-19
### Added
- **Flexible Data Encoding Support**: New `--enc` option for wsssht with multiple encoding modes
- `--enc hex`: Hexadecimal encoding of binary data (default, backward compatible)
- `--enc base64`: Base64 encoding of binary data for better efficiency
- `--enc bin`: Direct binary data transmission without encoding
- Configuration file support with `enc = hex` option in `wsssht.conf`
- Automatic encoding negotiation between wsssht and wssshc clients
### Enhanced
- **Tunnel Data Handling**: Improved data channel message processing
- wssshc now parses `enc` attribute from tunnel requests
- Support for multiple encoding formats in tunnel data messages
- Backward compatibility maintained with existing hex encoding
- Enhanced error handling for unsupported encoding modes
### Technical Details
- **Encoding Architecture**: Extensible encoding system with weight-based selection
- Clean separation between encoding modes and data transmission
- Efficient binary data handling for high-performance applications
- JSON message format updates to include encoding specifications
- Server-side forwarding maintains data integrity across all encoding modes
### Security
- **Data Integrity**: All encoding modes preserve data integrity during transmission
- **Protocol Compliance**: Proper JSON message formatting for all encoding types
- **Backward Compatibility**: Existing installations continue to work without changes
## [1.6.2] - 2025-09-19 ## [1.6.2] - 2025-09-19
### Fixed ### Fixed
......
...@@ -658,6 +658,14 @@ python3 -m pytest tests/integration/ ...@@ -658,6 +658,14 @@ python3 -m pytest tests/integration/
## Recent Updates ## Recent Updates
### Version 1.6.5
- **Flexible Data Encoding Support**: New `--enc` option for wsssht with multiple encoding modes
- `--enc hex`: Hexadecimal encoding of binary data (default, backward compatible)
- `--enc base64`: Base64 encoding of binary data for better efficiency
- `--enc bin`: Direct binary data transmission without encoding
- Configuration file support with `enc = hex` option in `wsssht.conf`
- Automatic encoding negotiation between wsssht and wssshc clients
### Version 1.6.2 ### Version 1.6.2
- **Tunnel Close Forwarding**: Critical fix for tunnel closure synchronization between wssshc, server, and wsssht - **Tunnel Close Forwarding**: Critical fix for tunnel closure synchronization between wssshc, server, and wsssht
- **Web Terminal JavaScript Fixes**: Comprehensive fixes for web interface terminal functionality - **Web Terminal JavaScript Fixes**: Comprehensive fixes for web interface terminal functionality
......
# WSSSH: Warp-Powered Stefy's Spatial Secure Hyperdrive - Future Enhancements Roadmap # WSSSH: Warp-Powered Stefy's Spatial Secure Hyperdrive - Future Enhancements Roadmap
## Recently Completed (v1.6.5)
- [x] **Flexible Data Encoding Support**: New `--enc` option for wsssht with multiple encoding modes
- `--enc hex`: Hexadecimal encoding of binary data (default, backward compatible)
- `--enc base64`: Base64 encoding of binary data for better efficiency
- `--enc bin`: Direct binary data transmission without encoding
- Configuration file support with `enc = hex` option in `wsssht.conf`
- Automatic encoding negotiation between wsssht and wssshc clients
- Updated tunnel request messages to include encoding specification
- Enhanced data channel message processing for all encoding formats
- Maintained backward compatibility with existing hex encoding
## Recently Completed (v1.6.2)
- [x] **Tunnel Close Forwarding**: Critical fix for tunnel closure synchronization between wssshc, server, and wsssht
- [x] **Web Terminal JavaScript Fixes**: Comprehensive fixes for web interface terminal functionality
- [x] **Fullscreen Terminal Support**: Enhanced web terminal with fullscreen toggle functionality
- [x] **Logo Serving Path**: Fixed web interface logo loading from correct directory
## Recently Completed (v1.6.1) ## Recently Completed (v1.6.1)
- [x] **Major Code Refactoring**: Complete modularization of `wsssht.c` for improved maintainability - [x] **Major Code Refactoring**: Complete modularization of `wsssht.c` for improved maintainability
- Split monolithic 2769-line `wsssht.c` into modular components in `libwsssht/` directory - Split monolithic 2769-line `wsssht.c` into modular components in `libwsssht/` directory
......
This diff is collapsed.
...@@ -33,4 +33,7 @@ service = ssh ...@@ -33,4 +33,7 @@ service = ssh
tunnel-host = 127.0.0.1 tunnel-host = 127.0.0.1
# Connection retry interval in seconds (default: 5) # Connection retry interval in seconds (default: 5)
interval = 5 interval = 5
\ No newline at end of file
# Data encoding: hex, base64, or bin (default: hex)
enc = hex
\ No newline at end of file
wsssh-tools (1.6.1-1) unstable; urgency=medium wsssh-tools (1.6.5-1) unstable; urgency=medium
* Version 1.6.1: Major code refactoring and documentation updates * Version 1.6.5: Flexible data encoding support for wsssht
* Complete modularization of wsssht.c into libwsssht/ components * Added --enc option with hex/base64/bin encoding modes
* Enhanced tunnel data handling with multiple encoding formats
* Improved data channel message processing and negotiation
* Split monolithic 2769-line wsssht.c into modular structure: * Split monolithic 2769-line wsssht.c into modular structure:
- utils.h/c: Utility functions (print_usage, parse_connection_string, parse_args) - utils.h/c: Utility functions (print_usage, parse_connection_string, parse_args)
- modes.h/c: Operating mode implementations (bridge, script, daemon modes) - modes.h/c: Operating mode implementations (bridge, script, daemon modes)
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
#define BUFFER_SIZE 8192 #define BUFFER_SIZE 1048576
int send_json_message(SSL *ssl, const char *type, const char *client_id, const char *request_id) { int send_json_message(SSL *ssl, const char *type, const char *client_id, const char *request_id) {
char message[1024]; char message[1024];
...@@ -88,22 +88,43 @@ int send_registration_message(SSL *ssl, const char *client_id, const char *passw ...@@ -88,22 +88,43 @@ int send_registration_message(SSL *ssl, const char *client_id, const char *passw
} }
int send_tunnel_request_message(SSL *ssl, const char *client_id, const char *request_id, const char *tunnel, const char *tunnel_control, const char *service) { int send_tunnel_request_message(SSL *ssl, const char *client_id, const char *request_id, const char *tunnel, const char *tunnel_control, const char *service) {
return send_tunnel_request_message_with_enc(ssl, client_id, request_id, tunnel, tunnel_control, service, ENCODING_HEX);
}
int send_tunnel_request_message_with_enc(SSL *ssl, const char *client_id, const char *request_id, const char *tunnel, const char *tunnel_control, const char *service, wsssh_encoding_t encoding) {
const char *enc_str;
switch (encoding) {
case ENCODING_HEX:
enc_str = "hex";
break;
case ENCODING_BASE64:
enc_str = "base64";
break;
case ENCODING_BINARY:
enc_str = "bin";
break;
default:
enc_str = "hex";
break;
}
char message[1024]; char message[1024];
if (service) { if (service) {
snprintf(message, sizeof(message), snprintf(message, sizeof(message),
"{\"type\":\"tunnel_request\",\"client_id\":\"%s\",\"request_id\":\"%s\",\"tunnel\":\"%s\",\"tunnel_control\":\"%s\",\"service\":\"%s\",\"version\":\"%s\"}", "{\"type\":\"tunnel_request\",\"client_id\":\"%s\",\"request_id\":\"%s\",\"tunnel\":\"%s\",\"tunnel_control\":\"%s\",\"service\":\"%s\",\"enc\":\"%s\",\"version\":\"%s\"}",
client_id, request_id, tunnel, tunnel_control, service, WSSSH_VERSION); client_id, request_id, tunnel, tunnel_control, service, enc_str, WSSSH_VERSION);
} else { } else {
snprintf(message, sizeof(message), snprintf(message, sizeof(message),
"{\"type\":\"tunnel_request\",\"client_id\":\"%s\",\"request_id\":\"%s\",\"tunnel\":\"%s\",\"tunnel_control\":\"%s\",\"version\":\"%s\"}", "{\"type\":\"tunnel_request\",\"client_id\":\"%s\",\"request_id\":\"%s\",\"tunnel\":\"%s\",\"tunnel_control\":\"%s\",\"enc\":\"%s\",\"version\":\"%s\"}",
client_id, request_id, tunnel, tunnel_control, WSSSH_VERSION); client_id, request_id, tunnel, tunnel_control, enc_str, WSSSH_VERSION);
} }
// Send as WebSocket frame // Send as WebSocket frame
return send_websocket_frame(ssl, message); return send_websocket_frame(ssl, message);
} }
int send_tunnel_close_message(SSL *ssl, const char *request_id, int debug) { int send_tunnel_close_message(SSL *ssl, const char *request_id, int debug) {
char close_msg[256]; char close_msg[256];
snprintf(close_msg, sizeof(close_msg), "{\"type\":\"tunnel_close\",\"request_id\":\"%s\"}", request_id); snprintf(close_msg, sizeof(close_msg), "{\"type\":\"tunnel_close\",\"request_id\":\"%s\"}", request_id);
......
...@@ -21,12 +21,14 @@ ...@@ -21,12 +21,14 @@
#define CONTROL_MESSAGES_H #define CONTROL_MESSAGES_H
#include <openssl/ssl.h> #include <openssl/ssl.h>
#include "wssshlib.h"
#include "tunnel.h" #include "tunnel.h"
// Function declarations for control channel messages // Function declarations for control channel messages
int send_json_message(SSL *ssl, const char *type, const char *client_id, const char *request_id); int send_json_message(SSL *ssl, const char *type, const char *client_id, const char *request_id);
int send_registration_message(SSL *ssl, const char *client_id, const char *password, const char *tunnel, const char *tunnel_control, const char *wssshd_private_ip); int send_registration_message(SSL *ssl, const char *client_id, const char *password, const char *tunnel, const char *tunnel_control, const char *wssshd_private_ip);
int send_tunnel_request_message(SSL *ssl, const char *client_id, const char *request_id, const char *tunnel, const char *tunnel_control, const char *service); int send_tunnel_request_message(SSL *ssl, const char *client_id, const char *request_id, const char *tunnel, const char *tunnel_control, const char *service);
int send_tunnel_request_message_with_enc(SSL *ssl, const char *client_id, const char *request_id, const char *tunnel, const char *tunnel_control, const char *service, wsssh_encoding_t encoding);
int send_tunnel_close_message(SSL *ssl, const char *request_id, int debug); int send_tunnel_close_message(SSL *ssl, const char *request_id, int debug);
int send_tunnel_keepalive_message(SSL *ssl, tunnel_t *tunnel, int debug); int send_tunnel_keepalive_message(SSL *ssl, tunnel_t *tunnel, int debug);
int send_tunnel_keepalive_ack_message(SSL *ssl, const char *request_id, int debug); int send_tunnel_keepalive_ack_message(SSL *ssl, const char *request_id, int debug);
......
This diff is collapsed.
...@@ -22,8 +22,47 @@ ...@@ -22,8 +22,47 @@
#include <openssl/ssl.h> #include <openssl/ssl.h>
// Retransmission buffer entry
typedef struct {
uint32_t frame_id;
char *message;
size_t message_len;
time_t timestamp;
int retries;
} retransmission_entry_t;
// Retransmission buffer
#define RETRANSMISSION_BUFFER_SIZE 10
#define MAX_FRAME_SIZE 1048576 // 1MB max frame size
#define RETRANSMISSION_TIMEOUT 30 // 30 seconds timeout
#define MAX_RETRIES 3
typedef struct {
retransmission_entry_t entries[RETRANSMISSION_BUFFER_SIZE];
int count;
uint32_t next_frame_id;
pthread_mutex_t mutex;
} retransmission_buffer_t;
// Function declarations for data channel messages // Function declarations for data channel messages
int send_tunnel_data_message(SSL *ssl, const char *request_id, const char *data_hex, int debug); int send_tunnel_data_message(SSL *ssl, const char *request_id, const char *data_hex, int debug);
int send_tunnel_data_binary_message(SSL *ssl, const char *request_id, const unsigned char *data, size_t data_len, int debug);
int send_tunnel_data_reliable_message(SSL *ssl, const char *request_id, const unsigned char *data, size_t data_len, retransmission_buffer_t *buffer, int debug);
int send_tunnel_response_message(SSL *ssl, const char *request_id, const char *data_hex, int debug); int send_tunnel_response_message(SSL *ssl, const char *request_id, const char *data_hex, int debug);
int send_tunnel_ack_message(SSL *ssl, const char *request_id, uint32_t frame_id, int debug);
int send_tunnel_ko_message(SSL *ssl, const char *request_id, uint32_t frame_id, int debug);
// Retransmission buffer functions
retransmission_buffer_t *retransmission_buffer_init(void);
void retransmission_buffer_free(retransmission_buffer_t *buffer);
int retransmission_buffer_add(retransmission_buffer_t *buffer, uint32_t frame_id, const char *message, size_t message_len);
void retransmission_buffer_ack(retransmission_buffer_t *buffer, uint32_t frame_id);
void retransmission_buffer_ko(retransmission_buffer_t *buffer, uint32_t frame_id);
void retransmission_buffer_gc(retransmission_buffer_t *buffer);
uint32_t retransmission_buffer_get_next_frame_id(retransmission_buffer_t *buffer);
// Checksum functions
uint32_t crc32_checksum(const unsigned char *data, size_t len);
int send_tunnel_data_binary_message(SSL *ssl, const char *request_id, const unsigned char *data, size_t data_len, int debug);
#endif // DATA_MESSAGES_H #endif // DATA_MESSAGES_H
\ No newline at end of file
This diff is collapsed.
...@@ -46,7 +46,7 @@ void *run_tunnel_thread(void *arg) { ...@@ -46,7 +46,7 @@ void *run_tunnel_thread(void *arg) {
tunnel_thread_args_t *args = (tunnel_thread_args_t *)arg; tunnel_thread_args_t *args = (tunnel_thread_args_t *)arg;
// Establish the tunnel for this connection // Establish the tunnel for this connection
int tunnel_sock = setup_tunnel(args->wssshd_host, args->wssshd_port, args->client_id, 0, args->config->debug, 0, args->tunnel_host); int tunnel_sock = setup_tunnel(args->wssshd_host, args->wssshd_port, args->client_id, 0, args->config->debug, 0, args->tunnel_host, args->config->encoding);
if (tunnel_sock < 0) { if (tunnel_sock < 0) {
fprintf(stderr, "Failed to establish tunnel for connection\n"); fprintf(stderr, "Failed to establish tunnel for connection\n");
close(args->accepted_sock); close(args->accepted_sock);
......
This diff is collapsed.
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <openssl/ssl.h> #include <openssl/ssl.h>
#include <pthread.h> #include <pthread.h>
#include "data_messages.h"
// Frame buffer for wsscp // Frame buffer for wsscp
typedef struct { typedef struct {
...@@ -50,6 +51,10 @@ typedef struct { ...@@ -50,6 +51,10 @@ typedef struct {
unsigned long long total_bytes_received; // Total bytes received through tunnel unsigned long long total_bytes_received; // Total bytes received through tunnel
unsigned long long bytes_last_period; // Bytes transferred in last 30-second period unsigned long long bytes_last_period; // Bytes transferred in last 30-second period
time_t last_stats_reset; // When we last reset the period stats time_t last_stats_reset; // When we last reset the period stats
int bin; // Binary mode flag - if true, transmit data as binary instead of hex
// Reliable transmission
retransmission_buffer_t *retransmission_buffer; // Buffer for reliable message retransmission
} tunnel_t; } tunnel_t;
// Service configuration structure // Service configuration structure
...@@ -94,17 +99,21 @@ void *forward_ws_to_local(void *arg); ...@@ -94,17 +99,21 @@ void *forward_ws_to_local(void *arg);
void *forward_ws_to_ssh_server(void *arg); void *forward_ws_to_ssh_server(void *arg);
void *tunnel_thread(void *arg); void *tunnel_thread(void *arg);
void handle_tunnel_request(SSL *ssl, const char *request_id, int debug, const char *ssh_host, int ssh_port); void handle_tunnel_request(SSL *ssl, const char *request_id, int debug, const char *ssh_host, int ssh_port);
void handle_tunnel_request_with_enc(SSL *ssl, const char *request_id, int debug, const char *ssh_host, int ssh_port, wsssh_encoding_t encoding);
void handle_tunnel_request_with_service(SSL *ssl, const char *request_id, service_config_t *service, int debug); void handle_tunnel_request_with_service(SSL *ssl, const char *request_id, service_config_t *service, int debug);
void handle_tunnel_request_with_service_and_enc(SSL *ssl, const char *request_id, service_config_t *service, int debug, wsssh_encoding_t encoding);
void handle_tunnel_data(SSL *ssl, const char *request_id, const char *data_hex, int debug); void handle_tunnel_data(SSL *ssl, const char *request_id, const char *data_hex, int debug);
void handle_tunnel_close(SSL *ssl, const char *request_id, int debug); void handle_tunnel_close(SSL *ssl, const char *request_id, int debug);
void send_tunnel_close(SSL *ssl, const char *request_id, int debug); void send_tunnel_close(SSL *ssl, const char *request_id, int debug);
void handle_tunnel_keepalive(SSL *ssl, const char *request_id, unsigned long long total_bytes, double rate_bps, int debug); void handle_tunnel_keepalive(SSL *ssl, const char *request_id, unsigned long long total_bytes, double rate_bps, int debug);
void handle_tunnel_keepalive_ack(SSL *ssl, const char *request_id, int debug); void handle_tunnel_keepalive_ack(SSL *ssl, const char *request_id, int debug);
void handle_tunnel_ack(SSL *ssl, const char *request_id, uint32_t frame_id, int debug);
void handle_tunnel_ko(SSL *ssl, const char *request_id, uint32_t frame_id, int debug);
void send_tunnel_keepalive(SSL *ssl, tunnel_t *tunnel, int debug); void send_tunnel_keepalive(SSL *ssl, tunnel_t *tunnel, int debug);
void check_keepalive_timeouts(int debug); void check_keepalive_timeouts(int debug);
void cleanup_tunnel(int debug); void cleanup_tunnel(int debug);
int reconnect_websocket(tunnel_t *tunnel, const char *wssshd_host, int wssshd_port, const char *client_id, const char *request_id, int debug); int reconnect_websocket(tunnel_t *tunnel, const char *wssshd_host, int wssshd_port, const char *client_id, const char *request_id, int debug);
int setup_tunnel(const char *wssshd_host, int wssshd_port, const char *client_id, int local_port, int debug, int use_buffer, const char *tunnel_host); int setup_tunnel(const char *wssshd_host, int wssshd_port, const char *client_id, int local_port, int debug, int use_buffer, const char *tunnel_host, wsssh_encoding_t encoding);
// CPU affinity functions // CPU affinity functions
void init_cpu_affinity(void); void init_cpu_affinity(void);
......
...@@ -87,6 +87,7 @@ void print_usage(const char *program_name) { ...@@ -87,6 +87,7 @@ void print_usage(const char *program_name) {
fprintf(stderr, " --tunnel TRANSPORT Transport for data channel (comma-separated or 'any', or 'websocket' default: any)\n"); fprintf(stderr, " --tunnel TRANSPORT Transport for data channel (comma-separated or 'any', or 'websocket' default: any)\n");
fprintf(stderr, " --tunnel-control TYPES Transport types for control channel (comma-separated or 'any', default: any)\n"); fprintf(stderr, " --tunnel-control TYPES Transport types for control channel (comma-separated or 'any', default: any)\n");
fprintf(stderr, " --service SERVICE Service type (default: ssh)\n"); fprintf(stderr, " --service SERVICE Service type (default: ssh)\n");
fprintf(stderr, " --enc ENCODING Data encoding: hex, base64, or bin (default: hex)\n");
fprintf(stderr, " --mode MODE Operating mode: interactive, silent, bridge, script, pipe (default: interactive)\n"); fprintf(stderr, " --mode MODE Operating mode: interactive, silent, bridge, script, pipe (default: interactive)\n");
fprintf(stderr, " --silent Shortcut for --mode silent\n"); fprintf(stderr, " --silent Shortcut for --mode silent\n");
fprintf(stderr, " --bridge Shortcut for --mode bridge\n"); fprintf(stderr, " --bridge Shortcut for --mode bridge\n");
...@@ -148,6 +149,18 @@ int wsssht_parse_args(int argc, char *argv[], wsssh_config_t *config, int *remai ...@@ -148,6 +149,18 @@ int wsssht_parse_args(int argc, char *argv[], wsssh_config_t *config, int *remai
if (config->service) free(config->service); if (config->service) free(config->service);
config->service = strdup(argv[i + 1]); config->service = strdup(argv[i + 1]);
i++; // Skip the argument i++; // Skip the argument
} else if (strcmp(argv[i], "--enc") == 0 && i + 1 < argc) {
if (strcmp(argv[i + 1], "hex") == 0) {
config->encoding = ENCODING_HEX;
} else if (strcmp(argv[i + 1], "base64") == 0) {
config->encoding = ENCODING_BASE64;
} else if (strcmp(argv[i + 1], "bin") == 0) {
config->encoding = ENCODING_BINARY;
} else {
fprintf(stderr, "Error: Invalid encoding: %s (must be hex, base64, or bin)\n", argv[i + 1]);
return 0;
}
i++; // Skip the argument
} else if (strcmp(argv[i], "--debug") == 0) { } else if (strcmp(argv[i], "--debug") == 0) {
config->debug = 1; config->debug = 1;
} else if (strcmp(argv[i], "--mode") == 0 && i + 1 < argc) { } else if (strcmp(argv[i], "--mode") == 0 && i + 1 < argc) {
......
...@@ -39,8 +39,7 @@ int websocket_handshake(SSL *ssl, const char *host, int port, const char *path, ...@@ -39,8 +39,7 @@ int websocket_handshake(SSL *ssl, const char *host, int port, const char *path,
int bytes_read; int bytes_read;
if (debug) { if (debug) {
printf("[DEBUG] Starting WebSocket handshake to %s:%d\n", host, port); fprintf(stderr, "[DEBUG] Starting WebSocket handshake to %s:%d\n", host, port);
fflush(stdout);
} }
// Send WebSocket handshake // Send WebSocket handshake
...@@ -55,8 +54,7 @@ int websocket_handshake(SSL *ssl, const char *host, int port, const char *path, ...@@ -55,8 +54,7 @@ int websocket_handshake(SSL *ssl, const char *host, int port, const char *path,
path, host, port); path, host, port);
if (debug) { if (debug) {
printf("[DEBUG] Sending WebSocket handshake request...\n"); fprintf(stderr, "[DEBUG] Sending WebSocket handshake request...\n");
fflush(stdout);
} }
// Lock SSL mutex for write operation // Lock SSL mutex for write operation
...@@ -69,8 +67,7 @@ int websocket_handshake(SSL *ssl, const char *host, int port, const char *path, ...@@ -69,8 +67,7 @@ int websocket_handshake(SSL *ssl, const char *host, int port, const char *path,
} }
if (debug) { if (debug) {
printf("[DEBUG] WebSocket handshake request sent, waiting for response...\n"); fprintf(stderr, "[DEBUG] WebSocket handshake request sent, waiting for response...\n");
fflush(stdout);
} }
// Read response // Read response
...@@ -84,20 +81,18 @@ int websocket_handshake(SSL *ssl, const char *host, int port, const char *path, ...@@ -84,20 +81,18 @@ int websocket_handshake(SSL *ssl, const char *host, int port, const char *path,
response[bytes_read] = '\0'; response[bytes_read] = '\0';
if (debug) { if (debug) {
printf("[DEBUG] Received WebSocket handshake response (%d bytes)\n", bytes_read); fprintf(stderr, "[DEBUG] Received WebSocket handshake response (%d bytes)\n", bytes_read);
} }
// Check for successful handshake // Check for successful handshake
if (strstr(response, "101 Switching Protocols") == NULL) { if (strstr(response, "101 Switching Protocols") == NULL) {
fprintf(stderr, "WebSocket handshake failed - no 101 response\n"); fprintf(stderr, "WebSocket handshake failed - no 101 response\n");
printf("[DEBUG] Response: %.200s\n", response); fprintf(stderr, "[DEBUG] Response: %.200s\n", response);
fflush(stdout);
return 0; return 0;
} }
if (debug) { if (debug) {
printf("[DEBUG] WebSocket handshake successful\n"); fprintf(stderr, "[DEBUG] WebSocket handshake successful\n");
fflush(stdout);
} }
return 1; return 1;
} }
...@@ -212,6 +207,114 @@ int send_websocket_frame(SSL *ssl, const char *data) { ...@@ -212,6 +207,114 @@ int send_websocket_frame(SSL *ssl, const char *data) {
return 1; return 1;
} }
int send_websocket_binary_frame(SSL *ssl, const unsigned char *data, size_t data_len) {
// Lock SSL mutex to prevent concurrent SSL operations
pthread_mutex_lock(&ssl_mutex);
int header_len = 2;
if (data_len <= 125) {
header_len = 6; // 2 + 4 for mask
} else if (data_len <= 65535) {
header_len = 8; // 4 + 4 for mask
} else {
header_len = 14; // 10 + 4 for mask
}
int frame_len = header_len + data_len;
char *frame = malloc(frame_len);
if (!frame) {
pthread_mutex_unlock(&ssl_mutex);
return 0;
}
frame[0] = 0x82; // FIN + binary opcode
if (data_len <= 125) {
frame[1] = 0x80 | data_len; // MASK + length
} else if (data_len <= 65535) {
frame[1] = 0x80 | 126; // MASK + extended length
frame[2] = (data_len >> 8) & 0xFF;
frame[3] = data_len & 0xFF;
} else {
frame[1] = 0x80 | 127; // MASK + extended length
frame[2] = 0;
frame[3] = 0;
frame[4] = 0;
frame[5] = 0;
frame[6] = (data_len >> 24) & 0xFF;
frame[7] = (data_len >> 16) & 0xFF;
frame[8] = (data_len >> 8) & 0xFF;
frame[9] = data_len & 0xFF;
}
// Add mask key
char mask_key[4];
for (int i = 0; i < 4; i++) {
mask_key[i] = rand() % 256;
frame[header_len - 4 + i] = mask_key[i];
}
// Mask payload
for (size_t i = 0; i < data_len; i++) {
frame[header_len + i] = data[i] ^ mask_key[i % 4];
}
// Handle partial writes for large frames with SIGINT checking
int total_written = 0;
int retry_count = 0;
const int max_retries = 3;
while (total_written < frame_len && retry_count < max_retries) {
// Check for SIGINT to allow interruption
if (sigint_received) {
fprintf(stderr, "[DEBUG] SIGINT received during WebSocket send, aborting\n");
fflush(stderr);
free(frame);
pthread_mutex_unlock(&ssl_mutex);
return 0;
}
int to_write = frame_len - total_written;
// Limit to BUFFER_SIZE to avoid issues with very large frames
if (to_write > BUFFER_SIZE) {
to_write = BUFFER_SIZE;
}
int written = SSL_write(ssl, frame + total_written, to_write);
if (written <= 0) {
int ssl_error = SSL_get_error(ssl, written);
// Handle transient SSL errors with retry
if ((ssl_error == SSL_ERROR_WANT_READ || ssl_error == SSL_ERROR_WANT_WRITE) && retry_count < max_retries - 1) {
retry_count++;
usleep(10000); // Wait 10ms before retry
continue; // Retry the write operation
}
fprintf(stderr, "WebSocket binary frame SSL_write failed: %d (after %d retries)\n", ssl_error, retry_count);
char error_buf[256];
ERR_error_string_n(ssl_error, error_buf, sizeof(error_buf));
fprintf(stderr, "SSL write error details: %s\n", error_buf);
free(frame);
pthread_mutex_unlock(&ssl_mutex);
return 0; // Write failed
}
total_written += written;
retry_count = 0; // Reset retry count on successful write
}
if (total_written < frame_len) {
fprintf(stderr, "WebSocket binary frame write incomplete: %d/%d bytes written\n", total_written, frame_len);
free(frame);
pthread_mutex_unlock(&ssl_mutex);
return 0;
}
free(frame);
pthread_mutex_unlock(&ssl_mutex);
return 1;
}
// Bridge mode transport layer functions - Pure WebSocket connection without tunnel setup // Bridge mode transport layer functions - Pure WebSocket connection without tunnel setup
int setup_websocket_connection(const char *host, int port, const char *client_id, int debug, SSL_CTX **ctx_out) { int setup_websocket_connection(const char *host, int port, const char *client_id, int debug, SSL_CTX **ctx_out) {
int sock; int sock;
...@@ -220,8 +323,7 @@ int setup_websocket_connection(const char *host, int port, const char *client_id ...@@ -220,8 +323,7 @@ int setup_websocket_connection(const char *host, int port, const char *client_id
SSL *ssl; SSL *ssl;
if (debug) { if (debug) {
printf("[DEBUG] Setting up pure WebSocket connection to %s:%d for client %s\n", host, port, client_id); fprintf(stderr, "[DEBUG] Setting up pure WebSocket connection to %s:%d for client %s\n", host, port, client_id);
fflush(stdout);
} }
// Create socket // Create socket
...@@ -313,8 +415,7 @@ int setup_websocket_connection(const char *host, int port, const char *client_id ...@@ -313,8 +415,7 @@ int setup_websocket_connection(const char *host, int port, const char *client_id
// For now, we'll handle cleanup in the calling function // For now, we'll handle cleanup in the calling function
if (debug) { if (debug) {
printf("[DEBUG] Pure WebSocket connection established successfully\n"); fprintf(stderr, "[DEBUG] Pure WebSocket connection established successfully\n");
fflush(stdout);
} }
// Return the SSL context for proper cleanup // Return the SSL context for proper cleanup
......
...@@ -23,11 +23,12 @@ ...@@ -23,11 +23,12 @@
#include <openssl/ssl.h> #include <openssl/ssl.h>
// WSSSH version // WSSSH version
#define WSSSH_VERSION "1.6.1" #define WSSSH_VERSION "1.6.5"
// Function declarations // Function declarations
int websocket_handshake(SSL *ssl, const char *host, int port, const char *path, int debug); int websocket_handshake(SSL *ssl, const char *host, int port, const char *path, int debug);
int send_websocket_frame(SSL *ssl, const char *data); int send_websocket_frame(SSL *ssl, const char *data);
int send_websocket_binary_frame(SSL *ssl, const unsigned char *data, size_t data_len);
int parse_websocket_frame(const char *buffer, int bytes_read, char **payload, int *payload_len); int parse_websocket_frame(const char *buffer, int bytes_read, char **payload, int *payload_len);
// Bridge mode transport layer functions // Bridge mode transport layer functions
......
...@@ -46,8 +46,7 @@ SSL *create_ssl_connection(SSL_CTX *ssl_ctx, int sock, int debug) { ...@@ -46,8 +46,7 @@ SSL *create_ssl_connection(SSL_CTX *ssl_ctx, int sock, int debug) {
SSL_set_fd(ssl, sock); SSL_set_fd(ssl, sock);
if (debug) { if (debug) {
printf("[DEBUG] Establishing SSL connection...\n"); fprintf(stderr, "[DEBUG] Establishing SSL connection...\n");
fflush(stdout);
} }
if (SSL_connect(ssl) <= 0) { if (SSL_connect(ssl) <= 0) {
ERR_print_errors_fp(stderr); ERR_print_errors_fp(stderr);
...@@ -56,8 +55,7 @@ SSL *create_ssl_connection(SSL_CTX *ssl_ctx, int sock, int debug) { ...@@ -56,8 +55,7 @@ SSL *create_ssl_connection(SSL_CTX *ssl_ctx, int sock, int debug) {
return NULL; return NULL;
} }
if (debug) { if (debug) {
printf("[DEBUG] SSL connection established\n"); fprintf(stderr, "[DEBUG] SSL connection established\n");
fflush(stdout);
} }
return ssl; return ssl;
......
...@@ -61,6 +61,13 @@ typedef enum { ...@@ -61,6 +61,13 @@ typedef enum {
MODE_PIPE // ProxyCommand mode: stdin/stdout proxy MODE_PIPE // ProxyCommand mode: stdin/stdout proxy
} wsssh_mode_t; } wsssh_mode_t;
// Data encoding modes
typedef enum {
ENCODING_HEX = 0, // Default: hex encoding
ENCODING_BASE64, // Base64 encoding
ENCODING_BINARY // Binary (no encoding)
} wsssh_encoding_t;
// Config structures // Config structures
typedef struct { typedef struct {
char *local_port; char *local_port;
...@@ -75,6 +82,7 @@ typedef struct { ...@@ -75,6 +82,7 @@ typedef struct {
char *tunnel_control; // Transport types for control channel (comma-separated or "any") char *tunnel_control; // Transport types for control channel (comma-separated or "any")
char *service; // Service type (default: "ssh") char *service; // Service type (default: "ssh")
wsssh_mode_t mode; // Operating mode wsssh_mode_t mode; // Operating mode
wsssh_encoding_t encoding; // Data encoding mode
int daemon; // Daemon mode: lazy initialization int daemon; // Daemon mode: lazy initialization
} wsssh_config_t; } wsssh_config_t;
......
...@@ -14,6 +14,7 @@ wsssht \- WSSH Tunnel Setup Tool ...@@ -14,6 +14,7 @@ wsssht \- WSSH Tunnel Setup Tool
[\fB\-\-tunnel\fR \fITRANSPORT\fR] [\fB\-\-tunnel\fR \fITRANSPORT\fR]
[\fB\-\-tunnel\-control\fR \fITYPES\fR] [\fB\-\-tunnel\-control\fR \fITYPES\fR]
[\fB\-\-service\fR \fISERVICE\fR] [\fB\-\-service\fR \fISERVICE\fR]
[\fB\-\-enc\fR \fIENCODING\fR]
[\fB\-\-mode\fR \fIMODE\fR] [\fB\-\-mode\fR \fIMODE\fR]
[\fB\-\-silent\fR] [\fB\-\-silent\fR]
[\fB\-\-bridge\fR] [\fB\-\-bridge\fR]
...@@ -66,6 +67,9 @@ Transport types for control channel (comma\-separated or 'any', default: any) ...@@ -66,6 +67,9 @@ Transport types for control channel (comma\-separated or 'any', default: any)
.BR \-\-service " \fISERVICE\fR" .BR \-\-service " \fISERVICE\fR"
Service type (default: ssh) Service type (default: ssh)
.TP .TP
.BR \-\-enc " \fIENCODING\fR"
Data encoding: hex, base64, or bin (default: hex)
.TP
.BR \-\-mode " \fIMODE\fR" .BR \-\-mode " \fIMODE\fR"
Operating mode: interactive, silent, bridge, script (default: interactive) Operating mode: interactive, silent, bridge, script (default: interactive)
.TP .TP
...@@ -180,6 +184,7 @@ tunnel-host=127.0.0.1 ...@@ -180,6 +184,7 @@ tunnel-host=127.0.0.1
tunnel=websocket tunnel=websocket
tunnel-control=websocket tunnel-control=websocket
service=ssh service=ssh
enc=hex
interval=5 interval=5
.fi .fi
.RE .RE
......
This diff is collapsed.
This diff is collapsed.
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