From 667108319ddd064ff4c634214362d3f93287b61d Mon Sep 17 00:00:00 2001 From: Davide Beatrici Date: Mon, 11 May 2020 07:07:04 +0200 Subject: [PATCH] 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. --- src/Cedar/Proto.c | 68 ++++++++++------------------ src/Cedar/Proto.h | 15 ++++--- src/Cedar/Proto_OpenVPN.c | 95 +++++++++++++++------------------------ src/Cedar/Proto_OpenVPN.h | 4 +- 4 files changed, 71 insertions(+), 111 deletions(-) diff --git a/src/Cedar/Proto.c b/src/Cedar/Proto.c index 482aa85a..b15f8e52 100644 --- a/src/Cedar/Proto.c +++ b/src/Cedar/Proto.c @@ -65,31 +65,34 @@ bool ProtoImplAdd(PROTO *proto, PROTO_IMPL *impl) { 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; - if (proto == NULL || sock == NULL) + if (proto == NULL || data == NULL || size == 0) { return NULL; } - if (Peek(sock, buf, sizeof(buf)) == 0) - { - return false; - } - for (i = 0; i < LIST_NUM(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()); - return impl; + continue; } + + 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; } @@ -104,29 +107,23 @@ bool ProtoHandleConnection(PROTO *proto, SOCK *sock) INTERRUPT_MANAGER *im; SOCK_EVENT *se; - const UINT64 giveup = Tick64() + (UINT64)OPENVPN_NEW_SESSION_DEADLINE_TIMEOUT; - if (proto == NULL || sock == NULL) { return false; } - impl = ProtoImplDetect(proto, sock); - if (impl == NULL) { - Debug("ProtoHandleConnection(): unrecognized protocol\n"); - return false; - } + UCHAR tmp[PROTO_CHECK_BUFFER_SIZE]; + if (Peek(sock, tmp, sizeof(tmp)) == 0) + { + return false; + } - if (StrCmp(impl->Name(), "OpenVPN") == 0 && proto->Cedar->Server->DisableOpenVPNServer == true) - { - Debug("ProtoHandleConnection(): OpenVPN detected, but it's disabled\n"); - return false; - } - - if ((impl->SupportedModes() & PROTO_MODE_TCP) == false) - { - return false; + impl = ProtoImplDetect(proto, PROTO_MODE_TCP, tmp, sizeof(tmp)); + if (impl == NULL) + { + return false; + } } im = NewInterruptManager(); @@ -208,23 +205,6 @@ bool ProtoHandleConnection(PROTO *proto, SOCK *sock) 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 diff --git a/src/Cedar/Proto.h b/src/Cedar/Proto.h index 26b3c1ee..0fcc5e69 100644 --- a/src/Cedar/Proto.h +++ b/src/Cedar/Proto.h @@ -7,8 +7,12 @@ #define PROTO_TCP_BUFFER_SIZE (128 * 1024) -#define PROTO_MODE_TCP 1 -#define PROTO_MODE_UDP 2 +typedef enum PROTO_MODE +{ + PROTO_MODE_UNKNOWN = 0, + PROTO_MODE_TCP = 1, + PROTO_MODE_UDP = 2 +} PROTO_MODE; typedef struct PROTO { @@ -21,12 +25,9 @@ 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 (*IsPacketForMe)(const PROTO_MODE mode, 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; int ProtoImplCompare(void *p1, void *p2); @@ -35,7 +36,7 @@ PROTO *ProtoNew(CEDAR *cedar); void ProtoDelete(PROTO *proto); 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); diff --git a/src/Cedar/Proto_OpenVPN.c b/src/Cedar/Proto_OpenVPN.c index f61c3de2..11ca8266 100644 --- a/src/Cedar/Proto_OpenVPN.c +++ b/src/Cedar/Proto_OpenVPN.c @@ -21,12 +21,9 @@ PROTO_IMPL *OvsGetProtoImpl() OvsInit, OvsFree, OvsName, - OvsSupportedModes, OvsIsPacketForMe, OvsProcessData, OvsBufferLimit, - OvsIsOk, - OvsEstablishedSessions }; return &impl; @@ -55,22 +52,30 @@ 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) +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; } @@ -81,16 +86,14 @@ bool OvsProcessData(void *param, TCP_RAW_DATA *received_data, FIFO *data_to_send { bool ret = true; UINT i; - OPENVPN_SERVER *server; + OPENVPN_SERVER *server = param; 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; } - server = param; - // Separate to a list of datagrams by interpreting the data received from the TCP socket while (true) { @@ -166,6 +169,21 @@ bool OvsProcessData(void *param, TCP_RAW_DATA *received_data, FIFO *data_to_send 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; } @@ -179,46 +197,6 @@ void OvsBufferLimit(void *param, const bool 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 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->Now = Tick64(); + s->Giveup = s->Now + OPENVPN_NEW_SESSION_DEADLINE_TIMEOUT; s->NextSessionId = 1; diff --git a/src/Cedar/Proto_OpenVPN.h b/src/Cedar/Proto_OpenVPN.h index 8fae45f3..7c88e6ce 100644 --- a/src/Cedar/Proto_OpenVPN.h +++ b/src/Cedar/Proto_OpenVPN.h @@ -194,6 +194,7 @@ struct OPENVPN_SERVER LIST *SendPacketList; // Transmission packet list LIST *SessionList; // Session list UINT64 Now; // Current time + UINT64 Giveup; // Session establishment deadline SOCK_EVENT *SockEvent; // Socket event UCHAR TmpBuf[OPENVPN_TMP_BUFFER_SIZE]; // Temporary buffer 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); void OvsFree(void *param); char *OvsName(); -UINT OvsSupportedModes(); -bool OvsIsPacketForMe(const UCHAR *buf, const UINT size); +bool OvsIsPacketForMe(const PROTO_MODE mode, const UCHAR *data, 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);