mirror of
https://github.com/SoftEtherVPN/SoftEtherVPN.git
synced 2024-11-23 01:49:53 +03:00
Merge PR #957: Add interface for easy protocol implementation
This commit is contained in:
commit
7dff0dce17
@ -1606,6 +1606,9 @@ void InitCedar()
|
|||||||
|
|
||||||
// Initialize protocol module
|
// Initialize protocol module
|
||||||
InitProtocol();
|
InitProtocol();
|
||||||
|
|
||||||
|
// Initialize third-party protocol interface
|
||||||
|
ProtoInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Free Cedar communication module
|
// Free Cedar communication module
|
||||||
@ -1616,6 +1619,9 @@ void FreeCedar()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Free third-party protocol interface
|
||||||
|
ProtoFree();
|
||||||
|
|
||||||
// Free protocol module
|
// Free protocol module
|
||||||
FreeProtocol();
|
FreeProtocol();
|
||||||
}
|
}
|
||||||
|
@ -305,8 +305,7 @@
|
|||||||
#define CONNECTION_TYPE_ADMIN_RPC 5 // RPC for Management
|
#define CONNECTION_TYPE_ADMIN_RPC 5 // RPC for Management
|
||||||
#define CONNECTION_TYPE_ENUM_HUB 6 // HUB enumeration
|
#define CONNECTION_TYPE_ENUM_HUB 6 // HUB enumeration
|
||||||
#define CONNECTION_TYPE_PASSWORD 7 // Password change
|
#define CONNECTION_TYPE_PASSWORD 7 // Password change
|
||||||
#define CONNECTION_TYPE_SSTP 8 // SSTP
|
#define CONNECTION_TYPE_OTHER 0xffffffff // E.g. Third-party protocol
|
||||||
#define CONNECTION_TYPE_OPENVPN 9 // OpenVPN
|
|
||||||
|
|
||||||
// Protocol
|
// Protocol
|
||||||
#define CONNECTION_TCP 0 // TCP protocol
|
#define CONNECTION_TCP 0 // TCP protocol
|
||||||
@ -1031,6 +1030,7 @@ typedef struct CEDAR
|
|||||||
// Layer-2/Layer-3 converter
|
// Layer-2/Layer-3 converter
|
||||||
#include <Cedar/IPC.h>
|
#include <Cedar/IPC.h>
|
||||||
// Third party protocols
|
// Third party protocols
|
||||||
|
#include <Cedar/Proto.h>
|
||||||
#include <Cedar/Proto_IPsec.h>
|
#include <Cedar/Proto_IPsec.h>
|
||||||
#include <Cedar/Proto_EtherIP.h>
|
#include <Cedar/Proto_EtherIP.h>
|
||||||
#include <Cedar/Proto_IkePacket.h>
|
#include <Cedar/Proto_IkePacket.h>
|
||||||
|
@ -650,6 +650,10 @@
|
|||||||
RelativePath=".\NullLan.c"
|
RelativePath=".\NullLan.c"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\Proto.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\Proto_EtherIP.c"
|
RelativePath=".\Proto_EtherIP.c"
|
||||||
>
|
>
|
||||||
@ -1280,6 +1284,10 @@
|
|||||||
RelativePath=".\NullLan.h"
|
RelativePath=".\NullLan.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\Proto.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\Proto_EtherIP.h"
|
RelativePath=".\Proto_EtherIP.h"
|
||||||
>
|
>
|
||||||
|
@ -2901,21 +2901,8 @@ void ConnectionAccept(CONNECTION *c)
|
|||||||
X *x;
|
X *x;
|
||||||
K *k;
|
K *k;
|
||||||
char tmp[128];
|
char tmp[128];
|
||||||
UCHAR openssl_check_buf[2];
|
|
||||||
char *error_details = NULL;
|
|
||||||
SERVER *server;
|
|
||||||
UCHAR *peek_buf = NULL;
|
|
||||||
UINT peek_buf_size = 1500;
|
|
||||||
char sni[256] = {0};
|
|
||||||
bool native1 = false;
|
|
||||||
bool native2 = false;
|
|
||||||
bool native3 = false;
|
|
||||||
bool no_native = false;
|
|
||||||
UINT peek_size = 0;
|
|
||||||
UINT initial_timeout = CONNECTING_TIMEOUT;
|
UINT initial_timeout = CONNECTING_TIMEOUT;
|
||||||
bool no_peek_log = false;
|
|
||||||
UCHAR ctoken_hash[SHA1_SIZE];
|
UCHAR ctoken_hash[SHA1_SIZE];
|
||||||
bool no_write_ctoken_log = false;
|
|
||||||
|
|
||||||
// Validate arguments
|
// Validate arguments
|
||||||
if (c == NULL)
|
if (c == NULL)
|
||||||
@ -2925,13 +2912,7 @@ void ConnectionAccept(CONNECTION *c)
|
|||||||
|
|
||||||
Zero(ctoken_hash, sizeof(ctoken_hash));
|
Zero(ctoken_hash, sizeof(ctoken_hash));
|
||||||
|
|
||||||
peek_buf = ZeroMalloc(peek_buf_size);
|
// Get a socket
|
||||||
|
|
||||||
Debug("ConnectionAccept()\n");
|
|
||||||
|
|
||||||
server = c->Cedar->Server;
|
|
||||||
|
|
||||||
// get a socket
|
|
||||||
s = c->FirstSock;
|
s = c->FirstSock;
|
||||||
AddRef(s->ref);
|
AddRef(s->ref);
|
||||||
|
|
||||||
@ -2945,37 +2926,18 @@ void ConnectionAccept(CONNECTION *c)
|
|||||||
initial_timeout += GetMachineRand() % (CONNECTING_TIMEOUT / 2);
|
initial_timeout += GetMachineRand() % (CONNECTING_TIMEOUT / 2);
|
||||||
SetTimeout(s, initial_timeout);
|
SetTimeout(s, initial_timeout);
|
||||||
|
|
||||||
|
// Handle third-party protocols
|
||||||
// Peek whether OpenSSL packet
|
if (s->IsReverseAcceptedSocket == false && s->Type == SOCK_TCP)
|
||||||
if (s->IsReverseAcceptedSocket == false)
|
|
||||||
{
|
{
|
||||||
if (s->Type == SOCK_TCP && (c->Cedar != NULL && c->Cedar->Server != NULL && c->Cedar->Server->DisableOpenVPNServer == false))
|
if (c->Cedar != NULL && c->Cedar->Server != NULL)
|
||||||
{
|
{
|
||||||
if (Peek(s, openssl_check_buf, sizeof(openssl_check_buf)) == sizeof(openssl_check_buf))
|
c->Type = CONNECTION_TYPE_OTHER;
|
||||||
|
|
||||||
|
if (ProtoHandleConnection(c->Cedar, s) == true)
|
||||||
{
|
{
|
||||||
if (OvsCheckTcpRecvBufIfOpenVPNProtocol(openssl_check_buf, sizeof(openssl_check_buf)))
|
goto FINAL;
|
||||||
{
|
|
||||||
// Detect OpenSSL packet
|
|
||||||
Debug("Detect OpenSSL on TCP!\n");
|
|
||||||
|
|
||||||
no_native = true;
|
|
||||||
|
|
||||||
if (OvsGetNoOpenVpnTcp() == false)
|
|
||||||
{
|
|
||||||
// Do OpenSSL processing
|
|
||||||
c->Type = CONNECTION_TYPE_OPENVPN;
|
|
||||||
if (OvsPerformTcpServer(c->Cedar, s) == false)
|
|
||||||
{
|
|
||||||
error_details = "OpenVPN_TCP_Aborted";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
goto ERROR;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Specify the encryption algorithm
|
// Specify the encryption algorithm
|
||||||
@ -2992,22 +2954,18 @@ void ConnectionAccept(CONNECTION *c)
|
|||||||
Unlock(c->Cedar->lock);
|
Unlock(c->Cedar->lock);
|
||||||
|
|
||||||
// Start the SSL communication
|
// Start the SSL communication
|
||||||
Debug("StartSSL()\n");
|
|
||||||
Copy(&s->SslAcceptSettings, &c->Cedar->SslAcceptSettings, sizeof(SSL_ACCEPT_SETTINGS));
|
Copy(&s->SslAcceptSettings, &c->Cedar->SslAcceptSettings, sizeof(SSL_ACCEPT_SETTINGS));
|
||||||
if (StartSSL(s, x, k) == false)
|
if (StartSSL(s, x, k) == false)
|
||||||
{
|
{
|
||||||
// Failed
|
// Failed
|
||||||
AddNoSsl(c->Cedar, &s->RemoteIP);
|
AddNoSsl(c->Cedar, &s->RemoteIP);
|
||||||
Debug("Failed to StartSSL.\n");
|
Debug("ConnectionAccept(): StartSSL() failed\n");
|
||||||
FreeX(x);
|
FreeX(x);
|
||||||
FreeK(k);
|
FreeK(k);
|
||||||
|
|
||||||
error_details = "StartSSL";
|
goto FINAL;
|
||||||
|
|
||||||
goto ERROR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
FreeX(x);
|
FreeX(x);
|
||||||
FreeK(k);
|
FreeK(k);
|
||||||
|
|
||||||
@ -3019,29 +2977,18 @@ void ConnectionAccept(CONNECTION *c)
|
|||||||
if (ServerAccept(c) == false)
|
if (ServerAccept(c) == false)
|
||||||
{
|
{
|
||||||
// Failed
|
// Failed
|
||||||
Debug("ServerAccept Failed. Err = %u\n", c->Err);
|
Debug("ConnectionAccept(): ServerAccept() failed with error %u\n", c->Err);
|
||||||
goto ERROR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FINAL:
|
||||||
if (c->flag1 == false)
|
if (c->flag1 == false)
|
||||||
{
|
{
|
||||||
Debug("%s %u c->flag1 == false\n", __FILE__, __LINE__);
|
Debug("%s %u c->flag1 == false\n", __FILE__, __LINE__);
|
||||||
Disconnect(s);
|
Disconnect(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
DelConnection(c->Cedar, c);
|
DelConnection(c->Cedar, c);
|
||||||
ReleaseSock(s);
|
ReleaseSock(s);
|
||||||
|
|
||||||
Free(peek_buf);
|
|
||||||
return;
|
|
||||||
|
|
||||||
ERROR:
|
|
||||||
Debug("ConnectionAccept() Error.\n");
|
|
||||||
|
|
||||||
|
|
||||||
Disconnect(s);
|
|
||||||
DelConnection(c->Cedar, c);
|
|
||||||
ReleaseSock(s);
|
|
||||||
Free(peek_buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop the threads putting additional connection of all that are currently running
|
// Stop the threads putting additional connection of all that are currently running
|
||||||
|
271
src/Cedar/Proto.c
Normal file
271
src/Cedar/Proto.c
Normal file
@ -0,0 +1,271 @@
|
|||||||
|
#include "CedarPch.h"
|
||||||
|
|
||||||
|
#include "Proto_OpenVPN.h"
|
||||||
|
|
||||||
|
static LIST *protocols = NULL;
|
||||||
|
|
||||||
|
int ProtoCompare(void *p1, void *p2)
|
||||||
|
{
|
||||||
|
PROTO *proto_1, *proto_2;
|
||||||
|
|
||||||
|
if (p1 == NULL || p2 == NULL)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
proto_1 = (PROTO *)p1;
|
||||||
|
proto_2 = (PROTO *)p2;
|
||||||
|
|
||||||
|
if (StrCmp(proto_1->impl->Name(), proto_2->impl->Name()) == 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProtoInit()
|
||||||
|
{
|
||||||
|
if (protocols != NULL)
|
||||||
|
{
|
||||||
|
ProtoFree();
|
||||||
|
}
|
||||||
|
|
||||||
|
protocols = NewList(ProtoCompare);
|
||||||
|
|
||||||
|
// OpenVPN
|
||||||
|
ProtoAdd(OvsGetProtoImpl());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProtoFree()
|
||||||
|
{
|
||||||
|
UINT i;
|
||||||
|
PROTO_IMPL *impl;
|
||||||
|
|
||||||
|
for (i = 0; i < ProtoNum(); ++i)
|
||||||
|
{
|
||||||
|
PROTO *proto = ProtoGet(i);
|
||||||
|
impl = proto->impl;
|
||||||
|
Free(proto);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReleaseList(protocols);
|
||||||
|
protocols = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ProtoAdd(PROTO_IMPL *impl)
|
||||||
|
{
|
||||||
|
PROTO *proto;
|
||||||
|
|
||||||
|
if (protocols == NULL || impl == NULL)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
proto = Malloc(sizeof(PROTO));
|
||||||
|
proto->impl = impl;
|
||||||
|
|
||||||
|
Add(protocols, proto);
|
||||||
|
|
||||||
|
Debug("ProtoAdd(): added %s\n", proto->impl->Name());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT ProtoNum()
|
||||||
|
{
|
||||||
|
return LIST_NUM(protocols);
|
||||||
|
}
|
||||||
|
|
||||||
|
PROTO *ProtoGet(const UINT index)
|
||||||
|
{
|
||||||
|
return LIST_DATA(protocols, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
PROTO *ProtoDetect(SOCK *sock)
|
||||||
|
{
|
||||||
|
UCHAR buf[PROTO_CHECK_BUFFER_SIZE];
|
||||||
|
UINT i;
|
||||||
|
|
||||||
|
if (sock == NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Peek(sock, buf, sizeof(buf)) == 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < ProtoNum(); ++i)
|
||||||
|
{
|
||||||
|
PROTO *p = ProtoGet(i);
|
||||||
|
if (p->impl->IsPacketForMe(buf, sizeof(buf)))
|
||||||
|
{
|
||||||
|
Debug("ProtoDetect(): %s detected\n", p->impl->Name());
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ProtoHandleConnection(CEDAR *cedar, SOCK *sock)
|
||||||
|
{
|
||||||
|
void *impl_data;
|
||||||
|
const PROTO_IMPL *impl;
|
||||||
|
const PROTO *proto;
|
||||||
|
|
||||||
|
UCHAR *buf;
|
||||||
|
TCP_RAW_DATA *recv_raw_data;
|
||||||
|
FIFO *send_fifo;
|
||||||
|
INTERRUPT_MANAGER *im;
|
||||||
|
SOCK_EVENT *se;
|
||||||
|
|
||||||
|
const UINT64 giveup = Tick64() + (UINT64)OPENVPN_NEW_SESSION_DEADLINE_TIMEOUT;
|
||||||
|
|
||||||
|
if (cedar == NULL || sock == NULL)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
proto = ProtoDetect(sock);
|
||||||
|
|
||||||
|
if (proto == NULL)
|
||||||
|
{
|
||||||
|
Debug("ProtoHandleConnection(): unrecognized protocol\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl = proto->impl;
|
||||||
|
|
||||||
|
if (StrCmp(impl->Name(), "OpenVPN") == 0 && cedar->Server->DisableOpenVPNServer == true)
|
||||||
|
{
|
||||||
|
Debug("ProtoHandleConnection(): OpenVPN detected, but it's disabled\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((impl->SupportedModes() & PROTO_MODE_TCP) == false)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
im = NewInterruptManager();
|
||||||
|
se = NewSockEvent();
|
||||||
|
|
||||||
|
if (impl->Init != NULL && impl->Init(&impl_data, cedar, im, se) == false)
|
||||||
|
{
|
||||||
|
Debug("ProtoHandleConnection(): failed to initialize %s\n", impl->Name());
|
||||||
|
FreeInterruptManager(im);
|
||||||
|
ReleaseSockEvent(se);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetTimeout(sock, TIMEOUT_INFINITE);
|
||||||
|
JoinSockToSockEvent(sock, se);
|
||||||
|
|
||||||
|
recv_raw_data = NewTcpRawData(&sock->RemoteIP, sock->RemotePort, &sock->LocalIP, sock->LocalPort);
|
||||||
|
send_fifo = NewFifoFast();
|
||||||
|
|
||||||
|
buf = Malloc(PROTO_TCP_BUFFER_SIZE);
|
||||||
|
|
||||||
|
Debug("ProtoHandleConnection(): entering main loop\n");
|
||||||
|
|
||||||
|
// Receive data from the TCP socket
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
UINT next_interval;
|
||||||
|
bool stop = false;
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
const UINT ret = Recv(sock, buf, PROTO_TCP_BUFFER_SIZE, false);
|
||||||
|
|
||||||
|
if (ret == SOCK_LATER)
|
||||||
|
{
|
||||||
|
// No more data to read
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (ret == 0)
|
||||||
|
{
|
||||||
|
// Disconnected
|
||||||
|
stop = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Write the received data into the FIFO
|
||||||
|
WriteFifo(recv_raw_data->Data, buf, ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (impl->ProcessData(impl_data, recv_raw_data, send_fifo) == false)
|
||||||
|
{
|
||||||
|
stop = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send data to the TCP socket
|
||||||
|
while (FifoSize(send_fifo) >= 1)
|
||||||
|
{
|
||||||
|
const UINT ret = Send(sock, FifoPtr(send_fifo), FifoSize(send_fifo), false);
|
||||||
|
|
||||||
|
if (ret == SOCK_LATER)
|
||||||
|
{
|
||||||
|
// Can not write anymore
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (ret == 0)
|
||||||
|
{
|
||||||
|
// Disconnected
|
||||||
|
stop = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Remove data that has been sent from the FIFO
|
||||||
|
ReadFifo(send_fifo, NULL, ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl->BufferLimit(impl_data, FifoSize(send_fifo) > MAX_BUFFERING_PACKET_SIZE);
|
||||||
|
|
||||||
|
if (impl->IsOk(impl_data) == false)
|
||||||
|
{
|
||||||
|
if (impl->EstablishedSessions(impl_data) == 0)
|
||||||
|
{
|
||||||
|
if (Tick64() >= giveup)
|
||||||
|
{
|
||||||
|
Debug("ProtoHandleConnection(): I waited too much for the session to start, I give up!\n");
|
||||||
|
stop = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug("ProtoHandleConnection(): implementation not OK, stopping the server\n");
|
||||||
|
stop = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stop)
|
||||||
|
{
|
||||||
|
// Error or disconnection occurs
|
||||||
|
Debug("ProtoHandleConnection(): breaking main loop\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait until the next event occurs
|
||||||
|
next_interval = GetNextIntervalForInterrupt(im);
|
||||||
|
next_interval = MIN(next_interval, UDPLISTENER_WAIT_INTERVAL);
|
||||||
|
WaitSockEvent(se, next_interval);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl->Free(impl_data);
|
||||||
|
|
||||||
|
FreeInterruptManager(im);
|
||||||
|
ReleaseSockEvent(se);
|
||||||
|
FreeTcpRawData(recv_raw_data);
|
||||||
|
ReleaseFifo(send_fifo);
|
||||||
|
Free(buf);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
44
src/Cedar/Proto.h
Normal file
44
src/Cedar/Proto.h
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#ifndef PROTO_H
|
||||||
|
#define PROTO_H
|
||||||
|
|
||||||
|
// OpenVPN sends 2 bytes, thus this is the buffer size.
|
||||||
|
// If another protocol requires more bytes to be detected, the buffer size must be increased.
|
||||||
|
#define PROTO_CHECK_BUFFER_SIZE 2
|
||||||
|
|
||||||
|
#define PROTO_TCP_BUFFER_SIZE (128 * 1024)
|
||||||
|
|
||||||
|
#define PROTO_MODE_TCP 1
|
||||||
|
#define PROTO_MODE_UDP 2
|
||||||
|
|
||||||
|
typedef struct PROTO_IMPL
|
||||||
|
{
|
||||||
|
bool (*Init)(void **param, CEDAR *cedar, INTERRUPT_MANAGER *im, SOCK_EVENT *se);
|
||||||
|
void (*Free)(void *param);
|
||||||
|
char *(*Name)();
|
||||||
|
UINT (*SupportedModes)();
|
||||||
|
bool (*IsPacketForMe)(const UCHAR *data, const UINT size);
|
||||||
|
bool (*ProcessData)(void *param, TCP_RAW_DATA *received_data, FIFO *data_to_send);
|
||||||
|
void (*BufferLimit)(void *param, const bool reached);
|
||||||
|
bool (*IsOk)(void *param);
|
||||||
|
UINT (*EstablishedSessions)(void *param);
|
||||||
|
} PROTO_IMPL;
|
||||||
|
|
||||||
|
typedef struct PROTO
|
||||||
|
{
|
||||||
|
PROTO_IMPL *impl;
|
||||||
|
} PROTO;
|
||||||
|
|
||||||
|
int ProtoCompare(void *p1, void *p2);
|
||||||
|
|
||||||
|
void ProtoInit();
|
||||||
|
void ProtoFree();
|
||||||
|
|
||||||
|
bool ProtoAdd(PROTO_IMPL *impl);
|
||||||
|
|
||||||
|
UINT ProtoNum();
|
||||||
|
PROTO *ProtoGet(const UINT index);
|
||||||
|
PROTO *ProtoDetect(SOCK *sock);
|
||||||
|
|
||||||
|
bool ProtoHandleConnection(CEDAR *cedar, SOCK *sock);
|
||||||
|
|
||||||
|
#endif
|
@ -7,10 +7,6 @@
|
|||||||
|
|
||||||
#include "CedarPch.h"
|
#include "CedarPch.h"
|
||||||
|
|
||||||
|
|
||||||
static bool g_no_openvpn_tcp = false;
|
|
||||||
static bool g_no_openvpn_udp = false;
|
|
||||||
|
|
||||||
// Ping signature of the OpenVPN protocol
|
// Ping signature of the OpenVPN protocol
|
||||||
static UCHAR ping_signature[] =
|
static UCHAR ping_signature[] =
|
||||||
{
|
{
|
||||||
@ -18,18 +14,213 @@ static UCHAR ping_signature[] =
|
|||||||
0x07, 0xed, 0x2d, 0x0a, 0x98, 0x1f, 0xc7, 0x48
|
0x07, 0xed, 0x2d, 0x0a, 0x98, 0x1f, 0xc7, 0x48
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get the OpenVPN over TCP disabling flag
|
PROTO_IMPL *OvsGetProtoImpl()
|
||||||
bool OvsGetNoOpenVpnTcp()
|
|
||||||
{
|
{
|
||||||
return g_no_openvpn_tcp;
|
static PROTO_IMPL impl =
|
||||||
|
{
|
||||||
|
OvsInit,
|
||||||
|
OvsFree,
|
||||||
|
OvsName,
|
||||||
|
OvsSupportedModes,
|
||||||
|
OvsIsPacketForMe,
|
||||||
|
OvsProcessData,
|
||||||
|
OvsBufferLimit,
|
||||||
|
OvsIsOk,
|
||||||
|
OvsEstablishedSessions
|
||||||
|
};
|
||||||
|
|
||||||
|
return &impl;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the OpenVPN over UDP disabling flag
|
bool OvsInit(void **param, CEDAR *cedar, INTERRUPT_MANAGER *im, SOCK_EVENT *se)
|
||||||
bool OvsGetNoOpenVpnUdp()
|
|
||||||
{
|
{
|
||||||
return g_no_openvpn_udp;
|
if (param == NULL || cedar == NULL || im == NULL || se == NULL)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*param = NewOpenVpnServer(cedar, im, se);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OvsFree(void *param)
|
||||||
|
{
|
||||||
|
FreeOpenVpnServer(param);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the protocol name
|
||||||
|
char *OvsName()
|
||||||
|
{
|
||||||
|
return "OpenVPN";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the supported modes (TCP & UDP)
|
||||||
|
UINT OvsSupportedModes()
|
||||||
|
{
|
||||||
|
return PROTO_MODE_TCP | PROTO_MODE_UDP;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check whether it's an OpenVPN packet
|
||||||
|
bool OvsIsPacketForMe(const UCHAR *buf, const UINT size)
|
||||||
|
{
|
||||||
|
if (buf == NULL || size != 2)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf[0] == 0x00 && buf[1] == 0x0E)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OvsProcessData(void *param, TCP_RAW_DATA *received_data, FIFO *data_to_send)
|
||||||
|
{
|
||||||
|
bool ret = true;
|
||||||
|
UINT i;
|
||||||
|
OPENVPN_SERVER *server;
|
||||||
|
UCHAR buf[OPENVPN_TCP_MAX_PACKET_SIZE];
|
||||||
|
|
||||||
|
if (param == NULL || received_data == NULL || data_to_send == NULL)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
server = param;
|
||||||
|
|
||||||
|
// Separate to a list of datagrams by interpreting the data received from the TCP socket
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
UDPPACKET *packet;
|
||||||
|
UCHAR *packet_ptr;
|
||||||
|
UINT packet_size, total_packet_size;
|
||||||
|
FIFO *recv_fifo = received_data->Data;
|
||||||
|
const UINT data_size = FifoSize(recv_fifo);
|
||||||
|
|
||||||
|
if (data_size < sizeof(USHORT))
|
||||||
|
{
|
||||||
|
// Corrupt data
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
packet_size = READ_USHORT(FifoPtr(recv_fifo));
|
||||||
|
|
||||||
|
if (packet_size == 0 || packet_size > sizeof(buf))
|
||||||
|
{
|
||||||
|
// Invalid packet size
|
||||||
|
ret = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
total_packet_size = packet_size + sizeof(USHORT);
|
||||||
|
|
||||||
|
if (data_size < total_packet_size)
|
||||||
|
{
|
||||||
|
// Corrupt data
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ReadFifo(recv_fifo, buf, total_packet_size) != total_packet_size)
|
||||||
|
{
|
||||||
|
// Mismatch
|
||||||
|
ret = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read one packet and put it in the list
|
||||||
|
packet_ptr = buf + sizeof(USHORT);
|
||||||
|
|
||||||
|
packet = NewUdpPacket(&received_data->SrcIP, received_data->SrcPort, &received_data->DstIP, received_data->DstPort, Clone(packet_ptr, packet_size), packet_size);
|
||||||
|
packet->Type = OPENVPN_PROTOCOL_TCP;
|
||||||
|
Add(server->RecvPacketList, packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the list of received datagrams
|
||||||
|
OvsRecvPacket(server, server->RecvPacketList);
|
||||||
|
|
||||||
|
// Release the received packet list
|
||||||
|
for (i = 0; i < LIST_NUM(server->RecvPacketList); ++i)
|
||||||
|
{
|
||||||
|
UDPPACKET *p = LIST_DATA(server->RecvPacketList, i);
|
||||||
|
FreeUdpPacket(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
DeleteAll(server->RecvPacketList);
|
||||||
|
|
||||||
|
// Store in the queue by getting a list of the datagrams to be transmitted from the OpenVPN server
|
||||||
|
for (i = 0; i < LIST_NUM(server->SendPacketList); ++i)
|
||||||
|
{
|
||||||
|
UDPPACKET *p = LIST_DATA(server->SendPacketList, i);
|
||||||
|
|
||||||
|
// Store the size in the TCP send queue first
|
||||||
|
USHORT us = Endian16((USHORT)p->Size);
|
||||||
|
|
||||||
|
WriteFifo(data_to_send, &us, sizeof(USHORT));
|
||||||
|
|
||||||
|
// Write the data body
|
||||||
|
WriteFifo(data_to_send, p->Data, p->Size);
|
||||||
|
|
||||||
|
// Packet release
|
||||||
|
FreeUdpPacket(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
DeleteAll(server->SendPacketList);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OvsBufferLimit(void *param, const bool reached)
|
||||||
|
{
|
||||||
|
if (param == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
((OPENVPN_SERVER *)param)->SupressSendPacket = reached;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OvsIsOk(void *param)
|
||||||
|
{
|
||||||
|
OPENVPN_SERVER *s;
|
||||||
|
|
||||||
|
if (param == NULL)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
s = param;
|
||||||
|
|
||||||
|
return (s->DisconnectCount < 1) && (s->SessionEstablishedCount > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT OvsEstablishedSessions(void *param)
|
||||||
|
{
|
||||||
|
LIST *sessions;
|
||||||
|
UINT i;
|
||||||
|
UINT established_sessions = 0;
|
||||||
|
|
||||||
|
if (param == NULL)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
sessions = ((OPENVPN_SERVER *)param)->SessionList;
|
||||||
|
|
||||||
|
for (i = 0;i < LIST_NUM(sessions);i++)
|
||||||
|
{
|
||||||
|
OPENVPN_SESSION *se = LIST_DATA(sessions, i);
|
||||||
|
|
||||||
|
if (se->Established)
|
||||||
|
{
|
||||||
|
++established_sessions;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return established_sessions;
|
||||||
|
}
|
||||||
|
|
||||||
// Write the OpenVPN log
|
// Write the OpenVPN log
|
||||||
void OvsLog(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_CHANNEL *c, char *name, ...)
|
void OvsLog(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_CHANNEL *c, char *name, ...)
|
||||||
@ -341,7 +532,7 @@ final:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Process the received packet
|
// Process the received packet
|
||||||
void OvsProceccRecvPacket(OPENVPN_SERVER *s, UDPPACKET *p, UINT protocol)
|
void OvsProceccRecvPacket(OPENVPN_SERVER *s, UDPPACKET *p)
|
||||||
{
|
{
|
||||||
OPENVPN_CHANNEL *c;
|
OPENVPN_CHANNEL *c;
|
||||||
OPENVPN_SESSION *se;
|
OPENVPN_SESSION *se;
|
||||||
@ -353,7 +544,7 @@ void OvsProceccRecvPacket(OPENVPN_SERVER *s, UDPPACKET *p, UINT protocol)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Search for the session
|
// Search for the session
|
||||||
se = OvsFindOrCreateSession(s, &p->DstIP, p->DestPort, &p->SrcIP, p->SrcPort, protocol);
|
se = OvsFindOrCreateSession(s, &p->DstIP, p->DestPort, &p->SrcIP, p->SrcPort, p->Type);
|
||||||
if (se == NULL)
|
if (se == NULL)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@ -1989,7 +2180,7 @@ OPENVPN_SESSION *OvsSearchSession(OPENVPN_SERVER *s, IP *server_ip, UINT server_
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Receive packets in the OpenVPN server
|
// Receive packets in the OpenVPN server
|
||||||
void OvsRecvPacket(OPENVPN_SERVER *s, LIST *recv_packet_list, UINT protocol)
|
void OvsRecvPacket(OPENVPN_SERVER *s, LIST *recv_packet_list)
|
||||||
{
|
{
|
||||||
UINT i, j;
|
UINT i, j;
|
||||||
LIST *delete_session_list = NULL;
|
LIST *delete_session_list = NULL;
|
||||||
@ -2021,7 +2212,7 @@ void OvsRecvPacket(OPENVPN_SERVER *s, LIST *recv_packet_list, UINT protocol)
|
|||||||
{
|
{
|
||||||
UDPPACKET *p = LIST_DATA(recv_packet_list, i);
|
UDPPACKET *p = LIST_DATA(recv_packet_list, i);
|
||||||
|
|
||||||
OvsProceccRecvPacket(s, p, protocol);
|
OvsProceccRecvPacket(s, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Treat for all sessions and all channels
|
// Treat for all sessions and all channels
|
||||||
@ -2702,24 +2893,17 @@ OPENVPN_SERVER *NewOpenVpnServer(CEDAR *cedar, INTERRUPT_MANAGER *interrupt, SOC
|
|||||||
s = ZeroMalloc(sizeof(OPENVPN_SERVER));
|
s = ZeroMalloc(sizeof(OPENVPN_SERVER));
|
||||||
|
|
||||||
s->Cedar = cedar;
|
s->Cedar = cedar;
|
||||||
|
|
||||||
AddRef(s->Cedar->ref);
|
|
||||||
|
|
||||||
s->Interrupt = interrupt;
|
s->Interrupt = interrupt;
|
||||||
|
s->SockEvent = sock_event;
|
||||||
|
|
||||||
s->SessionList = NewList(OvsCompareSessionList);
|
s->SessionList = NewList(OvsCompareSessionList);
|
||||||
|
s->RecvPacketList = NewListFast(NULL);
|
||||||
s->SendPacketList = NewListFast(NULL);
|
s->SendPacketList = NewListFast(NULL);
|
||||||
|
|
||||||
s->Now = Tick64();
|
s->Now = Tick64();
|
||||||
|
|
||||||
s->NextSessionId = 1;
|
s->NextSessionId = 1;
|
||||||
|
|
||||||
if (sock_event != NULL)
|
|
||||||
{
|
|
||||||
s->SockEvent = sock_event;
|
|
||||||
AddRef(s->SockEvent->ref);
|
|
||||||
}
|
|
||||||
|
|
||||||
OvsLog(s, NULL, NULL, "LO_START");
|
OvsLog(s, NULL, NULL, "LO_START");
|
||||||
|
|
||||||
s->Dh = DhNewFromBits(DH_PARAM_BITS_DEFAULT);
|
s->Dh = DhNewFromBits(DH_PARAM_BITS_DEFAULT);
|
||||||
@ -2739,33 +2923,33 @@ void FreeOpenVpnServer(OPENVPN_SERVER *s)
|
|||||||
|
|
||||||
OvsLog(s, NULL, NULL, "LO_STOP");
|
OvsLog(s, NULL, NULL, "LO_STOP");
|
||||||
|
|
||||||
// Release the session list
|
// Release the sessions list
|
||||||
for (i = 0;i < LIST_NUM(s->SessionList);i++)
|
for (i = 0; i < LIST_NUM(s->SessionList); ++i)
|
||||||
{
|
{
|
||||||
OPENVPN_SESSION *se = LIST_DATA(s->SessionList, i);
|
OPENVPN_SESSION *se = LIST_DATA(s->SessionList, i);
|
||||||
|
|
||||||
OvsFreeSession(se);
|
OvsFreeSession(se);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReleaseList(s->SessionList);
|
ReleaseList(s->SessionList);
|
||||||
|
|
||||||
// Release the packet which is attempting to send
|
// Release the incoming packets list
|
||||||
for (i = 0;i < LIST_NUM(s->SendPacketList);i++)
|
for (i = 0; i < LIST_NUM(s->RecvPacketList); ++i)
|
||||||
|
{
|
||||||
|
UDPPACKET *p = LIST_DATA(s->RecvPacketList, i);
|
||||||
|
FreeUdpPacket(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReleaseList(s->RecvPacketList);
|
||||||
|
|
||||||
|
// Release the outgoing packets list
|
||||||
|
for (i = 0; i < LIST_NUM(s->SendPacketList); ++i)
|
||||||
{
|
{
|
||||||
UDPPACKET *p = LIST_DATA(s->SendPacketList, i);
|
UDPPACKET *p = LIST_DATA(s->SendPacketList, i);
|
||||||
|
|
||||||
FreeUdpPacket(p);
|
FreeUdpPacket(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReleaseList(s->SendPacketList);
|
ReleaseList(s->SendPacketList);
|
||||||
|
|
||||||
ReleaseCedar(s->Cedar);
|
|
||||||
|
|
||||||
if (s->SockEvent != NULL)
|
|
||||||
{
|
|
||||||
ReleaseSockEvent(s->SockEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
DhFree(s->Dh);
|
DhFree(s->Dh);
|
||||||
|
|
||||||
Free(s);
|
Free(s);
|
||||||
@ -2783,12 +2967,6 @@ void OpenVpnServerUdpListenerProc(UDPLISTENER *u, LIST *packet_list)
|
|||||||
|
|
||||||
us = (OPENVPN_SERVER_UDP *)u->Param;
|
us = (OPENVPN_SERVER_UDP *)u->Param;
|
||||||
|
|
||||||
if (OvsGetNoOpenVpnUdp())
|
|
||||||
{
|
|
||||||
// OpenVPN over UDP is disabled
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (us->OpenVpnServer != NULL)
|
if (us->OpenVpnServer != NULL)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
@ -2797,7 +2975,7 @@ void OpenVpnServerUdpListenerProc(UDPLISTENER *u, LIST *packet_list)
|
|||||||
ClearStr(us->Cedar->OpenVPNPublicPorts, sizeof(us->Cedar->OpenVPNPublicPorts));
|
ClearStr(us->Cedar->OpenVPNPublicPorts, sizeof(us->Cedar->OpenVPNPublicPorts));
|
||||||
}
|
}
|
||||||
|
|
||||||
OvsRecvPacket(us->OpenVpnServer, packet_list, OPENVPN_PROTOCOL_UDP);
|
OvsRecvPacket(us->OpenVpnServer, packet_list);
|
||||||
|
|
||||||
UdpListenerSendPackets(u, us->OpenVpnServer->SendPacketList);
|
UdpListenerSendPackets(u, us->OpenVpnServer->SendPacketList);
|
||||||
DeleteAll(us->OpenVpnServer->SendPacketList);
|
DeleteAll(us->OpenVpnServer->SendPacketList);
|
||||||
@ -2821,7 +2999,7 @@ OPENVPN_SERVER_UDP *NewOpenVpnServerUdp(CEDAR *cedar)
|
|||||||
AddRef(u->Cedar->ref);
|
AddRef(u->Cedar->ref);
|
||||||
|
|
||||||
// Create a UDP listener
|
// Create a UDP listener
|
||||||
u->UdpListener = NewUdpListener(OpenVpnServerUdpListenerProc, u, &cedar->Server->ListenIP);
|
u->UdpListener = NewUdpListenerEx(OpenVpnServerUdpListenerProc, u, &cedar->Server->ListenIP, OPENVPN_PROTOCOL_UDP);
|
||||||
|
|
||||||
// Create an OpenVPN server
|
// Create an OpenVPN server
|
||||||
u->OpenVpnServer = NewOpenVpnServer(cedar, u->UdpListener->Interrupts, u->UdpListener->Event);
|
u->OpenVpnServer = NewOpenVpnServer(cedar, u->UdpListener->Interrupts, u->UdpListener->Event);
|
||||||
@ -2896,269 +3074,3 @@ void FreeOpenVpnServerUdp(OPENVPN_SERVER_UDP *u)
|
|||||||
|
|
||||||
Free(u);
|
Free(u);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether it's OpenSSL protocol by looking the first receive buffer of the TCP
|
|
||||||
bool OvsCheckTcpRecvBufIfOpenVPNProtocol(UCHAR *buf, UINT size)
|
|
||||||
{
|
|
||||||
if (buf == NULL || size != 2)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buf[0] == 0x00 && buf[1] == 0x0E)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run the OpenVPN server in TCP mode
|
|
||||||
bool OvsPerformTcpServer(CEDAR *cedar, SOCK *sock)
|
|
||||||
{
|
|
||||||
OPENVPN_SERVER *s;
|
|
||||||
INTERRUPT_MANAGER *im;
|
|
||||||
SOCK_EVENT *se;
|
|
||||||
FIFO *tcp_recv_fifo;
|
|
||||||
FIFO *tcp_send_fifo;
|
|
||||||
UINT buf_size = (128 * 1024);
|
|
||||||
UCHAR *buf;
|
|
||||||
UINT64 giveup_time = Tick64() + (UINT64)OPENVPN_NEW_SESSION_DEADLINE_TIMEOUT;
|
|
||||||
LIST *ovs_recv_packet;
|
|
||||||
UINT i;
|
|
||||||
bool ret = false;
|
|
||||||
// Validate arguments
|
|
||||||
if (cedar == NULL || sock == NULL)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize
|
|
||||||
buf = Malloc(buf_size);
|
|
||||||
im = NewInterruptManager();
|
|
||||||
se = NewSockEvent();
|
|
||||||
SetTimeout(sock, TIMEOUT_INFINITE);
|
|
||||||
JoinSockToSockEvent(sock, se);
|
|
||||||
|
|
||||||
tcp_recv_fifo = NewFifoFast();
|
|
||||||
tcp_send_fifo = NewFifoFast();
|
|
||||||
|
|
||||||
ovs_recv_packet = NewListFast(NULL);
|
|
||||||
|
|
||||||
// Create an OpenVPN server
|
|
||||||
s = NewOpenVpnServer(cedar, im, se);
|
|
||||||
|
|
||||||
// Main loop
|
|
||||||
Debug("Entering OpenVPN TCP Server Main Loop.\n");
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
UINT next_interval;
|
|
||||||
bool disconnected = false;
|
|
||||||
UINT64 now = Tick64();
|
|
||||||
|
|
||||||
// Receive data from a TCP socket
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
UINT r = Recv(sock, buf, buf_size, false);
|
|
||||||
if (r == SOCK_LATER)
|
|
||||||
{
|
|
||||||
// Can not read any more
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (r == 0)
|
|
||||||
{
|
|
||||||
// Disconnected
|
|
||||||
disconnected = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Read
|
|
||||||
WriteFifo(tcp_recv_fifo, buf, r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Separate to a list of datagrams by interpreting the data received from the TCP socket
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
UINT r = FifoSize(tcp_recv_fifo);
|
|
||||||
if (r >= sizeof(USHORT))
|
|
||||||
{
|
|
||||||
void *ptr = FifoPtr(tcp_recv_fifo);
|
|
||||||
USHORT packet_size = READ_USHORT(ptr);
|
|
||||||
if (packet_size != 0 && packet_size <= OPENVPN_TCP_MAX_PACKET_SIZE)
|
|
||||||
{
|
|
||||||
UINT total_len = (UINT)packet_size + sizeof(USHORT);
|
|
||||||
if (r >= total_len)
|
|
||||||
{
|
|
||||||
if (ReadFifo(tcp_recv_fifo, buf, total_len) != total_len)
|
|
||||||
{
|
|
||||||
// Mismatch
|
|
||||||
disconnected = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Read one packet
|
|
||||||
UINT payload_len = packet_size;
|
|
||||||
UCHAR *payload_ptr = buf + sizeof(USHORT);
|
|
||||||
|
|
||||||
// Pass the packet to the OpenVPN server
|
|
||||||
Add(ovs_recv_packet, NewUdpPacket(&sock->RemoteIP, sock->RemotePort,
|
|
||||||
&sock->LocalIP, sock->LocalPort,
|
|
||||||
Clone(payload_ptr, payload_len), payload_len));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Non-arrival
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Invalid packet size
|
|
||||||
disconnected = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Non-arrival
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pass a list of received datagrams to the OpenVPN server
|
|
||||||
OvsRecvPacket(s, ovs_recv_packet, OPENVPN_PROTOCOL_TCP);
|
|
||||||
|
|
||||||
// Release the received packet list
|
|
||||||
for (i = 0;i < LIST_NUM(ovs_recv_packet);i++)
|
|
||||||
{
|
|
||||||
UDPPACKET *p = LIST_DATA(ovs_recv_packet, i);
|
|
||||||
|
|
||||||
FreeUdpPacket(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
DeleteAll(ovs_recv_packet);
|
|
||||||
|
|
||||||
// Store in the queue by getting a list of the datagrams to be transmitted from the OpenVPN server
|
|
||||||
for (i = 0;i < LIST_NUM(s->SendPacketList);i++)
|
|
||||||
{
|
|
||||||
UDPPACKET *p = LIST_DATA(s->SendPacketList, i);
|
|
||||||
// Store the size to the TCP send queue first
|
|
||||||
USHORT us = (USHORT)p->Size;
|
|
||||||
//Debug(" *** TCP SEND %u\n", us);
|
|
||||||
us = Endian16(us);
|
|
||||||
WriteFifo(tcp_send_fifo, &us, sizeof(USHORT));
|
|
||||||
|
|
||||||
// Write the data body
|
|
||||||
WriteFifo(tcp_send_fifo, p->Data, p->Size);
|
|
||||||
|
|
||||||
// Packet release
|
|
||||||
FreeUdpPacket(p);
|
|
||||||
}
|
|
||||||
DeleteAll(s->SendPacketList);
|
|
||||||
|
|
||||||
// Send data to the TCP socket
|
|
||||||
while (FifoSize(tcp_send_fifo) >= 1)
|
|
||||||
{
|
|
||||||
UINT r = Send(sock, FifoPtr(tcp_send_fifo), FifoSize(tcp_send_fifo), false);
|
|
||||||
|
|
||||||
if (r == SOCK_LATER)
|
|
||||||
{
|
|
||||||
// Can not write any more
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (r == 0)
|
|
||||||
{
|
|
||||||
// Disconnected
|
|
||||||
disconnected = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Wrote out
|
|
||||||
ReadFifo(tcp_send_fifo, NULL, r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FifoSize(tcp_send_fifo) > MAX_BUFFERING_PACKET_SIZE)
|
|
||||||
{
|
|
||||||
s->SupressSendPacket = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
s->SupressSendPacket = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s->DisconnectCount >= 1)
|
|
||||||
{
|
|
||||||
// Session disconnection has occurred on OpenVPN server-side
|
|
||||||
disconnected = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (giveup_time <= now)
|
|
||||||
{
|
|
||||||
UINT i;
|
|
||||||
UINT num_established_sessions = 0;
|
|
||||||
for (i = 0;i < LIST_NUM(s->SessionList);i++)
|
|
||||||
{
|
|
||||||
OPENVPN_SESSION *se = LIST_DATA(s->SessionList, i);
|
|
||||||
|
|
||||||
if (se->Established)
|
|
||||||
{
|
|
||||||
num_established_sessions++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (num_established_sessions == 0)
|
|
||||||
{
|
|
||||||
// If the number of sessions is 0 even if wait a certain period of time after the start of server, abort
|
|
||||||
disconnected = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (disconnected)
|
|
||||||
{
|
|
||||||
// Error or disconnect occurs
|
|
||||||
Debug("Breaking OpenVPN TCP Server Main Loop.\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait until the next event occurs
|
|
||||||
next_interval = GetNextIntervalForInterrupt(im);
|
|
||||||
next_interval = MIN(next_interval, UDPLISTENER_WAIT_INTERVAL);
|
|
||||||
WaitSockEvent(se, next_interval);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s != NULL && s->SessionEstablishedCount != 0)
|
|
||||||
{
|
|
||||||
ret = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Release the OpenVPN server
|
|
||||||
FreeOpenVpnServer(s);
|
|
||||||
|
|
||||||
// Release object
|
|
||||||
FreeInterruptManager(im);
|
|
||||||
ReleaseSockEvent(se);
|
|
||||||
ReleaseFifo(tcp_recv_fifo);
|
|
||||||
ReleaseFifo(tcp_send_fifo);
|
|
||||||
Free(buf);
|
|
||||||
|
|
||||||
// Release the received packet list
|
|
||||||
for (i = 0;i < LIST_NUM(ovs_recv_packet);i++)
|
|
||||||
{
|
|
||||||
UDPPACKET *p = LIST_DATA(ovs_recv_packet, i);
|
|
||||||
|
|
||||||
FreeUdpPacket(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReleaseList(ovs_recv_packet);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -188,6 +188,7 @@ struct OPENVPN_SERVER
|
|||||||
{
|
{
|
||||||
CEDAR *Cedar;
|
CEDAR *Cedar;
|
||||||
INTERRUPT_MANAGER *Interrupt; // Interrupt manager
|
INTERRUPT_MANAGER *Interrupt; // Interrupt manager
|
||||||
|
LIST *RecvPacketList; // Received packets list
|
||||||
LIST *SendPacketList; // Transmission packet list
|
LIST *SendPacketList; // Transmission packet list
|
||||||
LIST *SessionList; // Session list
|
LIST *SessionList; // Session list
|
||||||
UINT64 Now; // Current time
|
UINT64 Now; // Current time
|
||||||
@ -212,8 +213,18 @@ struct OPENVPN_SERVER_UDP
|
|||||||
// OpenVPN Default Client Option String
|
// OpenVPN Default Client Option String
|
||||||
#define OVPN_DEF_CLIENT_OPTION_STRING "dev-type tun,link-mtu 1500,tun-mtu 1500,cipher AES-128-CBC,auth SHA1,keysize 128,key-method 2,tls-client"
|
#define OVPN_DEF_CLIENT_OPTION_STRING "dev-type tun,link-mtu 1500,tun-mtu 1500,cipher AES-128-CBC,auth SHA1,keysize 128,key-method 2,tls-client"
|
||||||
|
|
||||||
|
|
||||||
//// Function prototype
|
//// Function prototype
|
||||||
|
PROTO_IMPL *OvsGetProtoImpl();
|
||||||
|
bool OvsInit(void **param, CEDAR *cedar, INTERRUPT_MANAGER *im, SOCK_EVENT *se);
|
||||||
|
void OvsFree(void *param);
|
||||||
|
char *OvsName();
|
||||||
|
UINT OvsSupportedModes();
|
||||||
|
bool OvsIsPacketForMe(const UCHAR *buf, const UINT size);
|
||||||
|
bool OvsProcessData(void *param, TCP_RAW_DATA *received_data, FIFO *data_to_send);
|
||||||
|
void OvsBufferLimit(void *param, const bool reached);
|
||||||
|
bool OvsIsOk(void *param);
|
||||||
|
UINT OvsEstablishedSessions(void *param);
|
||||||
|
|
||||||
OPENVPN_SERVER_UDP *NewOpenVpnServerUdp(CEDAR *cedar);
|
OPENVPN_SERVER_UDP *NewOpenVpnServerUdp(CEDAR *cedar);
|
||||||
void FreeOpenVpnServerUdp(OPENVPN_SERVER_UDP *u);
|
void FreeOpenVpnServerUdp(OPENVPN_SERVER_UDP *u);
|
||||||
void OpenVpnServerUdpListenerProc(UDPLISTENER *u, LIST *packet_list);
|
void OpenVpnServerUdpListenerProc(UDPLISTENER *u, LIST *packet_list);
|
||||||
@ -221,8 +232,8 @@ void OvsApplyUdpPortList(OPENVPN_SERVER_UDP *u, char *port_list, IP *listen_ip);
|
|||||||
|
|
||||||
OPENVPN_SERVER *NewOpenVpnServer(CEDAR *cedar, INTERRUPT_MANAGER *interrupt, SOCK_EVENT *sock_event);
|
OPENVPN_SERVER *NewOpenVpnServer(CEDAR *cedar, INTERRUPT_MANAGER *interrupt, SOCK_EVENT *sock_event);
|
||||||
void FreeOpenVpnServer(OPENVPN_SERVER *s);
|
void FreeOpenVpnServer(OPENVPN_SERVER *s);
|
||||||
void OvsRecvPacket(OPENVPN_SERVER *s, LIST *recv_packet_list, UINT protocol);
|
void OvsRecvPacket(OPENVPN_SERVER *s, LIST *recv_packet_list);
|
||||||
void OvsProceccRecvPacket(OPENVPN_SERVER *s, UDPPACKET *p, UINT protocol);
|
void OvsProceccRecvPacket(OPENVPN_SERVER *s, UDPPACKET *p);
|
||||||
int OvsCompareSessionList(void *p1, void *p2);
|
int OvsCompareSessionList(void *p1, void *p2);
|
||||||
OPENVPN_SESSION *OvsSearchSession(OPENVPN_SERVER *s, IP *server_ip, UINT server_port, IP *client_ip, UINT client_port, UINT protocol);
|
OPENVPN_SESSION *OvsSearchSession(OPENVPN_SERVER *s, IP *server_ip, UINT server_port, IP *client_ip, UINT client_port, UINT protocol);
|
||||||
OPENVPN_SESSION *OvsNewSession(OPENVPN_SERVER *s, IP *server_ip, UINT server_port, IP *client_ip, UINT client_port, UINT protocol);
|
OPENVPN_SESSION *OvsNewSession(OPENVPN_SERVER *s, IP *server_ip, UINT server_port, IP *client_ip, UINT client_port, UINT protocol);
|
||||||
@ -264,16 +275,7 @@ UINT OvsCalcTcpMss(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_CHANNEL *c);
|
|||||||
|
|
||||||
CIPHER *OvsGetCipher(char *name);
|
CIPHER *OvsGetCipher(char *name);
|
||||||
MD *OvsGetMd(char *name);
|
MD *OvsGetMd(char *name);
|
||||||
bool OvsCheckTcpRecvBufIfOpenVPNProtocol(UCHAR *buf, UINT size);
|
|
||||||
|
|
||||||
bool OvsPerformTcpServer(CEDAR *cedar, SOCK *sock);
|
|
||||||
|
|
||||||
void OvsSetReplyForVgsPollEnable(bool b);
|
|
||||||
|
|
||||||
bool OvsGetNoOpenVpnTcp();
|
|
||||||
|
|
||||||
void OpenVpnServerUdpSetDhParam(OPENVPN_SERVER_UDP *u, DH_CTX *dh);
|
void OpenVpnServerUdpSetDhParam(OPENVPN_SERVER_UDP *u, DH_CTX *dh);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif // PROTO_OPENVPN_H
|
#endif // PROTO_OPENVPN_H
|
||||||
|
@ -6412,7 +6412,7 @@ bool ServerDownloadSignature(CONNECTION *c, char **error_detail_str)
|
|||||||
{
|
{
|
||||||
bool sstp_ret;
|
bool sstp_ret;
|
||||||
// Accept the SSTP connection
|
// Accept the SSTP connection
|
||||||
c->Type = CONNECTION_TYPE_SSTP;
|
c->Type = CONNECTION_TYPE_OTHER;
|
||||||
|
|
||||||
sstp_ret = AcceptSstp(c);
|
sstp_ret = AcceptSstp(c);
|
||||||
|
|
||||||
|
@ -421,6 +421,7 @@ typedef struct TUBEPAIR_DATA TUBEPAIR_DATA;
|
|||||||
typedef struct UDPLISTENER UDPLISTENER;
|
typedef struct UDPLISTENER UDPLISTENER;
|
||||||
typedef struct UDPLISTENER_SOCK UDPLISTENER_SOCK;
|
typedef struct UDPLISTENER_SOCK UDPLISTENER_SOCK;
|
||||||
typedef struct UDPPACKET UDPPACKET;
|
typedef struct UDPPACKET UDPPACKET;
|
||||||
|
typedef struct TCP_RAW_DATA TCP_RAW_DATA;
|
||||||
typedef struct INTERRUPT_MANAGER INTERRUPT_MANAGER;
|
typedef struct INTERRUPT_MANAGER INTERRUPT_MANAGER;
|
||||||
typedef struct TUBE_FLUSH_LIST TUBE_FLUSH_LIST;
|
typedef struct TUBE_FLUSH_LIST TUBE_FLUSH_LIST;
|
||||||
typedef struct ICMP_RESULT ICMP_RESULT;
|
typedef struct ICMP_RESULT ICMP_RESULT;
|
||||||
|
@ -18792,6 +18792,8 @@ LABEL_FATAL_ERROR:
|
|||||||
p->SrcPort = p->DestPort = MAKE_SPECIAL_PORT(50);
|
p->SrcPort = p->DestPort = MAKE_SPECIAL_PORT(50);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p->Type = u->PacketType;
|
||||||
|
|
||||||
Add(recv_list, p);
|
Add(recv_list, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -18980,6 +18982,40 @@ UDPLISTENER_SOCK *DetermineUdpSocketForSending(UDPLISTENER *u, UDPPACKET *p)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FreeTcpRawData(TCP_RAW_DATA *trd)
|
||||||
|
{
|
||||||
|
// Validate arguments
|
||||||
|
if (trd == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReleaseFifo(trd->Data);
|
||||||
|
Free(trd);
|
||||||
|
}
|
||||||
|
|
||||||
|
TCP_RAW_DATA *NewTcpRawData(IP *src_ip, UINT src_port, IP *dst_ip, UINT dst_port)
|
||||||
|
{
|
||||||
|
TCP_RAW_DATA *trd;
|
||||||
|
// Validate arguments
|
||||||
|
if (dst_ip == NULL || dst_port == 0)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
trd = ZeroMalloc(sizeof(TCP_RAW_DATA));
|
||||||
|
|
||||||
|
Copy(&trd->SrcIP, src_ip, sizeof(IP));
|
||||||
|
trd->SrcPort = src_port;
|
||||||
|
|
||||||
|
Copy(&trd->DstIP, dst_ip, sizeof(IP));
|
||||||
|
trd->DstPort = dst_port;
|
||||||
|
|
||||||
|
trd->Data = NewFifoFast();
|
||||||
|
|
||||||
|
return trd;
|
||||||
|
}
|
||||||
|
|
||||||
// Release of the UDP packet
|
// Release of the UDP packet
|
||||||
void FreeUdpPacket(UDPPACKET *p)
|
void FreeUdpPacket(UDPPACKET *p)
|
||||||
{
|
{
|
||||||
@ -19050,6 +19086,11 @@ void UdpListenerSendPackets(UDPLISTENER *u, LIST *packet_list)
|
|||||||
|
|
||||||
// Creating a UDP listener
|
// Creating a UDP listener
|
||||||
UDPLISTENER *NewUdpListener(UDPLISTENER_RECV_PROC *recv_proc, void *param, IP *listen_ip)
|
UDPLISTENER *NewUdpListener(UDPLISTENER_RECV_PROC *recv_proc, void *param, IP *listen_ip)
|
||||||
|
{
|
||||||
|
return NewUdpListenerEx(recv_proc, param, listen_ip, INFINITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
UDPLISTENER *NewUdpListenerEx(UDPLISTENER_RECV_PROC *recv_proc, void *param, IP *listen_ip, UINT packet_type)
|
||||||
{
|
{
|
||||||
UDPLISTENER *u;
|
UDPLISTENER *u;
|
||||||
// Validate arguments
|
// Validate arguments
|
||||||
@ -19061,6 +19102,7 @@ UDPLISTENER *NewUdpListener(UDPLISTENER_RECV_PROC *recv_proc, void *param, IP *l
|
|||||||
u = ZeroMalloc(sizeof(UDPLISTENER));
|
u = ZeroMalloc(sizeof(UDPLISTENER));
|
||||||
|
|
||||||
u->Param = param;
|
u->Param = param;
|
||||||
|
u->PacketType = packet_type;
|
||||||
|
|
||||||
u->PortList = NewList(NULL);
|
u->PortList = NewList(NULL);
|
||||||
u->Event = NewSockEvent();
|
u->Event = NewSockEvent();
|
||||||
|
@ -456,6 +456,16 @@ struct TUBEPAIR_DATA
|
|||||||
SOCK_EVENT *SockEvent1, *SockEvent2; // SockEvent
|
SOCK_EVENT *SockEvent1, *SockEvent2; // SockEvent
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TCP raw data
|
||||||
|
struct TCP_RAW_DATA
|
||||||
|
{
|
||||||
|
IP SrcIP; // Source IP address
|
||||||
|
IP DstIP; // Destination IP address
|
||||||
|
UINT SrcPort; // Source port
|
||||||
|
UINT DstPort; // Destination port
|
||||||
|
FIFO *Data; // Data body
|
||||||
|
};
|
||||||
|
|
||||||
// UDP listener socket entry
|
// UDP listener socket entry
|
||||||
struct UDPLISTENER_SOCK
|
struct UDPLISTENER_SOCK
|
||||||
{
|
{
|
||||||
@ -496,6 +506,7 @@ struct UDPLISTENER
|
|||||||
UINT64 LastCheckTick; // Time which the socket list was checked last
|
UINT64 LastCheckTick; // Time which the socket list was checked last
|
||||||
UDPLISTENER_RECV_PROC *RecvProc; // Receive procedure
|
UDPLISTENER_RECV_PROC *RecvProc; // Receive procedure
|
||||||
LIST *SendPacketList; // Transmission packet list
|
LIST *SendPacketList; // Transmission packet list
|
||||||
|
UINT PacketType; // The type to set when creating an UDPPACKET
|
||||||
void *Param; // Parameters
|
void *Param; // Parameters
|
||||||
INTERRUPT_MANAGER *Interrupts; // Interrupt manager
|
INTERRUPT_MANAGER *Interrupts; // Interrupt manager
|
||||||
bool HostIPAddressListChanged; // IP address list of the host has changed
|
bool HostIPAddressListChanged; // IP address list of the host has changed
|
||||||
@ -1405,12 +1416,15 @@ int CmpIpAddressList(void *p1, void *p2);
|
|||||||
UINT64 GetHostIPAddressListHash();
|
UINT64 GetHostIPAddressListHash();
|
||||||
|
|
||||||
UDPLISTENER *NewUdpListener(UDPLISTENER_RECV_PROC *recv_proc, void *param, IP *listen_ip);
|
UDPLISTENER *NewUdpListener(UDPLISTENER_RECV_PROC *recv_proc, void *param, IP *listen_ip);
|
||||||
|
UDPLISTENER *NewUdpListenerEx(UDPLISTENER_RECV_PROC *recv_proc, void *param, IP *listen_ip, UINT packet_type);
|
||||||
void UdpListenerThread(THREAD *thread, void *param);
|
void UdpListenerThread(THREAD *thread, void *param);
|
||||||
void FreeUdpListener(UDPLISTENER *u);
|
void FreeUdpListener(UDPLISTENER *u);
|
||||||
void AddPortToUdpListener(UDPLISTENER *u, UINT port);
|
void AddPortToUdpListener(UDPLISTENER *u, UINT port);
|
||||||
void DeletePortFromUdpListener(UDPLISTENER *u, UINT port);
|
void DeletePortFromUdpListener(UDPLISTENER *u, UINT port);
|
||||||
void DeleteAllPortFromUdpListener(UDPLISTENER *u);
|
void DeleteAllPortFromUdpListener(UDPLISTENER *u);
|
||||||
void UdpListenerSendPackets(UDPLISTENER *u, LIST *packet_list);
|
void UdpListenerSendPackets(UDPLISTENER *u, LIST *packet_list);
|
||||||
|
TCP_RAW_DATA *NewTcpRawData(IP *src_ip, UINT src_port, IP *dst_ip, UINT dst_port);
|
||||||
|
void FreeTcpRawData(TCP_RAW_DATA *trd);
|
||||||
UDPPACKET *NewUdpPacket(IP *src_ip, UINT src_port, IP *dst_ip, UINT dst_port, void *data, UINT size);
|
UDPPACKET *NewUdpPacket(IP *src_ip, UINT src_port, IP *dst_ip, UINT dst_port, void *data, UINT size);
|
||||||
void FreeUdpPacket(UDPPACKET *p);
|
void FreeUdpPacket(UDPPACKET *p);
|
||||||
UDPLISTENER_SOCK *DetermineUdpSocketForSending(UDPLISTENER *u, UDPPACKET *p);
|
UDPLISTENER_SOCK *DetermineUdpSocketForSending(UDPLISTENER *u, UDPPACKET *p);
|
||||||
|
Loading…
Reference in New Issue
Block a user