Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
wsssh
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexlab
wsssh
Commits
96207bd8
Commit
96207bd8
authored
Sep 17, 2025
by
Stefy Lanza (nextime / spora )
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix wssshc tunnel handling - remove SSH protocol logic, implement raw TCP forwarding
parent
1114c673
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
173 additions
and
197 deletions
+173
-197
tunnel.c
wssshtools/tunnel.c
+102
-170
tunnel.h
wssshtools/tunnel.h
+1
-1
wsssh.c
wssshtools/wsssh.c
+1
-0
wssshc.c
wssshtools/wssshc.c
+69
-26
No files found.
wssshtools/tunnel.c
View file @
96207bd8
...
@@ -95,7 +95,7 @@ int frame_buffer_consume(frame_buffer_t *fb, size_t len) {
...
@@ -95,7 +95,7 @@ int frame_buffer_consume(frame_buffer_t *fb, size_t len) {
return
1
;
return
1
;
}
}
void
handle_tunnel_request
(
SSL
*
ssl
,
const
char
*
request_id
,
int
debug
)
{
void
handle_tunnel_request
(
SSL
*
ssl
,
const
char
*
request_id
,
int
debug
,
const
char
*
ssh_host
,
int
ssh_port
)
{
pthread_mutex_lock
(
&
tunnel_mutex
);
pthread_mutex_lock
(
&
tunnel_mutex
);
if
(
active_tunnel
)
{
if
(
active_tunnel
)
{
if
(
active_tunnel
->
sock
>=
0
)
{
if
(
active_tunnel
->
sock
>=
0
)
{
...
@@ -110,11 +110,11 @@ void handle_tunnel_request(SSL *ssl, const char *request_id, int debug) {
...
@@ -110,11 +110,11 @@ void handle_tunnel_request(SSL *ssl, const char *request_id, int debug) {
return
;
return
;
}
}
// For wssshc:
Act as SSH client - connect to target SSH server
// For wssshc:
Connect to target TCP endpoint and forward raw TCP data
struct
sockaddr_in
target_addr
;
struct
sockaddr_in
target_addr
;
int
ssh
_sock
=
socket
(
AF_INET
,
SOCK_STREAM
,
0
);
int
target
_sock
=
socket
(
AF_INET
,
SOCK_STREAM
,
0
);
if
(
ssh
_sock
<
0
)
{
if
(
target
_sock
<
0
)
{
perror
(
"
SSH
socket creation failed"
);
perror
(
"
Target
socket creation failed"
);
free
(
active_tunnel
);
free
(
active_tunnel
);
active_tunnel
=
NULL
;
active_tunnel
=
NULL
;
pthread_mutex_unlock
(
&
tunnel_mutex
);
pthread_mutex_unlock
(
&
tunnel_mutex
);
...
@@ -123,19 +123,30 @@ void handle_tunnel_request(SSL *ssl, const char *request_id, int debug) {
...
@@ -123,19 +123,30 @@ void handle_tunnel_request(SSL *ssl, const char *request_id, int debug) {
memset
(
&
target_addr
,
0
,
sizeof
(
target_addr
));
memset
(
&
target_addr
,
0
,
sizeof
(
target_addr
));
target_addr
.
sin_family
=
AF_INET
;
target_addr
.
sin_family
=
AF_INET
;
target_addr
.
sin_port
=
htons
(
22
);
// Target SSH port
target_addr
.
sin_port
=
htons
(
ssh_port
);
// Target port
target_addr
.
sin_addr
.
s_addr
=
htonl
(
INADDR_LOOPBACK
);
// Target SSH host
// Resolve target host
struct
hostent
*
target_he
;
if
((
target_he
=
gethostbyname
(
ssh_host
))
==
NULL
)
{
herror
(
"Target host resolution failed"
);
close
(
target_sock
);
free
(
active_tunnel
);
active_tunnel
=
NULL
;
pthread_mutex_unlock
(
&
tunnel_mutex
);
return
;
}
target_addr
.
sin_addr
=
*
((
struct
in_addr
*
)
target_he
->
h_addr
);
// Target host
if
(
connect
(
ssh
_sock
,
(
struct
sockaddr
*
)
&
target_addr
,
sizeof
(
target_addr
))
<
0
)
{
if
(
connect
(
target
_sock
,
(
struct
sockaddr
*
)
&
target_addr
,
sizeof
(
target_addr
))
<
0
)
{
perror
(
"Connection to target
SSH server
failed"
);
perror
(
"Connection to target
endpoint
failed"
);
close
(
ssh
_sock
);
close
(
target
_sock
);
free
(
active_tunnel
);
free
(
active_tunnel
);
active_tunnel
=
NULL
;
active_tunnel
=
NULL
;
pthread_mutex_unlock
(
&
tunnel_mutex
);
pthread_mutex_unlock
(
&
tunnel_mutex
);
return
;
return
;
}
}
active_tunnel
->
sock
=
ssh_sock
;
// SSH client
connection to target
active_tunnel
->
sock
=
target_sock
;
// TCP
connection to target
active_tunnel
->
local_sock
=
-
1
;
// Not used in wssshc
active_tunnel
->
local_sock
=
-
1
;
// Not used in wssshc
strcpy
(
active_tunnel
->
request_id
,
request_id
);
strcpy
(
active_tunnel
->
request_id
,
request_id
);
active_tunnel
->
active
=
1
;
active_tunnel
->
active
=
1
;
...
@@ -143,77 +154,34 @@ void handle_tunnel_request(SSL *ssl, const char *request_id, int debug) {
...
@@ -143,77 +154,34 @@ void handle_tunnel_request(SSL *ssl, const char *request_id, int debug) {
active_tunnel
->
ssl
=
ssl
;
active_tunnel
->
ssl
=
ssl
;
active_tunnel
->
outgoing_buffer
=
NULL
;
// wssshc doesn't use buffer
active_tunnel
->
outgoing_buffer
=
NULL
;
// wssshc doesn't use buffer
active_tunnel
->
incoming_buffer
=
NULL
;
// wssshc doesn't need incoming buffer
active_tunnel
->
incoming_buffer
=
NULL
;
// wssshc doesn't need incoming buffer
active_tunnel
->
server_version_sent
=
0
;
// Not used for raw TCP
pthread_mutex_unlock
(
&
tunnel_mutex
);
pthread_mutex_unlock
(
&
tunnel_mutex
);
if
(
debug
)
{
if
(
debug
)
{
printf
(
"[DEBUG - Tunnel] wssshc connected to target SSH server
\n
"
);
printf
(
"[DEBUG - Tunnel] wssshc connected to target %s:%d
\n
"
,
ssh_host
,
ssh_port
);
fflush
(
stdout
);
}
// Send client version to target SSH server
const
char
*
client_version
=
"SSH-2.0-OpenSSH_9.9p1 Debian-3
\r\n
"
;
size_t
version_len
=
strlen
(
client_version
);
if
(
send
(
ssh_sock
,
client_version
,
version_len
,
0
)
<
0
)
{
perror
(
"Send client version failed"
);
return
;
}
// Receive server version
char
server_version_buf
[
256
];
int
bytes_read
=
recv
(
ssh_sock
,
server_version_buf
,
sizeof
(
server_version_buf
)
-
1
,
0
);
if
(
bytes_read
<=
0
)
{
perror
(
"Receive server version failed"
);
return
;
}
server_version_buf
[
bytes_read
]
=
'\0'
;
if
(
debug
)
{
printf
(
"[DEBUG - Tunnel] Received server version: %s"
,
server_version_buf
);
fflush
(
stdout
);
fflush
(
stdout
);
}
}
// Send tunnel_ack back to server
// Send tunnel_ack back to server
char
ack_msg
[
256
];
char
ack_msg
[
256
];
snprintf
(
ack_msg
,
sizeof
(
ack_msg
),
"{
\"
type
\"
:
\"
tunnel_ack
\"
,
\"
request_id
\"
:
\"
%s
\"
}"
,
request_id
);
snprintf
(
ack_msg
,
sizeof
(
ack_msg
),
"{
\"
type
\"
:
\"
tunnel_ack
\"
,
\"
request_id
\"
:
\"
%s
\"
}"
,
request_id
);
if
(
debug
)
{
if
(
debug
)
{
printf
(
"[DEBUG - WebSockets] Sending tunnel_ack: %s
\n
"
,
ack_msg
);
printf
(
"[DEBUG - WebSockets] Sending tunnel_ack: %s
\n
"
,
ack_msg
);
fflush
(
stdout
);
fflush
(
stdout
);
}
}
if
(
!
send_websocket_frame
(
ssl
,
ack_msg
))
{
if
(
!
send_websocket_frame
(
ssl
,
ack_msg
))
{
fprintf
(
stderr
,
"Send tunnel_ack failed
\n
"
);
fprintf
(
stderr
,
"Send tunnel_ack failed
\n
"
);
return
;
return
;
}
}
// Send server version as tunnel_response immediately
// Start bidirectional forwarding between WebSocket and target TCP endpoint
// Convert to hex
size_t
hex_size
=
(
size_t
)
bytes_read
*
2
+
1
;
if
(
hex_size
>
256
)
hex_size
=
256
;
char
hex_data
[
256
];
for
(
int
i
=
0
;
i
<
bytes_read
&&
(
size_t
)
i
*
2
<
hex_size
-
1
;
i
++
)
{
sprintf
(
hex_data
+
i
*
2
,
"%02x"
,
(
unsigned
char
)
server_version_buf
[
i
]);
}
hex_data
[
bytes_read
*
2
]
=
'\0'
;
char
response_msg
[
512
];
snprintf
(
response_msg
,
sizeof
(
response_msg
),
"{
\"
type
\"
:
\"
tunnel_response
\"
,
\"
request_id
\"
:
\"
%s
\"
,
\"
data
\"
:
\"
%s
\"
}"
,
request_id
,
hex_data
);
if
(
debug
)
{
printf
(
"[DEBUG - WebSockets] Sending server version immediately: %s
\n
"
,
response_msg
);
fflush
(
stdout
);
}
if
(
!
send_websocket_frame
(
ssl
,
response_msg
))
{
fprintf
(
stderr
,
"Send server version failed
\n
"
);
return
;
}
// Start bidirectional forwarding between WebSocket and SSH server
thread_args_t
*
thread_args
=
malloc
(
sizeof
(
thread_args_t
));
thread_args_t
*
thread_args
=
malloc
(
sizeof
(
thread_args_t
));
if
(
thread_args
)
{
if
(
thread_args
)
{
thread_args
->
ssl
=
ssl
;
thread_args
->
ssl
=
ssl
;
thread_args
->
debug
=
debug
;
thread_args
->
debug
=
debug
;
pthread_t
thread
;
pthread_t
thread
;
pthread_create
(
&
thread
,
NULL
,
forward_ws_to_ssh_server
,
thread_args
);
pthread_create
(
&
thread
,
NULL
,
forward_ws_to_ssh_server
,
thread_args
);
pthread_detach
(
thread
);
pthread_detach
(
thread
);
...
@@ -224,19 +192,19 @@ void cleanup_tunnel(int debug) {
...
@@ -224,19 +192,19 @@ void cleanup_tunnel(int debug) {
pthread_mutex_lock
(
&
tunnel_mutex
);
pthread_mutex_lock
(
&
tunnel_mutex
);
if
(
active_tunnel
)
{
if
(
active_tunnel
)
{
if
(
active_tunnel
->
sock
>=
0
)
{
if
(
active_tunnel
->
sock
>=
0
)
{
// Check if
SSH
connection is still valid before closing
// Check if
TCP
connection is still valid before closing
char
test_buf
[
1
];
char
test_buf
[
1
];
int
result
=
recv
(
active_tunnel
->
sock
,
test_buf
,
1
,
MSG_PEEK
|
MSG_DONTWAIT
);
int
result
=
recv
(
active_tunnel
->
sock
,
test_buf
,
1
,
MSG_PEEK
|
MSG_DONTWAIT
);
if
(
result
==
0
||
(
result
<
0
&&
(
errno
==
ECONNRESET
||
errno
==
EPIPE
)))
{
if
(
result
==
0
||
(
result
<
0
&&
(
errno
==
ECONNRESET
||
errno
==
EPIPE
)))
{
//
SSH
connection is closed or broken, safe to close
//
TCP
connection is closed or broken, safe to close
close
(
active_tunnel
->
sock
);
close
(
active_tunnel
->
sock
);
if
(
debug
)
{
if
(
debug
)
{
printf
(
"[DEBUG] [TCP Tunnel] Closed broken
SSH
connection
\n
"
);
printf
(
"[DEBUG] [TCP Tunnel] Closed broken
TCP
connection
\n
"
);
}
}
}
else
{
}
else
{
//
SSH
connection appears valid, don't close it
//
TCP
connection appears valid, don't close it
if
(
debug
)
{
if
(
debug
)
{
printf
(
"[DEBUG] [TCP Tunnel] Keeping
SSH
connection alive for potential reuse
\n
"
);
printf
(
"[DEBUG] [TCP Tunnel] Keeping
TCP
connection alive for potential reuse
\n
"
);
}
}
// Reset socket to -1 so it will be reconnected if needed
// Reset socket to -1 so it will be reconnected if needed
active_tunnel
->
sock
=
-
1
;
active_tunnel
->
sock
=
-
1
;
...
@@ -393,9 +361,6 @@ void *forward_tcp_to_ws(void *arg) {
...
@@ -393,9 +361,6 @@ void *forward_tcp_to_ws(void *arg) {
fflush
(
stdout
);
fflush
(
stdout
);
}
}
// Check if this is the SSH client version string
int
is_client_version
=
(
bytes_read
>=
8
&&
strncmp
(
buffer
,
"SSH-2.0-"
,
8
)
==
0
);
// Convert to hex with bounds checking
// Convert to hex with bounds checking
size_t
hex_size
=
(
size_t
)
bytes_read
*
2
+
1
;
size_t
hex_size
=
(
size_t
)
bytes_read
*
2
+
1
;
if
(
hex_size
>
BUFFER_SIZE
)
{
if
(
hex_size
>
BUFFER_SIZE
)
{
...
@@ -424,29 +389,6 @@ void *forward_tcp_to_ws(void *arg) {
...
@@ -424,29 +389,6 @@ void *forward_tcp_to_ws(void *arg) {
}
}
break
;
break
;
}
}
// If this was the client SSH version, immediately send the server version to prevent timeout
if
(
is_client_version
)
{
const
char
*
server_version
=
"SSH-2.0-OpenSSH_10.0p2 Debian-8
\r\n
"
;
size_t
version_len
=
strlen
(
server_version
);
if
(
debug
)
{
printf
(
"[DEBUG - TCPConnection] Sending server version immediately after client version
\n
"
);
fflush
(
stdout
);
}
ssize_t
sent
=
send
(
client_sock
,
server_version
,
version_len
,
0
);
if
(
sent
>
0
)
{
if
(
debug
)
{
printf
(
"[DEBUG] Sent %zd bytes of server version
\n
"
,
sent
);
fflush
(
stdout
);
}
// Set flag to skip duplicate server version
pthread_mutex_lock
(
&
tunnel_mutex
);
if
(
active_tunnel
)
{
active_tunnel
->
server_version_sent
=
1
;
}
pthread_mutex_unlock
(
&
tunnel_mutex
);
}
}
}
}
}
}
...
@@ -490,21 +432,21 @@ void *forward_ws_to_ssh_server(void *arg) {
...
@@ -490,21 +432,21 @@ void *forward_ws_to_ssh_server(void *arg) {
pthread_mutex_unlock
(
&
tunnel_mutex
);
pthread_mutex_unlock
(
&
tunnel_mutex
);
break
;
break
;
}
}
int
ssh_sock
=
active_tunnel
->
sock
;
// SSH server
connection
int
target_sock
=
active_tunnel
->
sock
;
// Target TCP
connection
char
request_id
[
37
];
char
request_id
[
37
];
strcpy
(
request_id
,
active_tunnel
->
request_id
);
strcpy
(
request_id
,
active_tunnel
->
request_id
);
pthread_mutex_unlock
(
&
tunnel_mutex
);
pthread_mutex_unlock
(
&
tunnel_mutex
);
// Use select to wait for data on
SSH server
connection
// Use select to wait for data on
target TCP
connection
FD_ZERO
(
&
readfds
);
FD_ZERO
(
&
readfds
);
FD_SET
(
ssh
_sock
,
&
readfds
);
FD_SET
(
target
_sock
,
&
readfds
);
tv
.
tv_sec
=
0
;
// 0 seconds
tv
.
tv_sec
=
0
;
// 0 seconds
tv
.
tv_usec
=
50000
;
// 50ms timeout
tv
.
tv_usec
=
50000
;
// 50ms timeout
int
retval
=
select
(
ssh
_sock
+
1
,
&
readfds
,
NULL
,
NULL
,
&
tv
);
int
retval
=
select
(
target
_sock
+
1
,
&
readfds
,
NULL
,
NULL
,
&
tv
);
if
(
retval
==
-
1
)
{
if
(
retval
==
-
1
)
{
if
(
debug
)
{
if
(
debug
)
{
perror
(
"[DEBUG] select on
SSH server
socket failed"
);
perror
(
"[DEBUG] select on
target
socket failed"
);
fflush
(
stdout
);
fflush
(
stdout
);
}
}
break
;
break
;
...
@@ -513,18 +455,18 @@ void *forward_ws_to_ssh_server(void *arg) {
...
@@ -513,18 +455,18 @@ void *forward_ws_to_ssh_server(void *arg) {
continue
;
continue
;
}
}
if
(
FD_ISSET
(
ssh
_sock
,
&
readfds
))
{
if
(
FD_ISSET
(
target
_sock
,
&
readfds
))
{
bytes_read
=
recv
(
ssh
_sock
,
buffer
,
sizeof
(
buffer
),
0
);
bytes_read
=
recv
(
target
_sock
,
buffer
,
sizeof
(
buffer
),
0
);
if
(
bytes_read
<=
0
)
{
if
(
bytes_read
<=
0
)
{
if
(
debug
)
{
if
(
debug
)
{
printf
(
"[DEBUG - TCPConnection]
SSH server
connection closed or error
\n
"
);
printf
(
"[DEBUG - TCPConnection]
Target
connection closed or error
\n
"
);
fflush
(
stdout
);
fflush
(
stdout
);
}
}
break
;
break
;
}
}
if
(
debug
)
{
if
(
debug
)
{
printf
(
"[DEBUG - TCPConnection] Forwarding %d bytes from
SSH server
to WebSocket
\n
"
,
bytes_read
);
printf
(
"[DEBUG - TCPConnection] Forwarding %d bytes from
target
to WebSocket
\n
"
,
bytes_read
);
fflush
(
stdout
);
fflush
(
stdout
);
}
}
...
@@ -543,7 +485,7 @@ void *forward_ws_to_ssh_server(void *arg) {
...
@@ -543,7 +485,7 @@ void *forward_ws_to_ssh_server(void *arg) {
}
}
hex_data
[
bytes_read
*
2
]
=
'\0'
;
hex_data
[
bytes_read
*
2
]
=
'\0'
;
// Send as tunnel_response (from
SSH server back to wsssh/wsscp
)
// Send as tunnel_response (from
target back to WebSocket
)
char
message
[
BUFFER_SIZE
];
char
message
[
BUFFER_SIZE
];
snprintf
(
message
,
sizeof
(
message
),
snprintf
(
message
,
sizeof
(
message
),
"{
\"
type
\"
:
\"
tunnel_response
\"
,
\"
request_id
\"
:
\"
%s
\"
,
\"
data
\"
:
\"
%s
\"
}"
,
"{
\"
type
\"
:
\"
tunnel_response
\"
,
\"
request_id
\"
:
\"
%s
\"
,
\"
data
\"
:
\"
%s
\"
}"
,
...
@@ -560,7 +502,7 @@ void *forward_ws_to_ssh_server(void *arg) {
...
@@ -560,7 +502,7 @@ void *forward_ws_to_ssh_server(void *arg) {
}
}
if
(
debug
)
{
if
(
debug
)
{
printf
(
"[DEBUG - TCPConnection]
SSH server
to WebSocket forwarding thread exiting
\n
"
);
printf
(
"[DEBUG - TCPConnection]
Target
to WebSocket forwarding thread exiting
\n
"
);
fflush
(
stdout
);
fflush
(
stdout
);
}
}
...
@@ -670,82 +612,72 @@ void handle_tunnel_data(SSL *ssl __attribute__((unused)), const char *request_id
...
@@ -670,82 +612,72 @@ void handle_tunnel_data(SSL *ssl __attribute__((unused)), const char *request_id
pthread_mutex_unlock
(
&
tunnel_mutex
);
pthread_mutex_unlock
(
&
tunnel_mutex
);
}
else
{
}
else
{
// wsssh/wssshc: Send directly to target socket
// wsssh/wssshc: Send directly to target socket
// Skip if server version was already sent early
if
(
debug
)
{
if
(
active_tunnel
->
server_version_sent
&&
strstr
(
data
,
"SSH-2.0-OpenSSH_10.0p2 Debian-8"
))
{
printf
(
"[DEBUG] Attempting to send %zu bytes to socket %d
\n
"
,
data_len
,
target_sock
);
if
(
debug
)
{
fflush
(
stdout
);
printf
(
"[DEBUG] Skipping duplicate server version send
\n
"
);
}
fflush
(
stdout
);
ssize_t
sent
=
send
(
target_sock
,
data
,
data_len
,
0
);
}
if
(
sent
<
0
)
{
}
else
{
if
(
debug
)
{
if
(
debug
)
{
printf
(
"[DEBUG]
Attempting to send %zu bytes to socket %d
\n
"
,
data_len
,
target_sock
);
printf
(
"[DEBUG]
Failed to send %zu bytes to target socket %d: %s (errno=%d)
\n
"
,
printf
(
"[DEBUG - TOREMOVE] Target socket is %d
\n
"
,
target_sock
);
data_len
,
target_sock
,
strerror
(
errno
),
errno
);
fflush
(
stdout
);
fflush
(
stdout
);
}
}
ssize_t
sent
=
send
(
target_sock
,
data
,
data_len
,
0
);
// Check if this is a recoverable error
if
(
sent
<
0
)
{
if
(
errno
==
EPIPE
||
errno
==
ECONNRESET
)
{
if
(
debug
)
{
if
(
debug
)
{
printf
(
"[DEBUG] Failed to send %zu bytes to target socket %d: %s (errno=%d)
\n
"
,
printf
(
"[DEBUG] Target disconnected, marking tunnel inactive
\n
"
);
data_len
,
target_sock
,
strerror
(
errno
),
errno
);
fflush
(
stdout
);
fflush
(
stdout
);
}
}
// Check if this is a recoverable error
// If send fails due to disconnection, mark tunnel as inactive
if
(
errno
==
EPIPE
||
errno
==
ECONNRESET
)
{
pthread_mutex_lock
(
&
tunnel_mutex
);
if
(
debug
)
{
if
(
active_tunnel
)
{
printf
(
"[DEBUG] SSH client disconnected, marking tunnel inactive
\n
"
);
active_tunnel
->
active
=
0
;
fflush
(
stdout
);
active_tunnel
->
broken
=
1
;
}
// Send tunnel_close notification immediately
// If send fails due to disconnection, mark tunnel as inactive
send_tunnel_close
(
active_tunnel
->
ssl
,
active_tunnel
->
request_id
,
debug
);
pthread_mutex_lock
(
&
tunnel_mutex
);
if
(
active_tunnel
)
{
active_tunnel
->
active
=
0
;
active_tunnel
->
broken
=
1
;
// Send tunnel_close notification immediately
send_tunnel_close
(
active_tunnel
->
ssl
,
active_tunnel
->
request_id
,
debug
);
}
pthread_mutex_unlock
(
&
tunnel_mutex
);
}
else
if
(
errno
==
EAGAIN
||
errno
==
EWOULDBLOCK
)
{
if
(
debug
)
{
printf
(
"[DEBUG] Send would block, will retry later
\n
"
);
fflush
(
stdout
);
}
// For non-blocking sockets, this is recoverable
// Don't mark tunnel as inactive
}
else
if
(
errno
==
EBADF
)
{
if
(
debug
)
{
printf
(
"[DEBUG] Bad file descriptor - socket may have been closed by SSH client
\n
"
);
printf
(
"[DEBUG - TOREMOVE] EBADF occurred, marking tunnel inactive
\n
"
);
fflush
(
stdout
);
}
// EBADF indicates the socket is invalid - SSH client likely disconnected
pthread_mutex_lock
(
&
tunnel_mutex
);
if
(
active_tunnel
)
{
active_tunnel
->
active
=
0
;
active_tunnel
->
broken
=
1
;
// Send tunnel_close notification immediately
send_tunnel_close
(
active_tunnel
->
ssl
,
active_tunnel
->
request_id
,
debug
);
}
pthread_mutex_unlock
(
&
tunnel_mutex
);
}
else
{
if
(
debug
)
{
printf
(
"[DEBUG] Unexpected send error, marking tunnel inactive
\n
"
);
fflush
(
stdout
);
}
// For other errors, mark tunnel as inactive
pthread_mutex_lock
(
&
tunnel_mutex
);
if
(
active_tunnel
)
{
active_tunnel
->
active
=
0
;
}
pthread_mutex_unlock
(
&
tunnel_mutex
);
}
}
}
else
if
(
debug
)
{
pthread_mutex_unlock
(
&
tunnel_mutex
);
if
((
size_t
)
sent
!=
data_len
)
{
}
else
if
(
errno
==
EAGAIN
||
errno
==
EWOULDBLOCK
)
{
printf
(
"[DEBUG] Partial send: sent %zd of %zu bytes to socket %d
\n
"
,
sent
,
data_len
,
target_sock
);
if
(
debug
)
{
}
else
{
printf
(
"[DEBUG] Send would block, will retry later
\n
"
);
printf
(
"[DEBUG] Successfully sent %zu bytes to socket %d
\n
"
,
data_len
,
target_sock
);
fflush
(
stdout
);
}
}
fflush
(
stdout
);
// For non-blocking sockets, this is recoverable
// Don't mark tunnel as inactive
}
else
if
(
errno
==
EBADF
)
{
if
(
debug
)
{
printf
(
"[DEBUG] Bad file descriptor - socket may have been closed
\n
"
);
fflush
(
stdout
);
}
// EBADF indicates the socket is invalid - target likely disconnected
pthread_mutex_lock
(
&
tunnel_mutex
);
if
(
active_tunnel
)
{
active_tunnel
->
active
=
0
;
active_tunnel
->
broken
=
1
;
// Send tunnel_close notification immediately
send_tunnel_close
(
active_tunnel
->
ssl
,
active_tunnel
->
request_id
,
debug
);
}
pthread_mutex_unlock
(
&
tunnel_mutex
);
}
else
{
if
(
debug
)
{
printf
(
"[DEBUG] Unexpected send error, marking tunnel inactive
\n
"
);
fflush
(
stdout
);
}
// For other errors, mark tunnel as inactive
pthread_mutex_lock
(
&
tunnel_mutex
);
if
(
active_tunnel
)
{
active_tunnel
->
active
=
0
;
}
pthread_mutex_unlock
(
&
tunnel_mutex
);
}
}
}
else
if
(
debug
)
{
if
((
size_t
)
sent
!=
data_len
)
{
printf
(
"[DEBUG] Partial send: sent %zd of %zu bytes to socket %d
\n
"
,
sent
,
data_len
,
target_sock
);
}
else
{
printf
(
"[DEBUG] Successfully sent %zu bytes to socket %d
\n
"
,
data_len
,
target_sock
);
}
fflush
(
stdout
);
}
}
}
}
free
(
data
);
free
(
data
);
...
...
wssshtools/tunnel.h
View file @
96207bd8
...
@@ -58,7 +58,7 @@ void *forward_tcp_to_ws(void *arg);
...
@@ -58,7 +58,7 @@ void *forward_tcp_to_ws(void *arg);
void
*
forward_ws_to_local
(
void
*
arg
);
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
);
void
handle_tunnel_request
(
SSL
*
ssl
,
const
char
*
request_id
,
int
debug
,
const
char
*
ssh_host
,
int
ssh_port
);
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
);
...
...
wssshtools/wsssh.c
View file @
96207bd8
...
@@ -236,6 +236,7 @@ char **modify_ssh_args(int argc, char *argv[], const char *original_host, int lo
...
@@ -236,6 +236,7 @@ char **modify_ssh_args(int argc, char *argv[], const char *original_host, int lo
int
main
(
int
argc
,
char
*
argv
[])
{
int
main
(
int
argc
,
char
*
argv
[])
{
// Read config
// Read config
char
*
config_domain
=
read_config_value
(
"domain"
);
char
*
config_domain
=
read_config_value
(
"domain"
);
...
...
wssshtools/wssshc.c
View file @
96207bd8
...
@@ -41,8 +41,10 @@ int global_debug = 0;
...
@@ -41,8 +41,10 @@ int global_debug = 0;
typedef
struct
{
typedef
struct
{
char
*
server_ip
;
char
*
wssshd_server
;
int
port
;
int
wssshd_port
;
char
*
ssh_host
;
int
ssh_port
;
char
*
client_id
;
char
*
client_id
;
char
*
password
;
char
*
password
;
int
interval
;
int
interval
;
...
@@ -73,12 +75,18 @@ void load_config_file(const char *config_path, wssshc_config_t *config) {
...
@@ -73,12 +75,18 @@ void load_config_file(const char *config_path, wssshc_config_t *config) {
while
(
end
>
value
&&
*
end
==
' '
)
*
end
--
=
0
;
while
(
end
>
value
&&
*
end
==
' '
)
*
end
--
=
0
;
if
(
strcmp
(
key
,
"password"
)
==
0
&&
!
config
->
password
)
{
if
(
strcmp
(
key
,
"password"
)
==
0
&&
!
config
->
password
)
{
config
->
password
=
strdup
(
value
);
config
->
password
=
strdup
(
value
);
}
else
if
(
strcmp
(
key
,
"server-ip"
)
==
0
&&
!
config
->
server_ip
)
{
}
else
if
(
strcmp
(
key
,
"wssshd-server"
)
==
0
&&
!
config
->
wssshd_server
)
{
config
->
server_ip
=
strdup
(
value
);
config
->
wssshd_server
=
strdup
(
value
);
}
else
if
(
strcmp
(
key
,
"domain"
)
==
0
&&
!
config
->
server_ip
)
{
}
else
if
(
strcmp
(
key
,
"domain"
)
==
0
&&
!
config
->
wssshd_server
)
{
config
->
server_ip
=
strdup
(
value
);
config
->
wssshd_server
=
strdup
(
value
);
}
else
if
(
strcmp
(
key
,
"port"
)
==
0
)
{
}
else
if
(
strcmp
(
key
,
"wssshd-port"
)
==
0
)
{
config
->
port
=
atoi
(
value
);
config
->
wssshd_port
=
atoi
(
value
);
}
else
if
(
strcmp
(
key
,
"port"
)
==
0
&&
config
->
wssshd_port
==
9898
)
{
config
->
wssshd_port
=
atoi
(
value
);
}
else
if
(
strcmp
(
key
,
"ssh-host"
)
==
0
&&
!
config
->
ssh_host
)
{
config
->
ssh_host
=
strdup
(
value
);
}
else
if
(
strcmp
(
key
,
"ssh-port"
)
==
0
)
{
config
->
ssh_port
=
atoi
(
value
);
}
else
if
(
strcmp
(
key
,
"id"
)
==
0
&&
!
config
->
client_id
)
{
}
else
if
(
strcmp
(
key
,
"id"
)
==
0
&&
!
config
->
client_id
)
{
config
->
client_id
=
strdup
(
value
);
config
->
client_id
=
strdup
(
value
);
}
else
if
(
strcmp
(
key
,
"interval"
)
==
0
)
{
}
else
if
(
strcmp
(
key
,
"interval"
)
==
0
)
{
...
@@ -117,8 +125,10 @@ void print_usage(const char *program_name) {
...
@@ -117,8 +125,10 @@ void print_usage(const char *program_name) {
fprintf
(
stderr
,
"Protect the dolls!
\n\n
"
);
fprintf
(
stderr
,
"Protect the dolls!
\n\n
"
);
fprintf
(
stderr
,
"Options:
\n
"
);
fprintf
(
stderr
,
"Options:
\n
"
);
fprintf
(
stderr
,
" --config FILE Configuration file path (overrides default hierarchy)
\n
"
);
fprintf
(
stderr
,
" --config FILE Configuration file path (overrides default hierarchy)
\n
"
);
fprintf
(
stderr
,
" --server-ip IP Server IP address
\n
"
);
fprintf
(
stderr
,
" --wssshd-server HOST WSSSHD server host (default: mbeted.nexlab.net)
\n
"
);
fprintf
(
stderr
,
" --port PORT Server port (default: %d)
\n
"
,
DEFAULT_PORT
);
fprintf
(
stderr
,
" --wssshd-port PORT WSSSHD server port (default: 9898)
\n
"
);
fprintf
(
stderr
,
" --ssh-host HOST SSH host to forward tunnel data to (default: 127.0.0.1)
\n
"
);
fprintf
(
stderr
,
" --ssh-port PORT SSH port to forward tunnel data to (default: 22)
\n
"
);
fprintf
(
stderr
,
" --id ID Client identifier
\n
"
);
fprintf
(
stderr
,
" --id ID Client identifier
\n
"
);
fprintf
(
stderr
,
" --password PASS Registration password
\n
"
);
fprintf
(
stderr
,
" --password PASS Registration password
\n
"
);
fprintf
(
stderr
,
" --interval SEC Reconnection interval (default: 30)
\n
"
);
fprintf
(
stderr
,
" --interval SEC Reconnection interval (default: 30)
\n
"
);
...
@@ -136,8 +146,10 @@ void print_usage(const char *program_name) {
...
@@ -136,8 +146,10 @@ void print_usage(const char *program_name) {
int
parse_args
(
int
argc
,
char
*
argv
[],
wssshc_config_t
*
config
)
{
int
parse_args
(
int
argc
,
char
*
argv
[],
wssshc_config_t
*
config
)
{
static
struct
option
long_options
[]
=
{
static
struct
option
long_options
[]
=
{
{
"config"
,
required_argument
,
0
,
'c'
},
{
"config"
,
required_argument
,
0
,
'c'
},
{
"server-ip"
,
required_argument
,
0
,
's'
},
{
"wssshd-server"
,
required_argument
,
0
,
's'
},
{
"port"
,
required_argument
,
0
,
'p'
},
{
"wssshd-port"
,
required_argument
,
0
,
'p'
},
{
"ssh-host"
,
required_argument
,
0
,
'H'
},
{
"ssh-port"
,
required_argument
,
0
,
'P'
},
{
"id"
,
required_argument
,
0
,
'i'
},
{
"id"
,
required_argument
,
0
,
'i'
},
{
"password"
,
required_argument
,
0
,
'w'
},
{
"password"
,
required_argument
,
0
,
'w'
},
{
"interval"
,
required_argument
,
0
,
't'
},
{
"interval"
,
required_argument
,
0
,
't'
},
...
@@ -149,17 +161,24 @@ int parse_args(int argc, char *argv[], wssshc_config_t *config) {
...
@@ -149,17 +161,24 @@ int parse_args(int argc, char *argv[], wssshc_config_t *config) {
int
opt
;
int
opt
;
char
*
custom_config
=
NULL
;
char
*
custom_config
=
NULL
;
while
((
opt
=
getopt_long
(
argc
,
argv
,
"c:s:p:i:w:t:dh"
,
long_options
,
NULL
))
!=
-
1
)
{
while
((
opt
=
getopt_long
(
argc
,
argv
,
"c:s:p:
H:P:
i:w:t:dh"
,
long_options
,
NULL
))
!=
-
1
)
{
switch
(
opt
)
{
switch
(
opt
)
{
case
'c'
:
case
'c'
:
custom_config
=
optarg
;
custom_config
=
optarg
;
break
;
break
;
case
's'
:
case
's'
:
if
(
config
->
server_ip
)
free
(
config
->
server_ip
);
if
(
config
->
wssshd_server
)
free
(
config
->
wssshd_server
);
config
->
server_ip
=
strdup
(
optarg
);
config
->
wssshd_server
=
strdup
(
optarg
);
break
;
break
;
case
'p'
:
case
'p'
:
config
->
port
=
atoi
(
optarg
);
config
->
wssshd_port
=
atoi
(
optarg
);
break
;
case
'H'
:
if
(
config
->
ssh_host
)
free
(
config
->
ssh_host
);
config
->
ssh_host
=
strdup
(
optarg
);
break
;
case
'P'
:
config
->
ssh_port
=
atoi
(
optarg
);
break
;
break
;
case
'i'
:
case
'i'
:
if
(
config
->
client_id
)
free
(
config
->
client_id
);
if
(
config
->
client_id
)
free
(
config
->
client_id
);
...
@@ -215,7 +234,7 @@ int connect_to_server(const wssshc_config_t *config) {
...
@@ -215,7 +234,7 @@ int connect_to_server(const wssshc_config_t *config) {
cleanup_tunnel
(
config
->
debug
);
cleanup_tunnel
(
config
->
debug
);
// Resolve hostname
// Resolve hostname
if
((
he
=
gethostbyname
(
config
->
server_ip
))
==
NULL
)
{
if
((
he
=
gethostbyname
(
config
->
wssshd_server
))
==
NULL
)
{
herror
(
"gethostbyname"
);
herror
(
"gethostbyname"
);
return
1
;
return
1
;
}
}
...
@@ -228,7 +247,7 @@ int connect_to_server(const wssshc_config_t *config) {
...
@@ -228,7 +247,7 @@ int connect_to_server(const wssshc_config_t *config) {
memset
(
&
server_addr
,
0
,
sizeof
(
server_addr
));
memset
(
&
server_addr
,
0
,
sizeof
(
server_addr
));
server_addr
.
sin_family
=
AF_INET
;
server_addr
.
sin_family
=
AF_INET
;
server_addr
.
sin_port
=
htons
(
config
->
port
);
server_addr
.
sin_port
=
htons
(
config
->
wssshd_
port
);
server_addr
.
sin_addr
=
*
((
struct
in_addr
*
)
he
->
h_addr
);
server_addr
.
sin_addr
=
*
((
struct
in_addr
*
)
he
->
h_addr
);
// Connect to server
// Connect to server
...
@@ -257,7 +276,7 @@ int connect_to_server(const wssshc_config_t *config) {
...
@@ -257,7 +276,7 @@ int connect_to_server(const wssshc_config_t *config) {
}
}
// Perform WebSocket handshake
// Perform WebSocket handshake
if
(
!
websocket_handshake
(
ssl
,
config
->
server_ip
,
config
->
port
,
"/"
))
{
if
(
!
websocket_handshake
(
ssl
,
config
->
wssshd_server
,
config
->
wssshd_
port
,
"/"
))
{
SSL_free
(
ssl
);
SSL_free
(
ssl
);
SSL_CTX_free
(
ssl_ctx
);
SSL_CTX_free
(
ssl_ctx
);
close
(
sock
);
close
(
sock
);
...
@@ -456,7 +475,7 @@ int connect_to_server(const wssshc_config_t *config) {
...
@@ -456,7 +475,7 @@ int connect_to_server(const wssshc_config_t *config) {
printf
(
"[DEBUG - WebSockets] Received tunnel_request for ID: %s
\n
"
,
id_start
);
printf
(
"[DEBUG - WebSockets] Received tunnel_request for ID: %s
\n
"
,
id_start
);
fflush
(
stdout
);
fflush
(
stdout
);
}
}
handle_tunnel_request
(
ssl
,
id_start
,
config
->
debug
);
handle_tunnel_request
(
ssl
,
id_start
,
config
->
debug
,
config
->
ssh_host
,
config
->
ssh_port
);
}
}
}
}
}
}
...
@@ -648,8 +667,10 @@ int connect_to_server(const wssshc_config_t *config) {
...
@@ -648,8 +667,10 @@ int connect_to_server(const wssshc_config_t *config) {
int
main
(
int
argc
,
char
*
argv
[])
{
int
main
(
int
argc
,
char
*
argv
[])
{
wssshc_config_t
config
=
{
wssshc_config_t
config
=
{
.
server_ip
=
NULL
,
.
wssshd_server
=
NULL
,
.
port
=
DEFAULT_PORT
,
.
wssshd_port
=
9898
,
.
ssh_host
=
NULL
,
.
ssh_port
=
22
,
.
client_id
=
NULL
,
.
client_id
=
NULL
,
.
password
=
NULL
,
.
password
=
NULL
,
.
interval
=
30
,
.
interval
=
30
,
...
@@ -667,11 +688,20 @@ int main(int argc, char *argv[]) {
...
@@ -667,11 +688,20 @@ int main(int argc, char *argv[]) {
return
1
;
return
1
;
}
}
// Set defaults for optional fields
if
(
!
config
.
wssshd_server
)
{
config
.
wssshd_server
=
strdup
(
"mbeted.nexlab.net"
);
}
if
(
!
config
.
ssh_host
)
{
config
.
ssh_host
=
strdup
(
"127.0.0.1"
);
}
// Validate required arguments
// Validate required arguments
if
(
!
config
.
server_ip
||
!
config
.
client_id
||
!
config
.
password
)
{
if
(
!
config
.
client_id
||
!
config
.
password
)
{
fprintf
(
stderr
,
"Error: --
server-ip, --id,
and --password are required
\n
"
);
fprintf
(
stderr
,
"Error: --
id
and --password are required
\n
"
);
print_usage
(
argv
[
0
]);
print_usage
(
argv
[
0
]);
if
(
config
.
server_ip
)
free
(
config
.
server_ip
);
if
(
config
.
wssshd_server
)
free
(
config
.
wssshd_server
);
if
(
config
.
ssh_host
)
free
(
config
.
ssh_host
);
if
(
config
.
client_id
)
free
(
config
.
client_id
);
if
(
config
.
client_id
)
free
(
config
.
client_id
);
if
(
config
.
password
)
free
(
config
.
password
);
if
(
config
.
password
)
free
(
config
.
password
);
pthread_mutex_destroy
(
&
tunnel_mutex
);
pthread_mutex_destroy
(
&
tunnel_mutex
);
...
@@ -679,7 +709,19 @@ int main(int argc, char *argv[]) {
...
@@ -679,7 +709,19 @@ int main(int argc, char *argv[]) {
}
}
global_debug
=
config
.
debug
;
global_debug
=
config
.
debug
;
// Print configured options
printf
(
"WebSocket SSH Client starting...
\n
"
);
printf
(
"WebSocket SSH Client starting...
\n
"
);
printf
(
"Configuration:
\n
"
);
printf
(
" WSSSHD Server: %s
\n
"
,
config
.
wssshd_server
?
config
.
wssshd_server
:
"(null)"
);
printf
(
" WSSSHD Port: %d
\n
"
,
config
.
wssshd_port
);
printf
(
" SSH Host: %s
\n
"
,
config
.
ssh_host
?
config
.
ssh_host
:
"(null)"
);
printf
(
" SSH Port: %d
\n
"
,
config
.
ssh_port
);
printf
(
" Client ID: %s
\n
"
,
config
.
client_id
?
config
.
client_id
:
"(null)"
);
printf
(
" Password: %s
\n
"
,
config
.
password
?
"***"
:
"(null)"
);
printf
(
" Reconnection Interval: %d seconds
\n
"
,
config
.
interval
);
printf
(
" Debug Mode: %s
\n
"
,
config
.
debug
?
"enabled"
:
"disabled"
);
printf
(
"
\n
"
);
while
(
1
)
{
while
(
1
)
{
int
result
=
connect_to_server
(
&
config
);
int
result
=
connect_to_server
(
&
config
);
...
@@ -699,7 +741,8 @@ int main(int argc, char *argv[]) {
...
@@ -699,7 +741,8 @@ int main(int argc, char *argv[]) {
}
}
// Cleanup
// Cleanup
free
(
config
.
server_ip
);
free
(
config
.
wssshd_server
);
free
(
config
.
ssh_host
);
free
(
config
.
client_id
);
free
(
config
.
client_id
);
free
(
config
.
password
);
free
(
config
.
password
);
pthread_mutex_destroy
(
&
tunnel_mutex
);
pthread_mutex_destroy
(
&
tunnel_mutex
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment