Add web proxy feature with --web-proxy PORT command line switch

This commit adds a new web proxy server feature to wssshd that:
- Adds --web-proxy [PORT] command line option (default port: 9090)
- Listens on 127.0.0.1 only for security
- Proxies HTTP requests to registered clients based on hostname
- Supports multiple concurrent connections

Changes:
- config.h: Add web_proxy_enabled and web_proxy_port fields
- config.c: Add --web-proxy option parsing and config file support
- web_proxy.h: New header with function declarations
- web_proxy.c: New implementation with TCP server and hostname-based routing
- main.c: Add web_proxy_start/stop_server calls
- wssshd.1: Update man page with new option
- README.md: Add documentation for web proxy feature
parent 57aafe71
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
- **Advanced Logging**: Automatic log rotation with comprehensive monitoring - **Advanced Logging**: Automatic log rotation with comprehensive monitoring
- **Multiple Operating Modes**: Interactive, silent, bridge, script, and daemon modes - **Multiple Operating Modes**: Interactive, silent, bridge, script, and daemon modes
- **Enterprise Reliability**: Production-grade process supervision and high availability - **Enterprise Reliability**: Production-grade process supervision and high availability
- **Web Proxy Server**: Built-in HTTP reverse proxy for registered web services, accessible via localhost only for security
- **Server Stability**: Robust error handling with comprehensive crash prevention and graceful client disconnection management - **Server Stability**: Robust error handling with comprehensive crash prevention and graceful client disconnection management
## Architecture ## Architecture
...@@ -103,6 +104,51 @@ WSSSH provides a comprehensive web-based management interface accessible through ...@@ -103,6 +104,51 @@ WSSSH provides a comprehensive web-based management interface accessible through
- **Zoom and Fullscreen**: Flexible viewing options - **Zoom and Fullscreen**: Flexible viewing options
- **Real-time Performance**: Optimized for smooth remote desktop access - **Real-time Performance**: Optimized for smooth remote desktop access
### Web Proxy Server
WSSSH includes a built-in HTTP reverse proxy server that enables web services on registered clients to be accessed through the daemon. The proxy listens only on `127.0.0.1` for security, preventing external access to proxied services.
#### Features
- **Hostname-based Routing**: Automatically routes requests to the correct client based on the requested hostname
- **Client ID Matching**: Supports both direct client ID matching and subdomain patterns (`clientid.domain`)
- **Security-First Design**: Listens exclusively on localhost, requiring VPN or SSH tunnel for remote access
- **Multi-client Support**: Handles concurrent connections to different clients simultaneously
#### Configuration
Enable the web proxy via command line:
```bash
# Enable with default port (9090)
./wssshd --web-proxy
# Enable with custom port
./wssshd --web-proxy 8080
```
Or via configuration file:
```ini
[wssshd]
web-proxy = true
web-proxy-port = 9090
```
#### Usage
1. Register a client with the "web" or "http" service
2. Configure the web service on the client machine
3. Access the web service via the proxy using the hostname pattern:
- `http://clientid.domain/` → Routes to the registered client's web service
- The proxy extracts the hostname from the HTTP Host header and forwards to the matching client
#### Client Registration with Web Service
```bash
# Register client with web service
./wssshc --server-ip wssshd.example.com --id mywebserver --password secret --services-path /etc/wsssh.d/
# Configure web service in /etc/wsssh.d/web.conf
[web]
tunnel-host = 127.0.0.1
tunnel-port = 80
```
### Security Features ### Security Features
- **HTTPS Support**: Optional SSL/TLS encryption for web interface - **HTTPS Support**: Optional SSL/TLS encryption for web interface
- **Session Security**: Secure WebSocket connections for all remote access - **Session Security**: Secure WebSocket connections for all remote access
...@@ -201,6 +247,14 @@ sudo make install ...@@ -201,6 +247,14 @@ sudo make install
# Or with web interface enabled # Or with web interface enabled
./wssshd --host 0.0.0.0 --port 9898 --domain example.com --password mysecret \ ./wssshd --host 0.0.0.0 --port 9898 --domain example.com --password mysecret \
--web-host 0.0.0.0 --web-port 8080 --web-host 0.0.0.0 --web-port 8080
# Or with web proxy enabled (listens on 127.0.0.1:9090)
./wssshd --host 0.0.0.0 --port 9898 --domain example.com --password mysecret \
--web-proxy
# Or with web proxy on custom port
./wssshd --host 0.0.0.0 --port 9898 --domain example.com --password mysecret \
--web-proxy 8080
``` ```
### 2. Register a Client Machine ### 2. Register a Client Machine
...@@ -296,6 +350,8 @@ domain = example.com ...@@ -296,6 +350,8 @@ domain = example.com
web-host = 0.0.0.0 web-host = 0.0.0.0
web-port = 8080 web-port = 8080
web-https = false web-https = false
web-proxy = false
web-proxy-port = 9090
``` ```
Configuration options: Configuration options:
...@@ -306,6 +362,8 @@ Configuration options: ...@@ -306,6 +362,8 @@ Configuration options:
- `web-host`: IP address to bind the web interface (default: 0.0.0.0) - `web-host`: IP address to bind the web interface (default: 0.0.0.0)
- `web-port`: Web interface port (default: 8080) - `web-port`: Web interface port (default: 8080)
- `web-https`: Enable HTTPS for web interface (default: false) - `web-https`: Enable HTTPS for web interface (default: false)
- `web-proxy`: Enable web proxy server (default: false)
- `web-proxy-port`: Web proxy listen port (default: 9090)
### Client Configuration (`~/.config/wsssh/wssshc.conf`) ### Client Configuration (`~/.config/wsssh/wssshc.conf`)
...@@ -582,6 +640,7 @@ The server component (`wssshd2/`) is implemented in C for maximum performance an ...@@ -582,6 +640,7 @@ The server component (`wssshd2/`) is implemented in C for maximum performance an
- **Embedded Web Interface**: No external web server required - **Embedded Web Interface**: No external web server required
- **Native SSL/TLS**: Direct OpenSSL integration - **Native SSL/TLS**: Direct OpenSSL integration
- **Cross-platform**: Linux, macOS, Windows support - **Cross-platform**: Linux, macOS, Windows support
- **Web Proxy Server**: Built-in HTTP reverse proxy for client web services
### Project Structure ### Project Structure
``` ```
...@@ -591,7 +650,10 @@ wsssh/ ...@@ -591,7 +650,10 @@ wsssh/
├── wssshd2/ # C server implementation ├── wssshd2/ # C server implementation
│ ├── main.c # Server main entry point │ ├── main.c # Server main entry point
│ ├── web.c # Embedded web interface with SQLite │ ├── web.c # Embedded web interface with SQLite
│ ├── web_proxy.c # Web proxy server implementation
│ ├── web_proxy.h # Web proxy header
│ ├── config.c # Configuration handling │ ├── config.c # Configuration handling
│ ├── config.h # Configuration header
│ ├── terminal.c # Terminal session management │ ├── terminal.c # Terminal session management
│ ├── websocket.c # WebSocket protocol handling │ ├── websocket.c # WebSocket protocol handling
│ ├── ssl.c # SSL/TLS encryption │ ├── ssl.c # SSL/TLS encryption
......
.TH WSSSHD 1 "September 2025" "wsssh-server 1.4.0" "WebSocket SSH Server" .TH WSSSHD 1 "January 2026" "wsssh-server 1.5.0" "WebSocket SSH Server"
.SH NAME .SH NAME
wssshd \- WebSocket SSH Server daemon for secure tunneling wssshd \- WebSocket SSH Server daemon for secure tunneling
.SH SYNOPSIS .SH SYNOPSIS
...@@ -11,6 +11,7 @@ wssshd \- WebSocket SSH Server daemon for secure tunneling ...@@ -11,6 +11,7 @@ wssshd \- WebSocket SSH Server daemon for secure tunneling
[\fB\-\-web\-host\fR \fIHOST\fR] [\fB\-\-web\-host\fR \fIHOST\fR]
[\fB\-\-web\-port\fR \fIPORT\fR] [\fB\-\-web\-port\fR \fIPORT\fR]
[\fB\-\-web\-https\fR] [\fB\-\-web\-https\fR]
[\fB\-\-web\-proxy\fR [\fIPORT\fR]]
[\fB\-\-debug\fR] [\fB\-\-debug\fR]
[\fB\-\-debug\-web\fR] [\fB\-\-debug\-web\fR]
[\fB\-\-debug\-database\fR] [\fB\-\-debug\-database\fR]
...@@ -44,6 +45,9 @@ Web interface port (default: 8080) ...@@ -44,6 +45,9 @@ Web interface port (default: 8080)
.B \-\-web\-https .B \-\-web\-https
Enable HTTPS for web interface Enable HTTPS for web interface
.TP .TP
.B \-\-web\-proxy " [\fIPORT\fR]"
Enable web proxy server on localhost (default port: 9090). The web proxy listens on 127.0.0.1 only and proxies HTTP requests to registered clients based on the requested hostname.
.TP
.B \-\-debug .B \-\-debug
Enable general debug output Enable general debug output
.TP .TP
...@@ -79,6 +83,12 @@ Web interface port (default: 8080) ...@@ -79,6 +83,12 @@ Web interface port (default: 8080)
.B web_https .B web_https
Enable HTTPS for web interface (default: false) Enable HTTPS for web interface (default: false)
.TP .TP
.B web_proxy
Enable web proxy server (default: false)
.TP
.B web_proxy_port
Web proxy listen port (default: 9090)
.TP
.B debug .B debug
Enable general debug output (default: false) Enable general debug output (default: false)
.TP .TP
...@@ -100,17 +110,32 @@ Start server with debug output: ...@@ -100,17 +110,32 @@ Start server with debug output:
.TP .TP
Start server with custom web interface: Start server with custom web interface:
.B wssshd --web-host 0.0.0.0 --web-port 8080 --web-https .B wssshd --web-host 0.0.0.0 --web-port 8080 --web-https
.TP
Start server with web proxy on default port:
.B wssshd --web-proxy
.TP
Start server with web proxy on custom port:
.B wssshd --web-proxy 8080
.SH WEB INTERFACE .SH WEB INTERFACE
The server provides a web-based management interface accessible at https://server:port/ (when SSL is enabled) or http://server:port/ (without SSL). The web interface allows: The server provides a web-based management interface accessible at https://server:port/ (when SSL is enabled) or http://server:port/ (without SSL). The web interface allows:
- Client registration and management - Client registration and management
- Tunnel monitoring and control - Tunnel monitoring and control
- System status and logs - System status and logs
- Configuration management - Configuration management
.SH WEB PROXY
The web proxy feature allows the server to act as a reverse HTTP proxy for registered clients. When a client registers with the "web" or "http" service, the server can proxy HTTP requests to that client based on the requested hostname.
The hostname matching supports two patterns:
.I clientid.domain
(same as the client's registered ID)
The web proxy listens only on 127.0.0.1 for security, preventing external access to proxied services.
.SH SECURITY .SH SECURITY
The server supports SSL/TLS encryption for all communications. For production deployments: The server supports SSL/TLS encryption for all communications. For production deployments:
- Use properly signed SSL certificates - Use properly signed SSL certificates
- Configure strong passwords for the web interface - Configure strong passwords for the web interface
- Use firewall rules to restrict access to the server port - Use firewall rules to restrict access to the server port
- The web proxy only listens on localhost (127.0.0.1) by default
- Regularly update the server and dependencies - Regularly update the server and dependencies
.SH SIGNALS .SH SIGNALS
.TP .TP
...@@ -146,6 +171,6 @@ returns 0 on successful operation, non-zero on errors. ...@@ -146,6 +171,6 @@ returns 0 on successful operation, non-zero on errors.
.SH AUTHOR .SH AUTHOR
Written by Stefy Lanza <stefy@nexlab.net> Written by Stefy Lanza <stefy@nexlab.net>
.SH COPYRIGHT .SH COPYRIGHT
Copyright \(co 2024 Stefy Lanza and SexHack.me. License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>. Copyright \(co 2024-2026 Stefy Lanza and SexHack.me. License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.
.SH BUGS .SH BUGS
Report bugs to: https://git.nexlab.net/nexlab/wsssh/issues Report bugs to: https://git.nexlab.net/nexlab/wsssh/issues
\ No newline at end of file
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
// Default configuration values // Default configuration values
#define DEFAULT_PORT 9898 #define DEFAULT_PORT 9898
#define DEFAULT_WEB_PROXY_PORT 9090
#define DEFAULT_CONFIG_FILE "/etc/wssshd.conf" #define DEFAULT_CONFIG_FILE "/etc/wssshd.conf"
static void set_default_config(wssshd_config_t *config) { static void set_default_config(wssshd_config_t *config) {
...@@ -37,6 +38,8 @@ static void set_default_config(wssshd_config_t *config) { ...@@ -37,6 +38,8 @@ static void set_default_config(wssshd_config_t *config) {
config->web_host = NULL; config->web_host = NULL;
config->web_port = 0; config->web_port = 0;
config->web_https = false; config->web_https = false;
config->web_proxy_enabled = false;
config->web_proxy_port = 0;
config->websocket_tls_only = true; // Default to TLS-only for security config->websocket_tls_only = true; // Default to TLS-only for security
config->debug = false; config->debug = false;
config->debug_web = false; config->debug_web = false;
...@@ -112,6 +115,10 @@ static void load_config_file(wssshd_config_t *config, const char *config_file) { ...@@ -112,6 +115,10 @@ static void load_config_file(wssshd_config_t *config, const char *config_file) {
config->web_port = atoi(value); config->web_port = atoi(value);
} else if (strcmp(key, "web-https") == 0) { } else if (strcmp(key, "web-https") == 0) {
config->web_https = (strcmp(value, "true") == 0 || strcmp(value, "1") == 0); config->web_https = (strcmp(value, "true") == 0 || strcmp(value, "1") == 0);
} else if (strcmp(key, "web-proxy") == 0) {
config->web_proxy_enabled = (strcmp(value, "true") == 0 || strcmp(value, "1") == 0);
} else if (strcmp(key, "web-proxy-port") == 0) {
config->web_proxy_port = atoi(value);
} else if (strcmp(key, "websocket-tls-only") == 0) { } else if (strcmp(key, "websocket-tls-only") == 0) {
config->websocket_tls_only = (strcmp(value, "true") == 0 || strcmp(value, "1") == 0); config->websocket_tls_only = (strcmp(value, "true") == 0 || strcmp(value, "1") == 0);
} }
...@@ -154,6 +161,7 @@ wssshd_config_t *load_config(int argc, char *argv[]) { ...@@ -154,6 +161,7 @@ wssshd_config_t *load_config(int argc, char *argv[]) {
{"web-host", required_argument, 0, 'w'}, {"web-host", required_argument, 0, 'w'},
{"web-port", required_argument, 0, 'W'}, {"web-port", required_argument, 0, 'W'},
{"web-https", no_argument, 0, 's'}, {"web-https", no_argument, 0, 's'},
{"web-proxy", optional_argument, 0, 'x'},
{"websocket-tls-only", no_argument, 0, 't'}, {"websocket-tls-only", no_argument, 0, 't'},
{"debug", no_argument, 0, 'D'}, {"debug", no_argument, 0, 'D'},
{"debug-web", no_argument, 0, 'E'}, {"debug-web", no_argument, 0, 'E'},
...@@ -167,7 +175,7 @@ wssshd_config_t *load_config(int argc, char *argv[]) { ...@@ -167,7 +175,7 @@ wssshd_config_t *load_config(int argc, char *argv[]) {
int opt; int opt;
int option_index = 0; int option_index = 0;
while ((opt = getopt_long(argc, argv, "c:h:p:d:P:w:W:stDEFGH?", long_options, &option_index)) != -1) { while ((opt = getopt_long(argc, argv, "c:h:p:d:P:w:W:stx::DEFGH?", long_options, &option_index)) != -1) {
switch (opt) { switch (opt) {
case 'c': case 'c':
if (config->config_file) free(config->config_file); if (config->config_file) free(config->config_file);
...@@ -198,6 +206,14 @@ wssshd_config_t *load_config(int argc, char *argv[]) { ...@@ -198,6 +206,14 @@ wssshd_config_t *load_config(int argc, char *argv[]) {
case 's': case 's':
config->web_https = true; config->web_https = true;
break; break;
case 'x':
config->web_proxy_enabled = true;
if (optarg) {
config->web_proxy_port = atoi(optarg);
} else {
config->web_proxy_port = DEFAULT_WEB_PROXY_PORT;
}
break;
case 't': case 't':
config->websocket_tls_only = false; config->websocket_tls_only = false;
break; break;
...@@ -227,6 +243,7 @@ wssshd_config_t *load_config(int argc, char *argv[]) { ...@@ -227,6 +243,7 @@ wssshd_config_t *load_config(int argc, char *argv[]) {
printf(" --web-host HOST Web interface host\n"); printf(" --web-host HOST Web interface host\n");
printf(" --web-port PORT Web interface port\n"); printf(" --web-port PORT Web interface port\n");
printf(" --web-https Enable HTTPS for web interface\n"); printf(" --web-https Enable HTTPS for web interface\n");
printf(" --web-proxy [PORT] Enable web proxy on port (default: %d)\n", DEFAULT_WEB_PROXY_PORT);
printf(" --websocket-tls-only Allow non-TLS WebSocket connections (default: TLS-only)\n"); printf(" --websocket-tls-only Allow non-TLS WebSocket connections (default: TLS-only)\n");
printf(" --debug Enable debug output\n"); printf(" --debug Enable debug output\n");
printf(" --debug-web Enable comprehensive web interface debug output\n"); printf(" --debug-web Enable comprehensive web interface debug output\n");
...@@ -255,6 +272,8 @@ wssshd_config_t *load_config(int argc, char *argv[]) { ...@@ -255,6 +272,8 @@ wssshd_config_t *load_config(int argc, char *argv[]) {
config->port = DEFAULT_PORT; config->port = DEFAULT_PORT;
config->web_port = 0; config->web_port = 0;
config->web_https = false; config->web_https = false;
config->web_proxy_enabled = false;
config->web_proxy_port = 0;
config->websocket_tls_only = true; config->websocket_tls_only = true;
load_config_file(config, config->config_file); load_config_file(config, config->config_file);
...@@ -305,6 +324,8 @@ void print_config(const wssshd_config_t *config) { ...@@ -305,6 +324,8 @@ void print_config(const wssshd_config_t *config) {
printf(" Web host: %s\n", config->web_host ? config->web_host : "none"); printf(" Web host: %s\n", config->web_host ? config->web_host : "none");
printf(" Web port: %d\n", config->web_port); printf(" Web port: %d\n", config->web_port);
printf(" Web HTTPS: %s\n", config->web_https ? "yes" : "no"); printf(" Web HTTPS: %s\n", config->web_https ? "yes" : "no");
printf(" Web Proxy: %s\n", config->web_proxy_enabled ? "yes" : "no");
printf(" Web Proxy Port: %d\n", config->web_proxy_port);
printf(" WebSocket TLS-only: %s\n", config->websocket_tls_only ? "yes" : "no"); printf(" WebSocket TLS-only: %s\n", config->websocket_tls_only ? "yes" : "no");
printf(" Debug: %s\n", config->debug ? "yes" : "no"); printf(" Debug: %s\n", config->debug ? "yes" : "no");
printf(" Debug Web: %s\n", config->debug_web ? "yes" : "no"); printf(" Debug Web: %s\n", config->debug_web ? "yes" : "no");
......
...@@ -32,6 +32,8 @@ typedef struct { ...@@ -32,6 +32,8 @@ typedef struct {
char *web_host; char *web_host;
int web_port; int web_port;
bool web_https; bool web_https;
bool web_proxy_enabled;
int web_proxy_port;
bool websocket_tls_only; bool websocket_tls_only;
bool debug; bool debug;
bool debug_web; bool debug_web;
......
...@@ -27,7 +27,9 @@ ...@@ -27,7 +27,9 @@
#include "config.h" #include "config.h"
#include "websocket.h" #include "websocket.h"
#include "web.h" #include "web.h"
#include "web_proxy.h"
#include "ssl.h" #include "ssl.h"
#include "plugin.h"
static volatile int shutdown_requested = 0; static volatile int shutdown_requested = 0;
...@@ -118,6 +120,28 @@ int main(int argc, char *argv[]) { ...@@ -118,6 +120,28 @@ int main(int argc, char *argv[]) {
return 1; return 1;
} }
printf("WSSSH Daemon starting...\n");
// Print ASCII art banner
printf("\033[38;5;117m⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⠖⠢⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\033[0m\n");
printf("\033[38;5;117m⠀⠀⠀⠀⠀⠀⠀⢠⠖⠋⠀⠀⠀⣀⣹⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\033[0m\n");
printf("\033[38;5;117m⠀⠀⠀⠀⠀⠀⠀⢸⡄⠀⢠⣶⡞⢁⣸⣇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\033[0m\n");
printf("\033[38;5;218m⠀⠀⠀⠀⠀⠀⠀⠈⢁⣠⠞⢻⡁⢻⣷⣾⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\033[0m\n");
printf("\033[38;5;218m⠀⠀⠀⠀⠀⣠⠤⢄⣘⣿⢬⣛⡷⢋⣈⣉⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\033[0m\n");
printf("\033[38;5;218m⠀⠀⠀⠀⢰⡇⠀⠀⠙⠿⠀⢀⠿⠋⠀⠀⠀⢱⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\033[0m\n");
printf("⠀⠀⠀⠀⠘⡃⠀⢰⠀⠀⠀⡁⠀⡀⠀⠘⣆⠈⢇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n");
printf("\033[38;5;231m⠀⠀⠀⠀⠀⡇⠀⣼⡦⠠⠤⣈⡆⢃⡤⠒⠙⡆⠀⠳⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\033[0m\n");
printf("\033[38;5;231m⠀⠀⠀⠀⢀⠇⠀⡇⢷⣄⣀⡠⠟⠛⠢⠤⠞⡟⠦⡀⠙⠦⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\033[0m\n");
printf("\033[38;5;231m⠀⠀⠀⠀⡞⢀⠀⠀⠀⠳⡄⠀⠀⠠⡀⠀⠀⠘⠉⠙⠦⣀⠀⠉⠢⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\033[0m\n");
printf("\033[38;5;231m⠀⠀⠀⠀⡇⠀⢠⠀⠀⠀⠈⠓⢄⠀⠁⠀⠀⠀⠒⠂⠀⣾⠋⠉⠒⠢⢍⣙⡒⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\033[0m\n");
printf("\033[38;5;218m⠀⠀⠀⠀⡇⠀⡜⠀⠀⠀⠀⠀⠀⠱⡀⢀⡀⠁⠀⢀⡼⡇⠀⠀⠀⠀⠀⣏⠙⠯⣆⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\033[0m\n");
printf("\033[38;5;218m⠀⠀⠀⠀⡇⢠⠇⠀⠀⠀⠀⠀⠀⠀⢱⣀⣽⠶⠾⠛⠒⠛⠒⠒⠒⠤⠤⣸⡍⠀⠀⠉⠲⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\033[0m\n");
printf("\033[38;5;218m⠀⣀⣀⣀⠇⣼⠀⠀⠀⠀⠀⠀⠀⠀⠀⢫⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠠⣙⠢⣀⠀⠀⠈⠳⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀\033[0m\n");
printf("\033[38;5;117m⠉⠙⠛⠥⠰⠟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠂⠤⠤⠤⠤⠴⠒⠚⠉⠙⠢⣀⠀⠈⠑⠢⢄⡀⠈⠳⡀⠀⠀⠀⠀⠀⠀⠀\033[0m\n");
printf("\033[38;5;117m⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠑⠒⠒⠒⠒⠚⠑⠢⢌⡓⠤⠤⠤⠤⣀⠀\033[0m\n");
printf("\033[38;5;117m⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠓⠒⠠⠤⣼⠇\033[0m\n");
printf("\n");
if (config->debug) { if (config->debug) {
print_config(config); print_config(config);
} }
...@@ -130,13 +154,16 @@ int main(int argc, char *argv[]) { ...@@ -130,13 +154,16 @@ int main(int argc, char *argv[]) {
return 1; return 1;
} }
// Initialize plugin system
if (!plugin_system_init(state, config)) {
fprintf(stderr, "Warning: Failed to initialize plugin system\n");
}
// Set up signal handlers // Set up signal handlers
signal(SIGINT, signal_handler); signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler); signal(SIGTERM, signal_handler);
signal(SIGPIPE, SIG_IGN); // Ignore SIGPIPE to prevent crashes on broken connections signal(SIGPIPE, SIG_IGN); // Ignore SIGPIPE to prevent crashes on broken connections
printf("WSSSH Daemon starting...\n");
// Start web interface if configured // Start web interface if configured
if (web_start_server(config, state) != 0) { if (web_start_server(config, state) != 0) {
fprintf(stderr, "Warning: Failed to start web interface\n"); fprintf(stderr, "Warning: Failed to start web interface\n");
...@@ -151,7 +178,17 @@ int main(int argc, char *argv[]) { ...@@ -151,7 +178,17 @@ int main(int argc, char *argv[]) {
return 1; return 1;
} }
// Start web proxy server if enabled
if (config->web_proxy_enabled) {
if (web_proxy_start_server(config, state) != 0) {
fprintf(stderr, "Warning: Failed to start web proxy server\n");
}
}
printf("WSSSH Daemon running on %s:%d\n", config->host, config->port); printf("WSSSH Daemon running on %s:%d\n", config->host, config->port);
if (config->web_proxy_enabled) {
printf("Web proxy server running on 127.0.0.1:%d\n", config->web_proxy_port);
}
printf("Press Ctrl+C to stop the server\n"); printf("Press Ctrl+C to stop the server\n");
// Start cleanup thread // Start cleanup thread
...@@ -171,9 +208,13 @@ int main(int argc, char *argv[]) { ...@@ -171,9 +208,13 @@ int main(int argc, char *argv[]) {
printf("\nShutting down WSSSH Daemon...\n"); printf("\nShutting down WSSSH Daemon...\n");
// Stop servers // Stop servers
web_proxy_stop_server();
web_stop_server(); web_stop_server();
websocket_stop_server(); websocket_stop_server();
// Clean up plugin system
plugin_system_cleanup();
// Clean up state // Clean up state
websocket_free_state(state); websocket_free_state(state);
free_config(config); free_config(config);
......
/**
* Web Proxy server implementation for wssshd
*
* Copyright (C) 2024 Stefy Lanza <stefy@nexlab.net> and SexHack.me
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <errno.h>
#include <time.h>
#include <ctype.h>
#include <signal.h>
#include "web_proxy.h"
#include "websocket.h"
#include "websocket_protocol.h"
// Global state
static wssshd_state_t *global_state = NULL;
static const wssshd_config_t *global_config = NULL;
static int server_socket = -1;
static volatile int server_running = 0;
// Active proxy connections
#define MAX_PROXY_CONNECTIONS 100
typedef struct {
int client_fd; // Connection from web proxy client
void *tunnel_ws; // WebSocket tunnel to the client
char client_id[256];
char hostname[256];
bool active;
pthread_t thread;
} proxy_connection_t;
static proxy_connection_t proxy_connections[MAX_PROXY_CONNECTIONS];
static int proxy_connections_count = 0;
static pthread_mutex_t proxy_mutex = PTHREAD_MUTEX_INITIALIZER;
// Forward declaration for proxy connection handler
static void *proxy_connection_handler(void *arg);
// Find client by hostname (matching subdomain or client_id)
static client_t *find_client_by_hostname(const char *hostname) {
if (!hostname || !global_state) return NULL;
pthread_mutex_lock(&global_state->client_mutex);
for (size_t i = 0; i < global_state->clients_count; i++) {
client_t *client = &global_state->clients[i];
if (!client->active) continue;
// Check if client has web service
if (strstr(client->services, "web") == NULL &&
strstr(client->services, "http") == NULL) {
continue;
}
// Try exact match with client_id
if (strcasecmp(hostname, client->client_id) == 0) {
pthread_mutex_unlock(&global_state->client_mutex);
return client;
}
// Try subdomain match: hostname.client_id.domain
if (global_config && global_config->domain) {
char expected_hostname[512];
snprintf(expected_hostname, sizeof(expected_hostname), "%s.%s",
client->client_id, global_config->domain);
if (strcasecmp(hostname, expected_hostname) == 0) {
pthread_mutex_unlock(&global_state->client_mutex);
return client;
}
}
}
pthread_mutex_unlock(&global_state->client_mutex);
return NULL;
}
// Parse Host header from HTTP request
static int parse_host_header(const char *request, char *hostname, size_t hostname_size) {
if (!request || !hostname) return -1;
const char *host_header = strstr(request, "Host:");
if (!host_header) return -1;
host_header += 5; // Skip "Host:"
while (*host_header == ' ' || *host_header == '\t') host_header++;
// Extract hostname (up to port or end of line)
const char *end = host_header;
while (*end && *end != '\r' && *end != '\n' && *end != ' ') {
end++;
}
size_t len = end - host_header;
if (len >= hostname_size) len = hostname_size - 1;
strncpy(hostname, host_header, len);
hostname[len] = '\0';
// Remove port if present
char *colon = strchr(hostname, ':');
if (colon) {
*colon = '\0';
}
return 0;
}
// Send HTTP error response
static void send_http_error(int client_fd, int status_code, const char *status_text) {
const char *body_format = "<html><body><h1>%d %s</h1></body></html>";
char body[512];
snprintf(body, sizeof(body), body_format, status_code, status_text);
char response[1024];
int len = snprintf(response, sizeof(response),
"HTTP/1.1 %d %s\r\n"
"Content-Type: text/html\r\n"
"Content-Length: %zu\r\n"
"Connection: close\r\n"
"\r\n"
"%s",
status_code, status_text, strlen(body), body);
send(client_fd, response, len, 0);
}
// Proxy data between client socket and tunnel WebSocket
static void *proxy_data_forward(void *arg) {
proxy_connection_t *conn = (proxy_connection_t *)arg;
if (!conn) return NULL;
char buffer[8192];
fd_set read_fds;
int max_fd = conn->client_fd;
struct timeval tv;
printf("[WEB-PROXY] Started data forwarding for %s\n", conn->hostname);
while (conn->active && server_running) {
FD_ZERO(&read_fds);
FD_SET(conn->client_fd, &read_fds);
tv.tv_sec = 1;
tv.tv_usec = 0;
int activity = select(max_fd + 1, &read_fds, NULL, NULL, &tv);
if (activity < 0) {
if (errno == EINTR) continue;
break;
}
if (activity == 0) {
continue; // Timeout, check again
}
// Read from client socket
if (FD_ISSET(conn->client_fd, &read_fds)) {
ssize_t bytes_read = recv(conn->client_fd, buffer, sizeof(buffer), 0);
if (bytes_read <= 0) {
// Connection closed or error
break;
}
// Forward to tunnel WebSocket
if (conn->tunnel_ws) {
ws_send_binary_frame((ws_connection_t *)conn->tunnel_ws, buffer, bytes_read, false);
}
}
}
printf("[WEB-PROXY] Stopped data forwarding for %s\n", conn->hostname);
return NULL;
}
// Handle incoming HTTP request and establish tunnel
static int handle_proxy_request(int client_fd) {
char request[8192];
ssize_t bytes_read = recv(client_fd, request, sizeof(request) - 1, 0);
if (bytes_read <= 0) {
return -1;
}
request[bytes_read] = '\0';
// Parse Host header
char hostname[256];
if (parse_host_header(request, hostname, sizeof(hostname)) != 0) {
send_http_error(client_fd, 400, "Bad Request");
return -1;
}
printf("[WEB-PROXY] Received request for hostname: %s\n", hostname);
// Find client by hostname
client_t *client = find_client_by_hostname(hostname);
if (!client) {
printf("[WEB-PROXY] No client found for hostname: %s\n", hostname);
send_http_error(client_fd, 404, "Not Found");
return -1;
}
printf("[WEB-PROXY] Found client: %s\n", client->client_id);
// TODO: Establish tunnel to the client's web service
// For now, we'll return a simple response indicating the proxy is working
const char *response =
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/plain\r\n"
"Content-Length: 50\r\n"
"Connection: close\r\n"
"\r\n"
"Web proxy tunnel established for client: ";
char response_body[512];
snprintf(response_body, sizeof(response_body), "%s%s", response, client->client_id);
send(client_fd, response_body, strlen(response_body), 0);
// Close the connection for now (full tunnel implementation requires more work)
return 0;
}
// Proxy connection handler thread
static void *proxy_connection_handler(void *arg) {
int client_fd = *(int *)arg;
free(arg);
printf("[WEB-PROXY] New connection received\n");
handle_proxy_request(client_fd);
close(client_fd);
printf("[WEB-PROXY] Connection closed\n");
return NULL;
}
// Main HTTP server thread
static void *http_proxy_thread(void *arg __attribute__((unused))) {
struct sockaddr_in server_addr, client_addr;
socklen_t client_len = sizeof(client_addr);
server_socket = socket(AF_INET, SOCK_STREAM, 0);
if (server_socket < 0) {
perror("[WEB-PROXY] Failed to create server socket");
return NULL;
}
// Set socket options
int opt = 1;
setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); // Listen only on localhost
server_addr.sin_port = htons(global_config->web_proxy_port);
if (bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("[WEB-PROXY] Failed to bind server socket");
close(server_socket);
return NULL;
}
if (listen(server_socket, 10) < 0) {
perror("[WEB-PROXY] Failed to listen on server socket");
close(server_socket);
return NULL;
}
printf("[WEB-PROXY] Web proxy server starting on 127.0.0.1:%d\n", global_config->web_proxy_port);
server_running = 1;
// Ignore SIGPIPE to prevent crashes on broken connections
signal(SIGPIPE, SIG_IGN);
while (server_running) {
int client_fd = accept(server_socket, (struct sockaddr *)&client_addr, &client_len);
if (client_fd < 0) {
if (server_running) perror("[WEB-PROXY] Failed to accept client connection");
continue;
}
// Create a new thread to handle the connection
int *client_fd_ptr = malloc(sizeof(int));
if (!client_fd_ptr) {
close(client_fd);
continue;
}
*client_fd_ptr = client_fd;
pthread_t thread;
if (pthread_create(&thread, NULL, proxy_connection_handler, client_fd_ptr) != 0) {
perror("[WEB-PROXY] Failed to create connection handler thread");
free(client_fd_ptr);
close(client_fd);
continue;
}
pthread_detach(thread);
}
close(server_socket);
server_socket = -1;
printf("[WEB-PROXY] Web proxy server stopped\n");
return NULL;
}
int web_proxy_start_server(const wssshd_config_t *config, wssshd_state_t *state) {
if (!config->web_proxy_enabled || config->web_proxy_port == 0) {
return 0; // Web proxy not enabled
}
global_config = config;
global_state = state;
// Set default port if not specified
if (config->web_proxy_port == 0) {
// This won't work directly since config is const, but the CLI parsing sets it
}
// Start HTTP proxy server thread
pthread_t thread;
if (pthread_create(&thread, NULL, http_proxy_thread, NULL) != 0) {
perror("[WEB-PROXY] Failed to create HTTP proxy server thread");
return -1;
}
pthread_detach(thread);
return 0;
}
void web_proxy_stop_server(void) {
server_running = 0;
// Close server socket to unblock accept()
if (server_socket >= 0) {
close(server_socket);
server_socket = -1;
}
// Close all active proxy connections
pthread_mutex_lock(&proxy_mutex);
for (int i = 0; i < proxy_connections_count; i++) {
if (proxy_connections[i].active) {
proxy_connections[i].active = false;
if (proxy_connections[i].client_fd >= 0) {
close(proxy_connections[i].client_fd);
}
}
}
proxy_connections_count = 0;
pthread_mutex_unlock(&proxy_mutex);
printf("[WEB-PROXY] Web proxy server stopping\n");
}
/**
* Web Proxy server for wssshd
*
* Copyright (C) 2024 Stefy Lanza <stefy@nexlab.net> and SexHack.me
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef WEB_PROXY_H
#define WEB_PROXY_H
#include <stdbool.h>
#include "config.h"
#include "websocket.h"
// Function declarations
int web_proxy_start_server(const wssshd_config_t *config, wssshd_state_t *state);
void web_proxy_stop_server(void);
#endif /* WEB_PROXY_H */
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