1
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:
Stephen Fewer 2010-02-06 17:55:41 +00:00
parent 75d5d3c136
commit 85ed7baa43
11 changed files with 540 additions and 122 deletions

View File

@ -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:

View File

@ -32,7 +32,7 @@
#include "list.h"
// #define DEBUGTRACE
//#define DEBUGTRACE
#ifdef DEBUGTRACE
#define dprintf(...) real_dprintf(__VA_ARGS__)

View File

@ -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),

View File

@ -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 },
};

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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 },

View File

@ -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"
>

View File

@ -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}"