1
0
mirror of https://github.com/SoftEtherVPN/SoftEtherVPN.git synced 2024-11-10 03:30:39 +03:00

Cedar: prepare Proto for UDP support

- An additional parameter is added to IsPacketForMe(), used to specify the protocol type (currently either TCP or UDP).
- SupportedModes() is dropped because it's now redundant.
- IsOk() and EstablishedSessions() are dropped because error checking should be handled by the implementation.
- ProtoImplDetect() now takes a buffer and its size rather than a SOCK, so that it can be used to detect UDP protocols.
- The OpenVPN toggle check is moved to ProtoImplDetect(), so that we don't have to duplicate it once UDP support is implemented.
This commit is contained in:
Davide Beatrici 2020-05-11 07:07:04 +02:00
parent 7e8b3c0b39
commit 667108319d
4 changed files with 71 additions and 111 deletions

View File

@ -65,31 +65,34 @@ bool ProtoImplAdd(PROTO *proto, PROTO_IMPL *impl) {
return true; return true;
} }
PROTO_IMPL *ProtoImplDetect(PROTO *proto, SOCK *sock) PROTO_IMPL *ProtoImplDetect(PROTO *proto, const PROTO_MODE mode, const UCHAR *data, const UINT size)
{ {
UCHAR buf[PROTO_CHECK_BUFFER_SIZE];
UINT i; UINT i;
if (proto == NULL || sock == NULL) if (proto == NULL || data == NULL || size == 0)
{ {
return NULL; return NULL;
} }
if (Peek(sock, buf, sizeof(buf)) == 0)
{
return false;
}
for (i = 0; i < LIST_NUM(proto->Impls); ++i) for (i = 0; i < LIST_NUM(proto->Impls); ++i)
{ {
PROTO_IMPL *impl = LIST_DATA(proto->Impls, i); PROTO_IMPL *impl = LIST_DATA(proto->Impls, i);
if (impl->IsPacketForMe(buf, sizeof(buf))) if (impl->IsPacketForMe(mode, data, size) == false)
{ {
Debug("ProtoImplDetect(): %s detected\n", impl->Name()); continue;
return impl;
} }
if (StrCmp(impl->Name(), "OpenVPN") == 0 && proto->Cedar->Server->DisableOpenVPNServer)
{
Debug("ProtoImplDetect(): OpenVPN detected, but it's disabled\n");
continue;
}
Debug("ProtoImplDetect(): %s detected\n", impl->Name());
return impl;
} }
Debug("ProtoImplDetect(): unrecognized protocol\n");
return NULL; return NULL;
} }
@ -104,29 +107,23 @@ bool ProtoHandleConnection(PROTO *proto, SOCK *sock)
INTERRUPT_MANAGER *im; INTERRUPT_MANAGER *im;
SOCK_EVENT *se; SOCK_EVENT *se;
const UINT64 giveup = Tick64() + (UINT64)OPENVPN_NEW_SESSION_DEADLINE_TIMEOUT;
if (proto == NULL || sock == NULL) if (proto == NULL || sock == NULL)
{ {
return false; return false;
} }
impl = ProtoImplDetect(proto, sock);
if (impl == NULL)
{ {
Debug("ProtoHandleConnection(): unrecognized protocol\n"); UCHAR tmp[PROTO_CHECK_BUFFER_SIZE];
return false; if (Peek(sock, tmp, sizeof(tmp)) == 0)
} {
return false;
}
if (StrCmp(impl->Name(), "OpenVPN") == 0 && proto->Cedar->Server->DisableOpenVPNServer == true) impl = ProtoImplDetect(proto, PROTO_MODE_TCP, tmp, sizeof(tmp));
{ if (impl == NULL)
Debug("ProtoHandleConnection(): OpenVPN detected, but it's disabled\n"); {
return false; return false;
} }
if ((impl->SupportedModes() & PROTO_MODE_TCP) == false)
{
return false;
} }
im = NewInterruptManager(); im = NewInterruptManager();
@ -208,23 +205,6 @@ bool ProtoHandleConnection(PROTO *proto, SOCK *sock)
impl->BufferLimit(impl_data, FifoSize(send_fifo) > MAX_BUFFERING_PACKET_SIZE); 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) if (stop)
{ {
// Error or disconnection occurs // Error or disconnection occurs

View File

@ -7,8 +7,12 @@
#define PROTO_TCP_BUFFER_SIZE (128 * 1024) #define PROTO_TCP_BUFFER_SIZE (128 * 1024)
#define PROTO_MODE_TCP 1 typedef enum PROTO_MODE
#define PROTO_MODE_UDP 2 {
PROTO_MODE_UNKNOWN = 0,
PROTO_MODE_TCP = 1,
PROTO_MODE_UDP = 2
} PROTO_MODE;
typedef struct PROTO typedef struct PROTO
{ {
@ -21,12 +25,9 @@ typedef struct PROTO_IMPL
bool (*Init)(void **param, CEDAR *cedar, INTERRUPT_MANAGER *im, SOCK_EVENT *se); bool (*Init)(void **param, CEDAR *cedar, INTERRUPT_MANAGER *im, SOCK_EVENT *se);
void (*Free)(void *param); void (*Free)(void *param);
char *(*Name)(); char *(*Name)();
UINT (*SupportedModes)(); bool (*IsPacketForMe)(const PROTO_MODE mode, const UCHAR *data, const UINT size);
bool (*IsPacketForMe)(const UCHAR *data, const UINT size);
bool (*ProcessData)(void *param, TCP_RAW_DATA *received_data, FIFO *data_to_send); bool (*ProcessData)(void *param, TCP_RAW_DATA *received_data, FIFO *data_to_send);
void (*BufferLimit)(void *param, const bool reached); void (*BufferLimit)(void *param, const bool reached);
bool (*IsOk)(void *param);
UINT (*EstablishedSessions)(void *param);
} PROTO_IMPL; } PROTO_IMPL;
int ProtoImplCompare(void *p1, void *p2); int ProtoImplCompare(void *p1, void *p2);
@ -35,7 +36,7 @@ PROTO *ProtoNew(CEDAR *cedar);
void ProtoDelete(PROTO *proto); void ProtoDelete(PROTO *proto);
bool ProtoImplAdd(PROTO *proto, PROTO_IMPL *impl); bool ProtoImplAdd(PROTO *proto, PROTO_IMPL *impl);
PROTO_IMPL *ProtoImplDetect(PROTO *proto, SOCK *sock); PROTO_IMPL *ProtoImplDetect(PROTO *proto, const PROTO_MODE mode, const UCHAR *data, const UINT size);
bool ProtoHandleConnection(PROTO *proto, SOCK *sock); bool ProtoHandleConnection(PROTO *proto, SOCK *sock);

View File

@ -21,12 +21,9 @@ PROTO_IMPL *OvsGetProtoImpl()
OvsInit, OvsInit,
OvsFree, OvsFree,
OvsName, OvsName,
OvsSupportedModes,
OvsIsPacketForMe, OvsIsPacketForMe,
OvsProcessData, OvsProcessData,
OvsBufferLimit, OvsBufferLimit,
OvsIsOk,
OvsEstablishedSessions
}; };
return &impl; return &impl;
@ -55,22 +52,30 @@ char *OvsName()
return "OpenVPN"; return "OpenVPN";
} }
// Return the supported modes (TCP & UDP)
UINT OvsSupportedModes()
{
return PROTO_MODE_TCP | PROTO_MODE_UDP;
}
// Check whether it's an OpenVPN packet // Check whether it's an OpenVPN packet
bool OvsIsPacketForMe(const UCHAR *buf, const UINT size) bool OvsIsPacketForMe(const PROTO_MODE mode, const UCHAR *data, const UINT size)
{ {
if (buf == NULL || size != 2) if (mode == PROTO_MODE_TCP)
{ {
return false; if (data == NULL || size < 2)
} {
return false;
}
if (buf[0] == 0x00 && buf[1] == 0x0E) if (data[0] == 0x00 && data[1] == 0x0E)
{
return true;
}
}
else if (mode == PROTO_MODE_UDP)
{ {
OPENVPN_PACKET *packet = OvsParsePacket(data, size);
if (packet == NULL)
{
return false;
}
OvsFreePacket(packet);
return true; return true;
} }
@ -81,16 +86,14 @@ bool OvsProcessData(void *param, TCP_RAW_DATA *received_data, FIFO *data_to_send
{ {
bool ret = true; bool ret = true;
UINT i; UINT i;
OPENVPN_SERVER *server; OPENVPN_SERVER *server = param;
UCHAR buf[OPENVPN_TCP_MAX_PACKET_SIZE]; UCHAR buf[OPENVPN_TCP_MAX_PACKET_SIZE];
if (param == NULL || received_data == NULL || data_to_send == NULL) if (server == NULL || received_data == NULL || data_to_send == NULL)
{ {
return false; return false;
} }
server = param;
// Separate to a list of datagrams by interpreting the data received from the TCP socket // Separate to a list of datagrams by interpreting the data received from the TCP socket
while (true) while (true)
{ {
@ -166,6 +169,21 @@ bool OvsProcessData(void *param, TCP_RAW_DATA *received_data, FIFO *data_to_send
DeleteAll(server->SendPacketList); DeleteAll(server->SendPacketList);
if (server->Giveup <= server->Now)
{
for (UINT i = 0; i < LIST_NUM(server->SessionList); ++i)
{
OPENVPN_SESSION *se = LIST_DATA(server->SessionList, i);
if (se->Established)
{
return ret && server->DisconnectCount < 1;
}
}
return false;
}
return ret; return ret;
} }
@ -179,46 +197,6 @@ void OvsBufferLimit(void *param, const bool reached)
((OPENVPN_SERVER *)param)->SupressSendPacket = reached; ((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, ...)
{ {
@ -2924,6 +2902,7 @@ OPENVPN_SERVER *NewOpenVpnServer(CEDAR *cedar, INTERRUPT_MANAGER *interrupt, SOC
s->SendPacketList = NewListFast(NULL); s->SendPacketList = NewListFast(NULL);
s->Now = Tick64(); s->Now = Tick64();
s->Giveup = s->Now + OPENVPN_NEW_SESSION_DEADLINE_TIMEOUT;
s->NextSessionId = 1; s->NextSessionId = 1;

View File

@ -194,6 +194,7 @@ struct OPENVPN_SERVER
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
UINT64 Giveup; // Session establishment deadline
SOCK_EVENT *SockEvent; // Socket event SOCK_EVENT *SockEvent; // Socket event
UCHAR TmpBuf[OPENVPN_TMP_BUFFER_SIZE]; // Temporary buffer UCHAR TmpBuf[OPENVPN_TMP_BUFFER_SIZE]; // Temporary buffer
UINT DisconnectCount; // The number of session lost that have occurred so far UINT DisconnectCount; // The number of session lost that have occurred so far
@ -220,8 +221,7 @@ PROTO_IMPL *OvsGetProtoImpl();
bool OvsInit(void **param, CEDAR *cedar, INTERRUPT_MANAGER *im, SOCK_EVENT *se); bool OvsInit(void **param, CEDAR *cedar, INTERRUPT_MANAGER *im, SOCK_EVENT *se);
void OvsFree(void *param); void OvsFree(void *param);
char *OvsName(); char *OvsName();
UINT OvsSupportedModes(); bool OvsIsPacketForMe(const PROTO_MODE mode, const UCHAR *data, const UINT size);
bool OvsIsPacketForMe(const UCHAR *buf, const UINT size);
bool OvsProcessData(void *param, TCP_RAW_DATA *received_data, FIFO *data_to_send); bool OvsProcessData(void *param, TCP_RAW_DATA *received_data, FIFO *data_to_send);
void OvsBufferLimit(void *param, const bool reached); void OvsBufferLimit(void *param, const bool reached);
bool OvsIsOk(void *param); bool OvsIsOk(void *param);