mirror of
https://github.com/rapid7/metasploit-payloads
synced 2025-01-14 17:37:27 +01:00
Commit the new TCP server channel support on the meterpreter end as well as some fixes to TCP client channels.
git-svn-id: file:///home/svn/framework3/trunk@8383 4d416f70-5f16-0410-b530-b9f4589650da
This commit is contained in:
parent
75d5d3c136
commit
85ed7baa43
@ -226,7 +226,7 @@ DWORD THREADCALL scheduler_waitable_thread( THREAD * thread )
|
||||
terminate = TRUE;
|
||||
break;
|
||||
case 1:
|
||||
dprintf( "[SCHEDULER] scheduler_waitable_thread( 0x%08X ), signaled on waitable...", thread );
|
||||
//dprintf( "[SCHEDULER] scheduler_waitable_thread( 0x%08X ), signaled on waitable...", thread );
|
||||
entry->routine( entry->remote, entry->context );
|
||||
break;
|
||||
default:
|
||||
|
@ -32,7 +32,7 @@
|
||||
#include "list.h"
|
||||
|
||||
|
||||
// #define DEBUGTRACE
|
||||
//#define DEBUGTRACE
|
||||
|
||||
#ifdef DEBUGTRACE
|
||||
#define dprintf(...) real_dprintf(__VA_ARGS__)
|
||||
|
@ -65,6 +65,7 @@ typedef enum
|
||||
MAKE_TLV(CHANNEL_DATA, TLV_META_TYPE_RAW, 52),
|
||||
MAKE_TLV(CHANNEL_DATA_GROUP, TLV_META_TYPE_GROUP, 53),
|
||||
MAKE_TLV(CHANNEL_CLASS, TLV_META_TYPE_UINT, 54),
|
||||
MAKE_TLV(CHANNEL_PARENTID, TLV_META_TYPE_UINT, 55),
|
||||
|
||||
// Channel extended types
|
||||
MAKE_TLV(SEEK_WHENCE, TLV_META_TYPE_UINT, 70),
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "precomp.h"
|
||||
|
||||
extern DWORD request_net_tcp_client_channel_open(Remote *remote, Packet *packet);
|
||||
extern DWORD request_net_tcp_server_channel_open(Remote *remote, Packet *packet);
|
||||
|
||||
// Channel type dispatch table
|
||||
struct
|
||||
@ -11,6 +12,7 @@ struct
|
||||
{
|
||||
{ "stdapi_fs_file", request_fs_file_channel_open },
|
||||
{ "stdapi_net_tcp_client", request_net_tcp_client_channel_open },
|
||||
{ "stdapi_net_tcp_server", request_net_tcp_server_channel_open },
|
||||
{ NULL, NULL },
|
||||
};
|
||||
|
||||
|
@ -10,7 +10,6 @@ typedef struct _SocketContext
|
||||
Channel *channel;
|
||||
#ifdef _WIN32
|
||||
WSAEVENT notify;
|
||||
HANDLE mutex;
|
||||
#else
|
||||
int notify;
|
||||
#endif
|
||||
@ -18,6 +17,7 @@ typedef struct _SocketContext
|
||||
} SocketContext;
|
||||
|
||||
typedef SocketContext TcpClientContext;
|
||||
typedef SocketContext TcpServerContext;
|
||||
typedef SocketContext UdpClientContext;
|
||||
|
||||
#define free_tcp_client_context(x) free_socket_context((SocketContext *)x)
|
||||
@ -27,6 +27,7 @@ typedef SocketContext UdpClientContext;
|
||||
* Request handlers
|
||||
*/
|
||||
DWORD request_net_tcp_client_channel_open(Remote *remote, Packet *packet);
|
||||
DWORD request_net_tcp_server_channel_open(Remote *remote, Packet *packet);
|
||||
|
||||
// Config
|
||||
DWORD request_net_config_get_routes(Remote *remote, Packet *packet);
|
||||
@ -41,10 +42,8 @@ DWORD request_net_socket_tcp_shutdown(Remote *remote, Packet *packet);
|
||||
/*
|
||||
* Channel creation
|
||||
*/
|
||||
DWORD create_tcp_client_channel(Remote *remote, LPCSTR host,
|
||||
USHORT port, Channel **outChannel);
|
||||
DWORD create_tcp_client_channel(Remote *remote, LPCSTR host,USHORT port, Channel **outChannel);
|
||||
|
||||
VOID free_socket_context(SocketContext *ctx);
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -1,42 +1,88 @@
|
||||
#include "precomp.h"
|
||||
#include "tcp.h"
|
||||
|
||||
/*********************************
|
||||
* TCP Client Channel Operations *
|
||||
*********************************/
|
||||
|
||||
/*
|
||||
* Writes data from the remote half of the channel to the established
|
||||
* connection.
|
||||
* Writes data from the remote half of the channel to the established connection.
|
||||
*/
|
||||
static DWORD tcp_channel_client_write(Channel *channel, Packet *request,
|
||||
LPVOID context, LPVOID buffer, DWORD bufferSize,
|
||||
LPDWORD bytesWritten)
|
||||
DWORD tcp_channel_client_write( Channel *channel, Packet *request, LPVOID context, LPVOID buffer, DWORD bufferSize, LPDWORD bytesWritten)
|
||||
{
|
||||
TcpClientContext *ctx = (TcpClientContext *)context;
|
||||
DWORD result= ERROR_SUCCESS;
|
||||
LONG written = 0;
|
||||
DWORD dwResult = ERROR_SUCCESS;
|
||||
TcpClientContext * ctx = NULL;
|
||||
LONG written = 0;
|
||||
|
||||
dprintf( "[TCP] tcp_channel_client_write. channel=0x%08X, buffsize=%d", channel, bufferSize );
|
||||
|
||||
// Write a chunk
|
||||
if ((written = send(ctx->fd, buffer, bufferSize, 0)) <= 0)
|
||||
do
|
||||
{
|
||||
written = 0;
|
||||
result = GetLastError();
|
||||
}
|
||||
dprintf( "[TCP] tcp_channel_client_write. channel=0x%08X, buffsize=%d", channel, bufferSize );
|
||||
|
||||
// Set bytesWritten
|
||||
if (bytesWritten)
|
||||
*bytesWritten = written;
|
||||
ctx = (TcpClientContext *)context;
|
||||
if( !ctx )
|
||||
BREAK_WITH_ERROR( "[TCP] tcp_channel_client_write. ctx == NULL", ERROR_INVALID_HANDLE );
|
||||
|
||||
return result;
|
||||
written = send( ctx->fd, buffer, bufferSize, 0 );
|
||||
|
||||
if( written == SOCKET_ERROR )
|
||||
{
|
||||
dwResult = WSAGetLastError();
|
||||
|
||||
if( dwResult == WSAEWOULDBLOCK )
|
||||
{
|
||||
struct timeval tv = {0};
|
||||
fd_set set = {0};
|
||||
DWORD res = 0;
|
||||
|
||||
dprintf( "[TCP] tcp_channel_client_write. send returned WSAEWOULDBLOCK, waiting until we can send again..." );
|
||||
|
||||
while( TRUE )
|
||||
{
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 1000;
|
||||
|
||||
FD_ZERO( &set );
|
||||
FD_SET( ctx->fd, &set );
|
||||
|
||||
res = select( 0, NULL, &set, NULL, &tv );
|
||||
if( res > 0 )
|
||||
{
|
||||
dwResult = ERROR_SUCCESS;
|
||||
break;
|
||||
}
|
||||
else if( res == SOCKET_ERROR )
|
||||
{
|
||||
dwResult = WSAGetLastError();
|
||||
break;
|
||||
}
|
||||
|
||||
Sleep( 100 );
|
||||
}
|
||||
|
||||
if( dwResult == ERROR_SUCCESS )
|
||||
continue;
|
||||
else
|
||||
dprintf( "[TCP] tcp_channel_client_write. select == SOCKET_ERROR. dwResult=%d", dwResult );
|
||||
}
|
||||
|
||||
written = 0;
|
||||
dprintf( "[TCP] tcp_channel_client_write. written == SOCKET_ERROR. dwResult=%d", dwResult );
|
||||
}
|
||||
|
||||
if( bytesWritten )
|
||||
*bytesWritten = written;
|
||||
|
||||
} while( 0 );
|
||||
|
||||
dprintf( "[TCP] tcp_channel_client_write. finished. dwResult=%d, written=%d", dwResult, written );
|
||||
|
||||
return dwResult;
|
||||
}
|
||||
|
||||
/*
|
||||
* Closes the established connection and cleans up stale state
|
||||
*/
|
||||
static DWORD tcp_channel_client_close(Channel *channel, Packet *request,
|
||||
LPVOID context)
|
||||
DWORD tcp_channel_client_close(Channel *channel, Packet *request, LPVOID context)
|
||||
{
|
||||
TcpClientContext *ctx = (TcpClientContext *)context;
|
||||
|
||||
@ -59,22 +105,14 @@ static DWORD tcp_channel_client_close(Channel *channel, Packet *request,
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback for when there is data available on the local side of the TCP
|
||||
* client connection
|
||||
* Callback for when there is data available on the local side of the TCP client connection
|
||||
*/
|
||||
static DWORD tcp_channel_client_local_notify(Remote *remote,
|
||||
TcpClientContext *ctx)
|
||||
DWORD tcp_channel_client_local_notify( Remote * remote, TcpClientContext * ctx )
|
||||
{
|
||||
struct timeval tv;
|
||||
fd_set set;
|
||||
UCHAR buf[16384];
|
||||
LONG bytesRead;
|
||||
|
||||
// Reset the notification event
|
||||
ResetEvent(ctx->notify);
|
||||
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
struct timeval tv = {0};
|
||||
fd_set set = {0};
|
||||
UCHAR buf[16384] = {0};
|
||||
LONG dwBytesRead = 0;
|
||||
|
||||
// We select in a loop with a zero second timeout because it's possible
|
||||
// that we could get a recv notification and a close notification at once,
|
||||
@ -82,42 +120,73 @@ static DWORD tcp_channel_client_local_notify(Remote *remote,
|
||||
// event handle wont get re set to notify us.
|
||||
do
|
||||
{
|
||||
FD_ZERO(&set);
|
||||
FD_SET(ctx->fd, &set);
|
||||
// Reset the notification event
|
||||
ResetEvent( ctx->notify );
|
||||
|
||||
FD_ZERO( &set );
|
||||
FD_SET( ctx->fd, &set );
|
||||
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
// Read data from the client connection
|
||||
bytesRead = recv(ctx->fd, buf, sizeof(buf), 0);
|
||||
dwBytesRead = recv( ctx->fd, buf, sizeof(buf), 0 );
|
||||
|
||||
// Not sure why we get these with pending data
|
||||
if(bytesRead == SOCKET_ERROR) {
|
||||
printf( "[TCP] tcp_channel_client_local_notify. [error] channel=0x%08X read=0x%.8x (ignored)", ctx->channel, bytesRead );
|
||||
continue;
|
||||
if( dwBytesRead == SOCKET_ERROR )
|
||||
{
|
||||
DWORD dwError = WSAGetLastError();
|
||||
|
||||
// WSAECONNRESET: The connection was forcibly closed by the remote host.
|
||||
// WSAECONNABORTED: The connection was terminated due to a time-out or other failure.
|
||||
if( dwError == WSAECONNRESET || dwError == WSAECONNABORTED )
|
||||
{
|
||||
dprintf( "[TCP] tcp_channel_client_local_notify. [error] closing down channel gracefully. WSAGetLastError=%d", dwError );
|
||||
// By setting bytesRead to zero, we can ensure we close down the channel gracefully...
|
||||
dwBytesRead = 0;
|
||||
}
|
||||
else if( dwError == WSAEWOULDBLOCK )
|
||||
{
|
||||
dprintf( "[TCP] tcp_channel_client_local_notify. channel=0x%08X. recv generated a WSAEWOULDBLOCK", ctx->channel );
|
||||
// break and let the scheduler notify us again if needed.
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
dprintf( "[TCP] tcp_channel_client_local_notify. [error] channel=0x%08X read=0x%.8x (ignored). WSAGetLastError=%d", ctx->channel, dwBytesRead, dwError );
|
||||
// we loop again because bytesRead is -1.
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( ctx->channel )
|
||||
{
|
||||
dprintf( "[TCP] tcp_channel_client_local_notify. [data] channel=0x%08X read=%d", ctx->channel, dwBytesRead );
|
||||
channel_write( ctx->channel, ctx->remote, NULL, 0, buf, dwBytesRead, 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
dprintf( "[TCP] tcp_channel_client_local_notify. [data] channel=<invalid> read=0x%.8x", dwBytesRead );
|
||||
}
|
||||
}
|
||||
|
||||
if (bytesRead == 0) {
|
||||
dprintf( "[TCP] tcp_channel_client_local_notify. [closed] channel=0x%08X read=0x%.8x", ctx->channel, bytesRead );
|
||||
if( dwBytesRead == 0 )
|
||||
{
|
||||
dprintf( "[TCP] tcp_channel_client_local_notify. [closed] channel=0x%08X read=0x%.8x", ctx->channel, dwBytesRead );
|
||||
|
||||
// Set the native channel operations context to NULL
|
||||
channel_set_native_io_context(ctx->channel, NULL);
|
||||
channel_set_native_io_context( ctx->channel, NULL );
|
||||
|
||||
// Sleep for a quarter second
|
||||
Sleep(250);
|
||||
Sleep( 250 );
|
||||
|
||||
// Free the context
|
||||
free_tcp_client_context(ctx);
|
||||
free_tcp_client_context( ctx );
|
||||
|
||||
// Stop processing
|
||||
break;
|
||||
}
|
||||
|
||||
if (ctx->channel) {
|
||||
// dprintf( "[TCP] tcp_channel_client_local_notify. [data] channel=0x%08X read=0x%.8x", ctx->channel, bytesRead );
|
||||
channel_write(ctx->channel, ctx->remote, NULL, 0, buf, bytesRead, 0);
|
||||
} else {
|
||||
dprintf( "[TCP] tcp_channel_client_local_notify. [data] channel=<invalid> read=0x%.8x", bytesRead );
|
||||
}
|
||||
|
||||
} while (select(0, &set, NULL, NULL, &tv) > 0);
|
||||
|
||||
} while( select( 1, &set, NULL, NULL, &tv ) > 0 );
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
@ -149,13 +218,11 @@ DWORD request_net_tcp_client_channel_open(Remote *remote, Packet *packet)
|
||||
port = packet_get_tlv_value_uint(packet, TLV_TYPE_PEER_PORT);
|
||||
|
||||
// Open the TCP channel
|
||||
if ((result = create_tcp_client_channel(remote, host,
|
||||
(USHORT)(port & 0xffff), &channel)) != ERROR_SUCCESS)
|
||||
if ((result = create_tcp_client_channel(remote, host, (USHORT)(port & 0xffff), &channel)) != ERROR_SUCCESS)
|
||||
break;
|
||||
|
||||
// Set the channel's identifier on the response
|
||||
packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID,
|
||||
channel_get_id(channel));
|
||||
packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, channel_get_id(channel));
|
||||
|
||||
} while (0);
|
||||
|
||||
@ -170,8 +237,7 @@ DWORD request_net_tcp_client_channel_open(Remote *remote, Packet *packet)
|
||||
* represent it.
|
||||
*
|
||||
*/
|
||||
DWORD create_tcp_client_channel(Remote *remote, LPCSTR remoteHost,
|
||||
USHORT remotePort, Channel **outChannel)
|
||||
DWORD create_tcp_client_channel(Remote *remote, LPCSTR remoteHost, USHORT remotePort, Channel **outChannel)
|
||||
{
|
||||
StreamChannelOps chops;
|
||||
TcpClientContext *ctx = NULL;
|
||||
@ -188,8 +254,7 @@ DWORD create_tcp_client_channel(Remote *remote, LPCSTR remoteHost,
|
||||
do
|
||||
{
|
||||
// Allocate a client socket
|
||||
if ((clientFd = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, 0))
|
||||
== INVALID_SOCKET)
|
||||
if ((clientFd = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, 0)) == INVALID_SOCKET)
|
||||
{
|
||||
clientFd = 0;
|
||||
result = GetLastError();
|
||||
@ -225,8 +290,7 @@ DWORD create_tcp_client_channel(Remote *remote, LPCSTR remoteHost,
|
||||
|
||||
dprintf( "[TCP] create_tcp_client_channel. host=%s, port=%d connected!", remoteHost, remotePort );
|
||||
// Allocate the client context for tracking the connection
|
||||
if (!(ctx = (TcpClientContext *)malloc(
|
||||
sizeof(TcpClientContext))))
|
||||
if (!(ctx = (TcpClientContext *)malloc( sizeof(TcpClientContext))))
|
||||
{
|
||||
result = ERROR_NOT_ENOUGH_MEMORY;
|
||||
break;
|
||||
@ -237,7 +301,6 @@ DWORD create_tcp_client_channel(Remote *remote, LPCSTR remoteHost,
|
||||
|
||||
ctx->remote = remote;
|
||||
ctx->fd = clientFd;
|
||||
ctx->mutex = CreateMutex(NULL, FALSE, NULL);
|
||||
|
||||
// Initialize the channel operations structure
|
||||
memset(&chops, 0, sizeof(chops));
|
||||
@ -248,8 +311,7 @@ DWORD create_tcp_client_channel(Remote *remote, LPCSTR remoteHost,
|
||||
|
||||
dprintf( "[TCP] create_tcp_client_channel. host=%s, port=%d creating the channel", remoteHost, remotePort );
|
||||
// Allocate an uninitialized channel for associated with this connection
|
||||
if (!(channel = channel_create_stream(0, 0,
|
||||
&chops)))
|
||||
if (!(channel = channel_create_stream(0, 0,&chops)))
|
||||
{
|
||||
result = ERROR_NOT_ENOUGH_MEMORY;
|
||||
break;
|
||||
@ -266,8 +328,7 @@ DWORD create_tcp_client_channel(Remote *remote, LPCSTR remoteHost,
|
||||
WSAEventSelect(ctx->fd, ctx->notify, FD_READ|FD_CLOSE);
|
||||
dprintf( "[TCP] create_tcp_client_channel. host=%s, port=%d created the notify %.8x", remoteHost, remotePort, ctx->notify );
|
||||
|
||||
scheduler_insert_waitable( ctx->notify, ctx,
|
||||
(WaitableNotifyRoutine)tcp_channel_client_local_notify);
|
||||
scheduler_insert_waitable( ctx->notify, ctx, (WaitableNotifyRoutine)tcp_channel_client_local_notify);
|
||||
}
|
||||
|
||||
} while (0);
|
||||
@ -328,31 +389,47 @@ VOID free_socket_context(SocketContext *ctx)
|
||||
*/
|
||||
DWORD request_net_socket_tcp_shutdown(Remote *remote, Packet *packet)
|
||||
{
|
||||
Packet *response = packet_create_response(packet);
|
||||
SocketContext *ctx = NULL;
|
||||
Channel *channel = NULL;
|
||||
DWORD result = ERROR_SUCCESS;
|
||||
DWORD how;
|
||||
dprintf( "[TCP] entering request_net_socket_tcp_shutdown" );
|
||||
DWORD dwResult = ERROR_SUCCESS;
|
||||
Packet * response = NULL;
|
||||
SocketContext * ctx = NULL;
|
||||
Channel * channel = NULL;
|
||||
DWORD cid = 0;
|
||||
DWORD how = 0;
|
||||
|
||||
// Find the associated channel
|
||||
channel = channel_find_by_id(packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID));
|
||||
|
||||
how = packet_get_tlv_value_uint(packet, TLV_TYPE_SHUTDOWN_HOW);
|
||||
|
||||
dprintf( "[TCP] request_net_socket_tcp_shutdown. channel=0x%08X", channel );
|
||||
|
||||
// If the channel and channel context are valid...
|
||||
if ((channel) &&
|
||||
((ctx = channel_get_native_io_context(channel))))
|
||||
do
|
||||
{
|
||||
if (shutdown(ctx->fd, how) == SOCKET_ERROR)
|
||||
result = WSAGetLastError();
|
||||
else
|
||||
free_socket_context( ctx );
|
||||
}
|
||||
dprintf( "[TCP] entering request_net_socket_tcp_shutdown" );
|
||||
response = packet_create_response( packet );
|
||||
if( !response )
|
||||
BREAK_WITH_ERROR( "[TCP] request_net_socket_tcp_shutdown. response == NULL", ERROR_NOT_ENOUGH_MEMORY );
|
||||
|
||||
cid = packet_get_tlv_value_uint( packet, TLV_TYPE_CHANNEL_ID );
|
||||
how = packet_get_tlv_value_uint( packet, TLV_TYPE_SHUTDOWN_HOW );
|
||||
|
||||
channel = channel_find_by_id( cid );
|
||||
if( !response )
|
||||
BREAK_WITH_ERROR( "[TCP] request_net_socket_tcp_shutdown. channel == NULL", ERROR_INVALID_HANDLE );
|
||||
|
||||
dprintf( "[TCP] request_net_socket_tcp_shutdown. channel=0x%08X, cid=%d", channel, cid );
|
||||
|
||||
ctx = channel_get_native_io_context( channel );
|
||||
if( !ctx )
|
||||
BREAK_WITH_ERROR( "[TCP] request_net_socket_tcp_shutdown. ctx == NULL", ERROR_INVALID_HANDLE );
|
||||
|
||||
if( shutdown( ctx->fd, how ) == SOCKET_ERROR )
|
||||
BREAK_ON_WSAERROR( "[TCP] request_net_socket_tcp_shutdown. shutdown failed" );
|
||||
|
||||
// sf: we dont seem to need to call this here, as the channels tcp_channel_client_local_notify() will
|
||||
// catch the socket closure and call free_socket_context() for us, due the the FD_READ|FD_CLOSE flags
|
||||
// being passed to WSAEventSelect for the notify event in create_tcp_client_channel().
|
||||
// This avoids a double call (from two different threads) and subsequent access violation in some edge cases.
|
||||
//free_socket_context( ctx );
|
||||
|
||||
} while( 0 );
|
||||
|
||||
packet_transmit_response( dwResult, remote, response );
|
||||
|
||||
packet_transmit_response(result, remote, response);
|
||||
dprintf( "[TCP] leaving request_net_socket_tcp_shutdown" );
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
@ -0,0 +1,8 @@
|
||||
#ifndef _METERPRETER_SOURCE_EXTENSION_STDAPI_STDAPI_SERVER_NET_TCP_H
|
||||
#define _METERPRETER_SOURCE_EXTENSION_STDAPI_STDAPI_SERVER_NET_TCP_H
|
||||
|
||||
DWORD tcp_channel_client_write( Channel *channel, Packet *request, LPVOID context, LPVOID buffer, DWORD bufferSize, LPDWORD bytesWritten);
|
||||
DWORD tcp_channel_client_close(Channel *channel, Packet *request, LPVOID context);
|
||||
DWORD tcp_channel_client_local_notify(Remote *remote, TcpClientContext *ctx);
|
||||
|
||||
#endif
|
@ -0,0 +1,298 @@
|
||||
#include "precomp.h"
|
||||
#include "tcp.h"
|
||||
|
||||
/*
|
||||
* Deallocates and cleans up the attributes of a tcp server socket context
|
||||
*/
|
||||
VOID free_tcp_server_context( TcpServerContext * ctx )
|
||||
{
|
||||
do
|
||||
{
|
||||
if( !ctx )
|
||||
break;
|
||||
|
||||
dprintf( "[TCP-SERVER] free_tcp_server_context. ctx=0x%08X", ctx );
|
||||
|
||||
if( ctx->fd )
|
||||
{
|
||||
closesocket( ctx->fd );
|
||||
ctx->fd = 0;
|
||||
}
|
||||
|
||||
if( ctx->channel )
|
||||
{
|
||||
channel_close( ctx->channel, ctx->remote, NULL, 0, NULL );
|
||||
ctx->channel = NULL;
|
||||
}
|
||||
|
||||
if( ctx->notify )
|
||||
{
|
||||
scheduler_remove_waitable( ctx->notify );
|
||||
ctx->notify = NULL;
|
||||
}
|
||||
|
||||
free( ctx );
|
||||
|
||||
} while( 0 );
|
||||
}
|
||||
|
||||
/*
|
||||
* Closes the server socket and brings down the client connections.
|
||||
*/
|
||||
DWORD tcp_channel_server_close( Channel * channel, Packet * request, LPVOID context )
|
||||
{
|
||||
TcpServerContext * ctx = (TcpServerContext *)context;
|
||||
|
||||
do
|
||||
{
|
||||
dprintf( "[TCP-SERVER] tcp_channel_server_close. channel=0x%08X, ctx=0x%08X", channel, ctx );
|
||||
|
||||
if( !ctx )
|
||||
break;
|
||||
|
||||
// Set the context channel to NULL so we don't try to close the
|
||||
// channel (since it's already being closed)
|
||||
ctx->channel = NULL;
|
||||
|
||||
// Free the context
|
||||
free_tcp_server_context( ctx );
|
||||
|
||||
// Set the native channel operations context to NULL
|
||||
channel_set_native_io_context( channel, NULL );
|
||||
|
||||
} while( 0 );
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a TCP client channel from a socket.
|
||||
*/
|
||||
TcpClientContext * tcp_channel_server_create_client( TcpServerContext * serverctx, SOCKET sock )
|
||||
{
|
||||
DWORD dwResult = ERROR_SUCCESS;
|
||||
TcpClientContext * clientctx = NULL;
|
||||
StreamChannelOps chops = {0};
|
||||
|
||||
do
|
||||
{
|
||||
if( !serverctx )
|
||||
BREAK_WITH_ERROR( "[TCP-SERVER] tcp_channel_server_create_client. serverctx == NULL", ERROR_INVALID_HANDLE );
|
||||
|
||||
clientctx = (TcpClientContext *)malloc( sizeof(TcpClientContext) );
|
||||
if( !clientctx )
|
||||
BREAK_WITH_ERROR( "[TCP-SERVER] tcp_channel_server_create_client. clientctx == NULL", ERROR_NOT_ENOUGH_MEMORY );
|
||||
|
||||
memset( clientctx, 0, sizeof(TcpClientContext) );
|
||||
|
||||
clientctx->remote = serverctx->remote;
|
||||
clientctx->fd = sock;
|
||||
|
||||
clientctx->notify = WSACreateEvent();
|
||||
if( clientctx->notify == WSA_INVALID_EVENT )
|
||||
BREAK_ON_WSAERROR( "[TCP-SERVER] tcp_channel_server_create_client. WSACreateEvent failed" );
|
||||
|
||||
if( WSAEventSelect( clientctx->fd, clientctx->notify, FD_READ|FD_CLOSE ) == SOCKET_ERROR )
|
||||
BREAK_ON_WSAERROR( "[TCP-SERVER] tcp_channel_server_create_client. WSAEventSelect failed" );
|
||||
|
||||
memset( &chops, 0, sizeof(StreamChannelOps) );
|
||||
|
||||
chops.native.context = clientctx;
|
||||
chops.native.write = tcp_channel_client_write;
|
||||
chops.native.close = tcp_channel_client_close;
|
||||
|
||||
clientctx->channel = channel_create_stream( 0, 0, &chops );
|
||||
if( !clientctx->channel )
|
||||
BREAK_WITH_ERROR( "[TCP-SERVER] tcp_channel_server_create_client. clientctx->channel == NULL", ERROR_INVALID_HANDLE );
|
||||
|
||||
dwResult = scheduler_insert_waitable( clientctx->notify, clientctx, (WaitableNotifyRoutine)tcp_channel_client_local_notify );
|
||||
|
||||
} while( 0 );
|
||||
|
||||
if( dwResult != ERROR_SUCCESS )
|
||||
{
|
||||
if( clientctx )
|
||||
{
|
||||
free( clientctx );
|
||||
clientctx = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return clientctx;
|
||||
}
|
||||
|
||||
/*
|
||||
* Notify routine for a tcp server channel to pick up its new client connections.
|
||||
*/
|
||||
DWORD tcp_channel_server_notify( Remote * remote, TcpServerContext * serverctx )
|
||||
{
|
||||
DWORD dwResult = ERROR_SUCCESS;
|
||||
TcpClientContext * clientctx = NULL;
|
||||
Packet * request = NULL;
|
||||
SOCKADDR_IN clientaddr = {0};
|
||||
SOCKADDR_IN serveraddr = {0};
|
||||
SOCKET sock = 0;
|
||||
DWORD size = 0;
|
||||
char * localhost = NULL;
|
||||
char * peerhost = NULL;
|
||||
int localport = 0;
|
||||
int peerport = 0;
|
||||
|
||||
do
|
||||
{
|
||||
if( !serverctx )
|
||||
BREAK_WITH_ERROR( "[TCP-SERVER] tcp_channel_server_notify. serverctx == NULL", ERROR_INVALID_HANDLE );
|
||||
|
||||
ResetEvent( serverctx->notify );
|
||||
|
||||
size = sizeof(SOCKADDR);
|
||||
|
||||
sock = accept( serverctx->fd, (SOCKADDR *)&clientaddr, &size );
|
||||
if( sock == INVALID_SOCKET )
|
||||
{
|
||||
if( WSAGetLastError() == WSAEWOULDBLOCK )
|
||||
{
|
||||
Sleep( 100 );
|
||||
break;
|
||||
}
|
||||
|
||||
BREAK_ON_WSAERROR( "[TCP-SERVER] tcp_channel_server_notify. accept failed" );
|
||||
}
|
||||
|
||||
dprintf( "[TCP-SERVER] tcp_channel_server_notify. Got new client connection on channel %d. sock=%d", channel_get_id(serverctx->channel), sock );
|
||||
|
||||
clientctx = tcp_channel_server_create_client( serverctx, sock );
|
||||
if( !clientctx )
|
||||
BREAK_WITH_ERROR( "[TCP-SERVER] tcp_channel_server_notify. clientctx == NULL", ERROR_INVALID_HANDLE );
|
||||
|
||||
size = sizeof(SOCKADDR);
|
||||
|
||||
if( getsockname( serverctx->fd, (SOCKADDR *)&serveraddr, &size ) == SOCKET_ERROR )
|
||||
BREAK_ON_WSAERROR( "[TCP-SERVER] request_net_tcp_server_channel_open. getsockname failed" );
|
||||
|
||||
localhost = inet_ntoa( serveraddr.sin_addr );
|
||||
if( !localhost )
|
||||
localhost = "";
|
||||
|
||||
localport = ntohs( serveraddr.sin_port );
|
||||
|
||||
peerhost = inet_ntoa( clientaddr.sin_addr );
|
||||
if( !peerhost )
|
||||
peerhost = "";
|
||||
|
||||
peerport = ntohs( clientaddr.sin_port );
|
||||
|
||||
dprintf( "[TCP-SERVER] tcp_channel_server_notify. New connection %s:%d <- %s:%d", localhost, localport, peerhost, peerport );
|
||||
|
||||
request = packet_create( PACKET_TLV_TYPE_REQUEST, "tcp_channel_open" );
|
||||
if( !request )
|
||||
BREAK_WITH_ERROR( "[TCP-SERVER] request_net_tcp_server_channel_open. packet_create failed", ERROR_INVALID_HANDLE );
|
||||
|
||||
packet_add_tlv_uint( request, TLV_TYPE_CHANNEL_ID, channel_get_id(clientctx->channel) );
|
||||
packet_add_tlv_uint( request, TLV_TYPE_CHANNEL_PARENTID, channel_get_id(serverctx->channel) );
|
||||
packet_add_tlv_string( request, TLV_TYPE_LOCAL_HOST, localhost );
|
||||
packet_add_tlv_uint( request, TLV_TYPE_LOCAL_PORT, localport );
|
||||
packet_add_tlv_string( request, TLV_TYPE_PEER_HOST, peerhost );
|
||||
packet_add_tlv_uint( request, TLV_TYPE_PEER_PORT, peerport );
|
||||
|
||||
dwResult = packet_transmit( serverctx->remote, request, NULL );
|
||||
|
||||
} while( 0 );
|
||||
|
||||
return dwResult;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocates a streaming TCP server channel
|
||||
*/
|
||||
DWORD request_net_tcp_server_channel_open( Remote * remote, Packet * packet )
|
||||
{
|
||||
DWORD dwResult = ERROR_SUCCESS;
|
||||
TcpServerContext * ctx = NULL;
|
||||
Packet * response = NULL;
|
||||
char * lhost = NULL;
|
||||
SOCKADDR_IN saddr = {0};
|
||||
StreamChannelOps chops = {0};
|
||||
USHORT lport = 0;
|
||||
|
||||
do
|
||||
{
|
||||
response = packet_create_response( packet );
|
||||
if( !response )
|
||||
BREAK_WITH_ERROR( "[TCP-SERVER] request_net_tcp_server_channel_open. response == NULL", ERROR_NOT_ENOUGH_MEMORY );
|
||||
|
||||
ctx = (TcpServerContext *)malloc( sizeof(TcpServerContext) );
|
||||
if( !ctx )
|
||||
BREAK_WITH_ERROR( "[TCP-SERVER] request_net_tcp_server_channel_open. ctx == NULL", ERROR_NOT_ENOUGH_MEMORY );
|
||||
|
||||
memset( ctx, 0, sizeof(TcpServerContext) );
|
||||
|
||||
ctx->remote = remote;
|
||||
|
||||
lport = (USHORT)( packet_get_tlv_value_uint( packet, TLV_TYPE_LOCAL_PORT ) & 0xFFFF );
|
||||
if( !lport )
|
||||
BREAK_WITH_ERROR( "[TCP-SERVER] request_net_tcp_server_channel_open. lport == NULL", ERROR_INVALID_HANDLE );
|
||||
|
||||
lhost = packet_get_tlv_value_string( packet, TLV_TYPE_LOCAL_HOST );
|
||||
if( !lhost )
|
||||
lhost = "0.0.0.0";
|
||||
|
||||
ctx->fd = WSASocket( AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, 0 );
|
||||
if( ctx->fd == INVALID_SOCKET )
|
||||
BREAK_ON_WSAERROR( "[TCP-SERVER] request_net_tcp_server_channel_open. WSASocket failed" );
|
||||
|
||||
saddr.sin_family = AF_INET;
|
||||
saddr.sin_port = htons( lport );
|
||||
saddr.sin_addr.s_addr = inet_addr( lhost );
|
||||
|
||||
if( bind( ctx->fd, (SOCKADDR *)&saddr, sizeof(SOCKADDR) ) == SOCKET_ERROR )
|
||||
BREAK_ON_WSAERROR( "[TCP-SERVER] request_net_tcp_server_channel_open. bind failed" );
|
||||
|
||||
if( listen( ctx->fd, SOMAXCONN ) == SOCKET_ERROR )
|
||||
BREAK_ON_WSAERROR( "[TCP-SERVER] request_net_tcp_server_channel_open. listen failed" );
|
||||
|
||||
ctx->notify = WSACreateEvent();
|
||||
if( ctx->notify == WSA_INVALID_EVENT )
|
||||
BREAK_ON_WSAERROR( "[TCP-SERVER] request_net_tcp_server_channel_open. WSACreateEvent failed" );
|
||||
|
||||
if( WSAEventSelect( ctx->fd, ctx->notify, FD_ACCEPT ) == SOCKET_ERROR )
|
||||
BREAK_ON_WSAERROR( "[TCP-SERVER] request_net_tcp_server_channel_open. WSAEventSelect failed" );
|
||||
|
||||
memset( &chops, 0, sizeof(StreamChannelOps) );
|
||||
chops.native.context = ctx;
|
||||
chops.native.close = tcp_channel_server_close;
|
||||
|
||||
ctx->channel = channel_create_stream( 0, CHANNEL_FLAG_SYNCHRONOUS, &chops );
|
||||
if( !ctx->channel )
|
||||
BREAK_WITH_ERROR( "[TCP-SERVER] request_net_tcp_server_channel_open. channel_create_stream failed", ERROR_INVALID_HANDLE );
|
||||
|
||||
scheduler_insert_waitable( ctx->notify, ctx, (WaitableNotifyRoutine)tcp_channel_server_notify );
|
||||
|
||||
packet_add_tlv_uint( response, TLV_TYPE_CHANNEL_ID, channel_get_id(ctx->channel) );
|
||||
|
||||
dprintf( "[TCP-SERVER] request_net_tcp_server_channel_open. tcp server %s:%d on channel %d", lhost, lport, channel_get_id(ctx->channel) );
|
||||
|
||||
} while( 0 );
|
||||
|
||||
packet_transmit_response( dwResult, remote, response );
|
||||
|
||||
do
|
||||
{
|
||||
if( dwResult == ERROR_SUCCESS )
|
||||
break;
|
||||
|
||||
if( !ctx )
|
||||
break;
|
||||
|
||||
if( ctx->fd )
|
||||
closesocket( ctx->fd );
|
||||
|
||||
if( ctx->channel )
|
||||
channel_destroy( ctx->channel, packet );
|
||||
|
||||
free( ctx );
|
||||
|
||||
} while( 0 );
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
@ -268,7 +268,8 @@ Command customCommands[] =
|
||||
{ request_net_config_get_interfaces, { 0 }, 0 },
|
||||
{ EMPTY_DISPATCH_HANDLER },
|
||||
},
|
||||
// Socket
|
||||
|
||||
// Socket
|
||||
{ "stdapi_net_socket_tcp_shutdown",
|
||||
{ request_net_socket_tcp_shutdown, { 0 }, 0 },
|
||||
{ EMPTY_DISPATCH_HANDLER },
|
||||
|
@ -425,7 +425,7 @@
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source"
|
||||
Name="Source files"
|
||||
Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
>
|
||||
<File
|
||||
@ -468,10 +468,6 @@
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\source\extensions\stdapi\server\precomp.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\source\extensions\stdapi\server\stdapi.c"
|
||||
>
|
||||
@ -516,10 +512,6 @@
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\source\extensions\stdapi\stdapi.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\source\extensions\stdapi\server\resource\stdapi.rc"
|
||||
>
|
||||
@ -643,10 +635,6 @@
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\source\extensions\stdapi\server\fs\fs.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\source\extensions\stdapi\server\fs\fs_util.c"
|
||||
>
|
||||
@ -731,10 +719,6 @@
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\source\extensions\stdapi\server\net\net.h"
|
||||
>
|
||||
</File>
|
||||
<Filter
|
||||
Name="config"
|
||||
>
|
||||
@ -862,15 +846,15 @@
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\source\extensions\stdapi\server\net\socket\tcp_server.c"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="sys"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\source\extensions\stdapi\server\sys\sys.h"
|
||||
>
|
||||
</File>
|
||||
<Filter
|
||||
Name="process"
|
||||
>
|
||||
@ -1483,6 +1467,54 @@
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
</Filter>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\source\extensions\stdapi\server\precomp.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\source\extensions\stdapi\stdapi.h"
|
||||
>
|
||||
</File>
|
||||
<Filter
|
||||
Name="net"
|
||||
>
|
||||
<Filter
|
||||
Name="socket"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\source\extensions\stdapi\server\net\net.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\source\extensions\stdapi\server\net\socket\tcp.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="fs"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\source\extensions\stdapi\server\fs\fs.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="sys"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\source\extensions\stdapi\server\sys\sys.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="ui"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\source\extensions\stdapi\server\ui\ui.h"
|
||||
>
|
||||
|
@ -1,6 +1,6 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 10.00
|
||||
# Visual Studio 2008
|
||||
# Visual C++ Express 2008
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "common", "common\common.vcproj", "{9E4DE963-873F-4525-A7D0-CE34EDBBDCCA}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ext_server_priv", "ext_server_priv\ext_server_priv.vcproj", "{87C64204-C82F-415D-AF45-D0B33BDFE39A}"
|
||||
|
Loading…
Reference in New Issue
Block a user