mirror of
https://github.com/SoftEtherVPN/SoftEtherVPN.git
synced 2024-09-19 18:20:40 +03:00
dd1eebdbed
Please note that the implementation is not 100% conformant to the protocol whitepaper (https://www.wireguard.com/papers/wireguard.pdf). More specifically: all peers are expected to send a handshake initiation once the current keypair is about to expire or is expired. I decided not to do that because our implementation is meant to act as a server only. A true WireGuard peer acts, instead, as both a client and a server. Once the keypair is expired, we immediately delete the session. The cookie mechanism can be implemented in future. As for authentication: unfortunately using the already existing methods is not possible due to the protocol not providing a way to send strings to a peer. That's because WireGuard doesn't have a concept of "users": it identifies a peer through the public key, which is determined using the source address. As a solution, this commit adds a special authentication method: once we receive the handshake initiation message and decrypt the peer's public key, we check whether it's in the allowed key list. If it is, we retrieve the associated Virtual Hub and user; if the hub exists and the user is in it, the authentication is successful. The allowed key list is stored in the configuration file like this: declare WireGuardKeyList { declare 96oA7iMvjn7oXiG3ghBDPaSUytT75uXceLV+Fx3XMlM= { string Hub DEFAULT string User user } }
1627 lines
27 KiB
C
1627 lines
27 KiB
C
// SoftEther VPN Source Code - Developer Edition Master Branch
|
|
// Cedar Communication Module
|
|
|
|
|
|
// Cedar.c
|
|
// Cedar Communication Module
|
|
|
|
|
|
#include "CedarPch.h"
|
|
|
|
static UINT init_cedar_counter = 0;
|
|
static REF *cedar_log_ref = NULL;
|
|
static LOG *cedar_log;
|
|
|
|
// Check whether there is any EAP-enabled RADIUS configuration
|
|
bool CedarIsThereAnyEapEnabledRadiusConfig(CEDAR *c)
|
|
{
|
|
bool ret = false;
|
|
UINT i;
|
|
if (c == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
LockHubList(c);
|
|
{
|
|
for (i = 0;i < LIST_NUM(c->HubList);i++)
|
|
{
|
|
HUB *hub = LIST_DATA(c->HubList, i);
|
|
|
|
if (hub->RadiusConvertAllMsChapv2AuthRequestToEap)
|
|
{
|
|
ret = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
UnlockHubList(c);
|
|
|
|
return ret;
|
|
}
|
|
|
|
// Get build date of current code
|
|
UINT64 GetCurrentBuildDate()
|
|
{
|
|
SYSTEMTIME st;
|
|
|
|
Zero(&st, sizeof(st));
|
|
|
|
st.wYear = BUILD_DATE_Y;
|
|
st.wMonth = BUILD_DATE_M;
|
|
st.wDay = BUILD_DATE_D;
|
|
st.wHour = BUILD_DATE_HO;
|
|
st.wMinute = BUILD_DATE_MI;
|
|
st.wSecond = BUILD_DATE_SE;
|
|
|
|
return SystemToUINT64(&st);
|
|
}
|
|
|
|
// Check current windows version is supported
|
|
bool IsSupportedWinVer(RPC_WINVER *v)
|
|
{
|
|
// Validate arguments
|
|
if (v == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (v->IsWindows == false)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (v->IsNT == false)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (v->IsBeta)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (v->VerMajor <= 4)
|
|
{
|
|
// Windows NT
|
|
return true;
|
|
}
|
|
|
|
if (v->VerMajor == 5 && v->VerMinor == 0)
|
|
{
|
|
// Windows 2000
|
|
if (v->ServicePack <= 4)
|
|
{
|
|
// SP4 or earlier
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (v->VerMajor == 5 && v->VerMinor == 1)
|
|
{
|
|
// Windows XP x86
|
|
if (v->ServicePack <= 3)
|
|
{
|
|
// SP3 or earlier
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (v->VerMajor == 5 && v->VerMinor == 2)
|
|
{
|
|
// Windows XP x64, Windows Server 2003
|
|
if (v->ServicePack <= 2)
|
|
{
|
|
// SP2 or earlier
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (v->VerMajor == 6 && v->VerMinor == 0)
|
|
{
|
|
// Windows Vista, Server 2008
|
|
if (v->ServicePack <= 2)
|
|
{
|
|
// SP2 or earlier
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (v->VerMajor == 6 && v->VerMinor == 1)
|
|
{
|
|
// Windows 7, Server 2008 R2
|
|
if (v->ServicePack <= 1)
|
|
{
|
|
// SP1 or earlier
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (v->VerMajor == 6 && v->VerMinor == 2)
|
|
{
|
|
// Windows 8, Server 2012
|
|
if (v->ServicePack <= 0)
|
|
{
|
|
// SP0 only
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (v->VerMajor == 6 && v->VerMinor == 3)
|
|
{
|
|
// Windows 8.1, Server 2012 R2
|
|
if (v->ServicePack <= 0)
|
|
{
|
|
// SP0 only
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if ((v->VerMajor == 6 && v->VerMinor == 4) || (v->VerMajor == 10 && v->VerMinor == 0))
|
|
{
|
|
// Windows 10 or Windows Server 2016
|
|
if (v->ServicePack <= 0)
|
|
{
|
|
// SP0 only
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Get version of Windows
|
|
void GetWinVer(RPC_WINVER *v)
|
|
{
|
|
// Validate arguments
|
|
if (v == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
#ifdef OS_WIN32
|
|
Win32GetWinVer(v);
|
|
#else // OS_WIN32
|
|
Zero(v, sizeof(RPC_WINVER));
|
|
StrCpy(v->Title, sizeof(v->Title), GetOsInfo()->OsProductName);
|
|
#endif // OS_WIN32
|
|
}
|
|
|
|
// Close tiny log
|
|
void FreeTinyLog(TINY_LOG *t)
|
|
{
|
|
// Validate arguments
|
|
if (t == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
FileClose(t->io);
|
|
DeleteLock(t->Lock);
|
|
Free(t);
|
|
}
|
|
|
|
// Write to tiny log
|
|
void WriteTinyLog(TINY_LOG *t, char *str)
|
|
{
|
|
BUF *b;
|
|
char dt[MAX_PATH];
|
|
// Validate arguments
|
|
if (t == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
GetDateTimeStrMilli64(dt, sizeof(dt), LocalTime64());
|
|
StrCat(dt, sizeof(dt), ": ");
|
|
|
|
b = NewBuf();
|
|
|
|
WriteBuf(b, dt, StrLen(dt));
|
|
WriteBuf(b, str, StrLen(str));
|
|
WriteBuf(b, "\r\n", 2);
|
|
|
|
Lock(t->Lock);
|
|
{
|
|
FileWrite(t->io, b->Buf, b->Size);
|
|
//FileFlush(t->io);
|
|
}
|
|
Unlock(t->Lock);
|
|
|
|
FreeBuf(b);
|
|
}
|
|
|
|
// Initialize tiny log
|
|
TINY_LOG *NewTinyLog()
|
|
{
|
|
char name[MAX_PATH];
|
|
SYSTEMTIME st;
|
|
TINY_LOG *t;
|
|
|
|
LocalTime(&st);
|
|
|
|
MakeDir(TINY_LOG_DIRNAME);
|
|
|
|
Format(name, sizeof(name), TINY_LOG_FILENAME,
|
|
st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
|
|
|
|
t = ZeroMalloc(sizeof(TINY_LOG));
|
|
|
|
StrCpy(t->FileName, sizeof(t->FileName), name);
|
|
t->io = FileCreate(name);
|
|
t->Lock = NewLock();
|
|
|
|
return t;
|
|
}
|
|
|
|
// Compare entries of No-SSL connection list
|
|
int CompareNoSslList(void *p1, void *p2)
|
|
{
|
|
NON_SSL *n1, *n2;
|
|
if (p1 == NULL || p2 == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
n1 = *(NON_SSL **)p1;
|
|
n2 = *(NON_SSL **)p2;
|
|
if (n1 == NULL || n2 == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
return CmpIpAddr(&n1->IpAddress, &n2->IpAddress);
|
|
}
|
|
|
|
// Decrement connection count of Non-SSL connection list entry
|
|
void DecrementNoSsl(CEDAR *c, IP *ip, UINT num_dec)
|
|
{
|
|
// Validate arguments
|
|
if (c == NULL || ip == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
LockList(c->NonSslList);
|
|
{
|
|
NON_SSL *n = SearchNoSslList(c, ip);
|
|
|
|
if (n != NULL)
|
|
{
|
|
if (n->Count >= num_dec)
|
|
{
|
|
n->Count -= num_dec;
|
|
}
|
|
}
|
|
}
|
|
UnlockList(c->NonSslList);
|
|
}
|
|
|
|
// Add new entry to Non-SSL connection list
|
|
bool AddNoSsl(CEDAR *c, IP *ip)
|
|
{
|
|
NON_SSL *n;
|
|
bool ret = true;
|
|
// Validate arguments
|
|
if (c == NULL || ip == NULL)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
LockList(c->NonSslList);
|
|
{
|
|
DeleteOldNoSsl(c);
|
|
|
|
n = SearchNoSslList(c, ip);
|
|
|
|
if (n == NULL)
|
|
{
|
|
n = ZeroMalloc(sizeof(NON_SSL));
|
|
Copy(&n->IpAddress, ip, sizeof(IP));
|
|
n->Count = 0;
|
|
|
|
Add(c->NonSslList, n);
|
|
}
|
|
|
|
n->EntryExpires = Tick64() + (UINT64)NON_SSL_ENTRY_EXPIRES;
|
|
|
|
n->Count++;
|
|
|
|
if (n->Count > NON_SSL_MIN_COUNT)
|
|
{
|
|
ret = false;
|
|
}
|
|
}
|
|
UnlockList(c->NonSslList);
|
|
|
|
return ret;
|
|
}
|
|
|
|
// Delete old entries in Non-SSL connection list
|
|
void DeleteOldNoSsl(CEDAR *c)
|
|
{
|
|
UINT i;
|
|
LIST *o;
|
|
// Validate arguments
|
|
if (c == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
o = NewListFast(NULL);
|
|
|
|
for (i = 0;i < LIST_NUM(c->NonSslList);i++)
|
|
{
|
|
NON_SSL *n = LIST_DATA(c->NonSslList, i);
|
|
|
|
if (n->EntryExpires <= Tick64())
|
|
{
|
|
Add(o, n);
|
|
}
|
|
}
|
|
|
|
for (i = 0;i < LIST_NUM(o);i++)
|
|
{
|
|
NON_SSL *n = LIST_DATA(o, i);
|
|
|
|
Delete(c->NonSslList, n);
|
|
Free(n);
|
|
}
|
|
|
|
ReleaseList(o);
|
|
}
|
|
|
|
// Search entry in Non-SSL connection list
|
|
NON_SSL *SearchNoSslList(CEDAR *c, IP *ip)
|
|
{
|
|
NON_SSL *n, t;
|
|
// Validate arguments
|
|
if (c == NULL || ip == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
Zero(&t, sizeof(t));
|
|
Copy(&t.IpAddress, ip, sizeof(IP));
|
|
|
|
n = Search(c->NonSslList, &t);
|
|
|
|
if (n == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
return n;
|
|
}
|
|
|
|
// Initialize Non-SSL connection list
|
|
void InitNoSslList(CEDAR *c)
|
|
{
|
|
// Validate arguments
|
|
if (c == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
c->NonSslList = NewList(CompareNoSslList);
|
|
}
|
|
|
|
// Free Non-SSL connection list
|
|
void FreeNoSslList(CEDAR *c)
|
|
{
|
|
UINT i;
|
|
// Validate arguments
|
|
if (c == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (i = 0;i < LIST_NUM(c->NonSslList);i++)
|
|
{
|
|
NON_SSL *n = LIST_DATA(c->NonSslList, i);
|
|
|
|
Free(n);
|
|
}
|
|
|
|
ReleaseList(c->NonSslList);
|
|
c->NonSslList = NULL;
|
|
}
|
|
|
|
// Start Cedar log
|
|
void StartCedarLog()
|
|
{
|
|
if (cedar_log_ref == NULL)
|
|
{
|
|
cedar_log_ref = NewRef();
|
|
}
|
|
else
|
|
{
|
|
AddRef(cedar_log_ref);
|
|
}
|
|
|
|
cedar_log = NewLog("debug_log", "debug", LOG_SWITCH_DAY);
|
|
}
|
|
|
|
// Stop Cedar log
|
|
void StopCedarLog()
|
|
{
|
|
if (cedar_log_ref == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (Release(cedar_log_ref) == 0)
|
|
{
|
|
FreeLog(cedar_log);
|
|
cedar_log = NULL;
|
|
cedar_log_ref = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
// Get sum of traffic data size
|
|
UINT64 GetTrafficPacketSize(TRAFFIC *t)
|
|
{
|
|
// Validate arguments
|
|
if (t == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return t->Recv.BroadcastBytes + t->Recv.UnicastBytes +
|
|
t->Send.BroadcastBytes + t->Send.UnicastBytes;
|
|
}
|
|
|
|
// Get sum of the number of packets in traffic
|
|
UINT64 GetTrafficPacketNum(TRAFFIC *t)
|
|
{
|
|
// Validate arguments
|
|
if (t == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return t->Recv.BroadcastCount + t->Recv.UnicastCount +
|
|
t->Send.BroadcastCount + t->Send.UnicastCount;
|
|
}
|
|
|
|
// Check whether the certificate is signed by CA which is trusted by the hub
|
|
bool CheckSignatureByCaLinkMode(SESSION *s, X *x)
|
|
{
|
|
LINK *k;
|
|
HUB *h;
|
|
bool ret = false;
|
|
// Validate arguments
|
|
if (s == NULL || x == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (s->LinkModeClient == false || (k = s->Link) == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
h = k->Hub;
|
|
|
|
if (h->HubDb != NULL)
|
|
{
|
|
LockList(h->HubDb->RootCertList);
|
|
{
|
|
X *root_cert;
|
|
root_cert = GetIssuerFromList(h->HubDb->RootCertList, x);
|
|
if (root_cert != NULL)
|
|
{
|
|
ret = true;
|
|
}
|
|
}
|
|
UnlockList(h->HubDb->RootCertList);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
// Check whether the certificate is signed by CA which is trusted by Cedar
|
|
bool CheckSignatureByCa(CEDAR *cedar, X *x)
|
|
{
|
|
X *ca;
|
|
// Validate arguments
|
|
if (cedar == NULL || x == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Get the CA which signed the certificate
|
|
ca = FindCaSignedX(cedar->CaList, x);
|
|
if (ca == NULL)
|
|
{
|
|
// Not found
|
|
return false;
|
|
}
|
|
|
|
// Found
|
|
FreeX(ca);
|
|
return true;
|
|
}
|
|
|
|
// Get the CA which signed the certificate
|
|
X *FindCaSignedX(LIST *o, X *x)
|
|
{
|
|
X *ret;
|
|
// Validate arguments
|
|
if (o == NULL || x == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
ret = NULL;
|
|
|
|
LockList(o);
|
|
{
|
|
UINT i;
|
|
for (i = 0;i < LIST_NUM(o);i++)
|
|
{
|
|
X *ca = LIST_DATA(o, i);
|
|
if (CheckXDateNow(ca))
|
|
{
|
|
if (CompareName(ca->subject_name, x->issuer_name))
|
|
{
|
|
K *k = GetKFromX(ca);
|
|
if (k != NULL)
|
|
{
|
|
if (CheckSignature(x, k))
|
|
{
|
|
ret = CloneX(ca);
|
|
}
|
|
FreeK(k);
|
|
}
|
|
}
|
|
else if (CompareX(ca, x))
|
|
{
|
|
ret = CloneX(ca);
|
|
}
|
|
}
|
|
|
|
if (ret != NULL)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
UnlockList(o);
|
|
|
|
return ret;
|
|
}
|
|
|
|
// Delete trusted CA from Cedar
|
|
bool DeleteCa(CEDAR *cedar, UINT ptr)
|
|
{
|
|
bool b = false;
|
|
// Validate arguments
|
|
if (cedar == NULL || ptr == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
LockList(cedar->CaList);
|
|
{
|
|
UINT i;
|
|
|
|
for (i = 0;i < LIST_NUM(cedar->CaList);i++)
|
|
{
|
|
X *x = LIST_DATA(cedar->CaList, i);
|
|
|
|
if (POINTER_TO_KEY(x) == ptr)
|
|
{
|
|
Delete(cedar->CaList, x);
|
|
FreeX(x);
|
|
|
|
b = true;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
UnlockList(cedar->CaList);
|
|
|
|
return b;
|
|
}
|
|
|
|
// Add trusted CA to Cedar
|
|
void AddCa(CEDAR *cedar, X *x)
|
|
{
|
|
// Validate arguments
|
|
if (cedar == NULL || x == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
LockList(cedar->CaList);
|
|
{
|
|
UINT i;
|
|
bool ok = true;
|
|
|
|
for (i = 0;i < LIST_NUM(cedar->CaList);i++)
|
|
{
|
|
X *exist_x = LIST_DATA(cedar->CaList, i);
|
|
if (CompareX(exist_x, x))
|
|
{
|
|
ok = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ok)
|
|
{
|
|
Insert(cedar->CaList, CloneX(x));
|
|
}
|
|
}
|
|
UnlockList(cedar->CaList);
|
|
}
|
|
|
|
// Delete connection from Cedar
|
|
void DelConnection(CEDAR *cedar, CONNECTION *c)
|
|
{
|
|
// Validate arguments
|
|
if (cedar == NULL || c == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
LockList(cedar->ConnectionList);
|
|
{
|
|
Debug("Connection %s Deleted from Cedar.\n", c->Name);
|
|
if (Delete(cedar->ConnectionList, c))
|
|
{
|
|
ReleaseConnection(c);
|
|
}
|
|
}
|
|
UnlockList(cedar->ConnectionList);
|
|
}
|
|
|
|
// Add connection to Cedar
|
|
void AddConnection(CEDAR *cedar, CONNECTION *c)
|
|
{
|
|
char tmp[MAX_SIZE];
|
|
UINT i;
|
|
// Validate arguments
|
|
if (cedar == NULL || c == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Determine the name of the connection
|
|
i = Inc(cedar->ConnectionIncrement);
|
|
Format(tmp, sizeof(tmp), "CID-%u", i);
|
|
|
|
|
|
Lock(c->lock);
|
|
{
|
|
Free(c->Name);
|
|
c->Name = CopyStr(tmp);
|
|
}
|
|
Unlock(c->lock);
|
|
|
|
LockList(cedar->ConnectionList);
|
|
{
|
|
Add(cedar->ConnectionList, c);
|
|
AddRef(c->ref);
|
|
Debug("Connection %s Inserted to Cedar.\n", c->Name);
|
|
}
|
|
UnlockList(cedar->ConnectionList);
|
|
}
|
|
|
|
// Stop all connections
|
|
void StopAllConnection(CEDAR *c)
|
|
{
|
|
UINT num;
|
|
UINT i;
|
|
CONNECTION **connections;
|
|
// Validate arguments
|
|
if (c == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
LockList(c->ConnectionList);
|
|
{
|
|
connections = ToArray(c->ConnectionList);
|
|
num = LIST_NUM(c->ConnectionList);
|
|
DeleteAll(c->ConnectionList);
|
|
}
|
|
UnlockList(c->ConnectionList);
|
|
|
|
for (i = 0;i < num;i++)
|
|
{
|
|
StopConnection(connections[i], false);
|
|
ReleaseConnection(connections[i]);
|
|
}
|
|
Free(connections);
|
|
}
|
|
|
|
// Delete a hub in Cedar
|
|
void DelHub(CEDAR *c, HUB *h)
|
|
{
|
|
DelHubEx(c, h, false);
|
|
}
|
|
void DelHubEx(CEDAR *c, HUB *h, bool no_lock)
|
|
{
|
|
// Validate arguments
|
|
if (c == NULL || h == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (no_lock == false)
|
|
{
|
|
LockHubList(c);
|
|
}
|
|
|
|
if (Delete(c->HubList, h))
|
|
{
|
|
ReleaseHub(h);
|
|
}
|
|
|
|
if (no_lock == false)
|
|
{
|
|
UnlockHubList(c);
|
|
}
|
|
}
|
|
|
|
// Add a new hub to Cedar
|
|
void AddHub(CEDAR *c, HUB *h)
|
|
{
|
|
// Validate arguments
|
|
if (c == NULL || h == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
LockHubList(c);
|
|
{
|
|
#if 0
|
|
// We shall not check here the number of hub
|
|
if (LIST_NUM(c->HubList) >= MAX_HUBS)
|
|
{
|
|
// over limit
|
|
UnlockHubList(c);
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
// Confirm there is no hub which have same name
|
|
if (IsHub(c, h->Name))
|
|
{
|
|
// exist
|
|
UnlockHubList(c);
|
|
return;
|
|
}
|
|
|
|
// Register the hub
|
|
Insert(c->HubList, h);
|
|
AddRef(h->ref);
|
|
}
|
|
UnlockHubList(c);
|
|
}
|
|
|
|
// Stop all hubs in Cedar
|
|
void StopAllHub(CEDAR *c)
|
|
{
|
|
HUB **hubs;
|
|
UINT i, num;
|
|
// Validate arguments
|
|
if (c == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
LockHubList(c);
|
|
{
|
|
hubs = ToArray(c->HubList);
|
|
num = LIST_NUM(c->HubList);
|
|
DeleteAll(c->HubList);
|
|
}
|
|
UnlockHubList(c);
|
|
|
|
for (i = 0;i < num;i++)
|
|
{
|
|
StopHub(hubs[i]);
|
|
ReleaseHub(hubs[i]);
|
|
}
|
|
|
|
Free(hubs);
|
|
}
|
|
|
|
// Get reverse listener socket in Cedar
|
|
SOCK *GetReverseListeningSock(CEDAR *c)
|
|
{
|
|
SOCK *s = NULL;
|
|
// Validate arguments
|
|
if (c == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
LockList(c->ListenerList);
|
|
{
|
|
UINT i;
|
|
for (i = 0;i < LIST_NUM(c->ListenerList);i++)
|
|
{
|
|
LISTENER *r = LIST_DATA(c->ListenerList, i);
|
|
|
|
if (r->Protocol == LISTENER_REVERSE)
|
|
{
|
|
Lock(r->lock);
|
|
{
|
|
s = r->Sock;
|
|
|
|
AddRef(s->ref);
|
|
}
|
|
Unlock(r->lock);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
UnlockList(c->ListenerList);
|
|
|
|
return s;
|
|
}
|
|
|
|
// Get in-process listener socket in Cedar
|
|
SOCK *GetInProcListeningSock(CEDAR *c)
|
|
{
|
|
SOCK *s = NULL;
|
|
// Validate arguments
|
|
if (c == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
LockList(c->ListenerList);
|
|
{
|
|
UINT i;
|
|
for (i = 0;i < LIST_NUM(c->ListenerList);i++)
|
|
{
|
|
LISTENER *r = LIST_DATA(c->ListenerList, i);
|
|
|
|
if (r->Protocol == LISTENER_INPROC)
|
|
{
|
|
Lock(r->lock);
|
|
{
|
|
s = r->Sock;
|
|
|
|
if (s != NULL)
|
|
{
|
|
AddRef(s->ref);
|
|
}
|
|
}
|
|
Unlock(r->lock);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
UnlockList(c->ListenerList);
|
|
|
|
return s;
|
|
}
|
|
|
|
// Add a new listener to Cedar
|
|
void AddListener(CEDAR *c, LISTENER *r)
|
|
{
|
|
// Validate arguments
|
|
if (c == NULL || r == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
LockList(c->ListenerList);
|
|
{
|
|
Add(c->ListenerList, r);
|
|
AddRef(r->ref);
|
|
}
|
|
UnlockList(c->ListenerList);
|
|
}
|
|
|
|
// Stop all listener in Cedar
|
|
void StopAllListener(CEDAR *c)
|
|
{
|
|
LISTENER **array;
|
|
UINT i, num;
|
|
// Validate arguments
|
|
if (c == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
LockList(c->ListenerList);
|
|
{
|
|
array = ToArray(c->ListenerList);
|
|
num = LIST_NUM(c->ListenerList);
|
|
DeleteAll(c->ListenerList);
|
|
}
|
|
UnlockList(c->ListenerList);
|
|
|
|
for (i = 0;i < num;i++)
|
|
{
|
|
StopListener(array[i]);
|
|
ReleaseListener(array[i]);
|
|
}
|
|
Free(array);
|
|
}
|
|
|
|
// Budget management functions
|
|
void CedarAddQueueBudget(CEDAR *c, int diff)
|
|
{
|
|
// Validate arguments
|
|
if (c == NULL || diff == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Lock(c->QueueBudgetLock);
|
|
{
|
|
int v = (int)c->QueueBudget;
|
|
v += diff;
|
|
c->QueueBudget = (UINT)v;
|
|
}
|
|
Unlock(c->QueueBudgetLock);
|
|
}
|
|
void CedarAddFifoBudget(CEDAR *c, int diff)
|
|
{
|
|
// Validate arguments
|
|
if (c == NULL || diff == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Lock(c->FifoBudgetLock);
|
|
{
|
|
int v = (int)c->FifoBudget;
|
|
v += diff;
|
|
c->FifoBudget = (UINT)v;
|
|
}
|
|
Unlock(c->FifoBudgetLock);
|
|
}
|
|
UINT CedarGetQueueBudgetConsuming(CEDAR *c)
|
|
{
|
|
// Validate arguments
|
|
if (c == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return c->QueueBudget;
|
|
}
|
|
UINT CedarGetFifoBudgetConsuming(CEDAR *c)
|
|
{
|
|
// Validate arguments
|
|
if (c == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return c->FifoBudget;
|
|
}
|
|
UINT CedarGetQueueBudgetBalance(CEDAR *c)
|
|
{
|
|
UINT current = CedarGetQueueBudgetConsuming(c);
|
|
UINT budget = QUEUE_BUDGET;
|
|
|
|
if (current <= budget)
|
|
{
|
|
return budget - current;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
UINT CedarGetFifoBudgetBalance(CEDAR *c)
|
|
{
|
|
UINT current = CedarGetFifoBudgetConsuming(c);
|
|
UINT budget = FIFO_BUDGET;
|
|
|
|
if (current <= budget)
|
|
{
|
|
return budget - current;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// Add the current TCP queue size
|
|
void CedarAddCurrentTcpQueueSize(CEDAR *c, int diff)
|
|
{
|
|
// Validate arguments
|
|
if (c == NULL || diff == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Lock(c->CurrentTcpQueueSizeLock);
|
|
{
|
|
int v = (int)c->CurrentTcpQueueSize;
|
|
v += diff;
|
|
c->CurrentTcpQueueSize = (UINT)v;
|
|
}
|
|
Unlock(c->CurrentTcpQueueSizeLock);
|
|
}
|
|
|
|
// Get the current TCP queue size
|
|
UINT CedarGetCurrentTcpQueueSize(CEDAR *c)
|
|
{
|
|
// Validate arguments
|
|
if (c == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return c->CurrentTcpQueueSize;
|
|
}
|
|
|
|
// Stop Cedar
|
|
void StopCedar(CEDAR *c)
|
|
{
|
|
// Validate arguments
|
|
if (c == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Stop flag
|
|
c->Halt = true;
|
|
|
|
// Stop all listener
|
|
StopAllListener(c);
|
|
// Stop all connections
|
|
StopAllConnection(c);
|
|
// Stop all hubs
|
|
StopAllHub(c);
|
|
// Free all virtual L3 switch
|
|
L3FreeAllSw(c);
|
|
}
|
|
|
|
// Clean up Cedar
|
|
void CleanupCedar(CEDAR *c)
|
|
{
|
|
UINT i;
|
|
// Validate arguments
|
|
if (c == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
WuFreeWebUI(c->WebUI);
|
|
FreeCedarLayer3(c);
|
|
|
|
for (i = 0; i < LIST_NUM(c->WgkList); ++i)
|
|
{
|
|
WGK *wgk = LIST_DATA(c->WgkList, i);
|
|
Free(wgk);
|
|
}
|
|
ReleaseList(c->WgkList);
|
|
|
|
for (i = 0;i < LIST_NUM(c->CaList);i++)
|
|
{
|
|
X *x = LIST_DATA(c->CaList, i);
|
|
FreeX(x);
|
|
}
|
|
ReleaseList(c->CaList);
|
|
|
|
ReleaseList(c->ListenerList);
|
|
ReleaseList(c->HubList);
|
|
ReleaseList(c->ConnectionList);
|
|
//CleanupUDPEntry(c);
|
|
ReleaseList(c->UDPEntryList);
|
|
DeleteLock(c->lock);
|
|
DeleteCounter(c->ConnectionIncrement);
|
|
DeleteCounter(c->CurrentSessions);
|
|
|
|
if (c->DebugLog != NULL)
|
|
{
|
|
FreeLog(c->DebugLog);
|
|
}
|
|
|
|
if (c->ServerX)
|
|
{
|
|
FreeX(c->ServerX);
|
|
}
|
|
if (c->ServerK)
|
|
{
|
|
FreeK(c->ServerK);
|
|
}
|
|
|
|
if (c->CipherList)
|
|
{
|
|
Free(c->CipherList);
|
|
}
|
|
|
|
for (i = 0;i < LIST_NUM(c->TrafficDiffList);i++)
|
|
{
|
|
TRAFFIC_DIFF *d = LIST_DATA(c->TrafficDiffList, i);
|
|
Free(d->Name);
|
|
Free(d->HubName);
|
|
Free(d);
|
|
}
|
|
|
|
ReleaseList(c->TrafficDiffList);
|
|
|
|
Free(c->ServerStr);
|
|
Free(c->MachineName);
|
|
|
|
Free(c->HttpUserAgent);
|
|
Free(c->HttpAccept);
|
|
Free(c->HttpAcceptLanguage);
|
|
Free(c->HttpAcceptEncoding);
|
|
|
|
FreeTraffic(c->Traffic);
|
|
|
|
DeleteLock(c->TrafficLock);
|
|
|
|
FreeNetSvcList(c);
|
|
|
|
Free(c->VerString);
|
|
Free(c->BuildInfo);
|
|
|
|
FreeLocalBridgeList(c);
|
|
|
|
DeleteCounter(c->AssignedBridgeLicense);
|
|
DeleteCounter(c->AssignedClientLicense);
|
|
|
|
FreeNoSslList(c);
|
|
|
|
DeleteLock(c->CedarSuperLock);
|
|
|
|
DeleteCounter(c->AcceptingSockets);
|
|
|
|
ReleaseIntList(c->UdpPortList);
|
|
|
|
DeleteLock(c->OpenVPNPublicPortsLock);
|
|
|
|
DeleteLock(c->CurrentRegionLock);
|
|
|
|
DeleteLock(c->CurrentTcpQueueSizeLock);
|
|
DeleteLock(c->QueueBudgetLock);
|
|
DeleteLock(c->FifoBudgetLock);
|
|
|
|
DeleteCounter(c->CurrentActiveLinks);
|
|
|
|
Free(c);
|
|
}
|
|
|
|
// Release reference of the Cedar
|
|
void ReleaseCedar(CEDAR *c)
|
|
{
|
|
// Validate arguments
|
|
if (c == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (Release(c->ref) == 0)
|
|
{
|
|
CleanupCedar(c);
|
|
}
|
|
}
|
|
|
|
// Set cipher list entry
|
|
void SetCedarCipherList(CEDAR *cedar, char *name)
|
|
{
|
|
// Validate arguments
|
|
if (cedar == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (cedar->CipherList != NULL)
|
|
{
|
|
Free(cedar->CipherList);
|
|
}
|
|
if (name != NULL)
|
|
{
|
|
cedar->CipherList = CopyStr(name);
|
|
}
|
|
else
|
|
{
|
|
cedar->CipherList = NULL;
|
|
}
|
|
}
|
|
|
|
// Compare net service list entries
|
|
int CompareNetSvc(void *p1, void *p2)
|
|
{
|
|
NETSVC *n1, *n2;
|
|
if (p1 == NULL || p2 == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
n1 = *(NETSVC **)p1;
|
|
n2 = *(NETSVC **)p2;
|
|
if (n1 == NULL || n2 == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
if (n1->Port > n2->Port)
|
|
{
|
|
return 1;
|
|
}
|
|
else if (n1->Port < n2->Port)
|
|
{
|
|
return -1;
|
|
}
|
|
else if (n1->Udp > n2->Udp)
|
|
{
|
|
return 1;
|
|
}
|
|
else if (n1->Udp < n2->Udp)
|
|
{
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Initialize net service list
|
|
void InitNetSvcList(CEDAR *cedar)
|
|
{
|
|
char filename[MAX_PATH] = "/etc/services";
|
|
BUF *b;
|
|
// Validate arguments
|
|
if (cedar == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
#ifdef OS_WIN32
|
|
Format(filename, sizeof(filename), "%s\\drivers\\etc\\services", MsGetSystem32Dir());
|
|
#endif
|
|
|
|
cedar->NetSvcList = NewList(CompareNetSvc);
|
|
|
|
b = ReadDump(filename);
|
|
if (b == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
while (true)
|
|
{
|
|
char *s = CfgReadNextLine(b);
|
|
if (s == NULL)
|
|
{
|
|
break;
|
|
}
|
|
|
|
Trim(s);
|
|
if (s[0] != '#')
|
|
{
|
|
TOKEN_LIST *t = ParseToken(s, " \t/");
|
|
if (t->NumTokens >= 3)
|
|
{
|
|
NETSVC *n = ZeroMalloc(sizeof(NETSVC));
|
|
n->Name = CopyStr(t->Token[0]);
|
|
n->Udp = (StrCmpi(t->Token[2], "udp") == 0 ? true : false);
|
|
n->Port = ToInt(t->Token[1]);
|
|
Add(cedar->NetSvcList, n);
|
|
}
|
|
FreeToken(t);
|
|
}
|
|
Free(s);
|
|
}
|
|
|
|
FreeBuf(b);
|
|
}
|
|
|
|
// Get net service name
|
|
char *GetSvcName(CEDAR *cedar, bool udp, UINT port)
|
|
{
|
|
char *ret = NULL;
|
|
NETSVC t;
|
|
// Validate arguments
|
|
if (cedar == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
t.Udp = (udp == 0 ? false : true);
|
|
t.Port = port;
|
|
|
|
LockList(cedar->NetSvcList);
|
|
{
|
|
NETSVC *n = Search(cedar->NetSvcList, &t);
|
|
if (n != NULL)
|
|
{
|
|
ret = n->Name;
|
|
}
|
|
}
|
|
UnlockList(cedar->NetSvcList);
|
|
|
|
return ret;
|
|
}
|
|
|
|
// Free net service list
|
|
void FreeNetSvcList(CEDAR *cedar)
|
|
{
|
|
UINT i;
|
|
// Validate arguments
|
|
if (cedar == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (i = 0;i < LIST_NUM(cedar->NetSvcList);i++)
|
|
{
|
|
NETSVC *n = LIST_DATA(cedar->NetSvcList, i);
|
|
Free(n->Name);
|
|
Free(n);
|
|
}
|
|
ReleaseList(cedar->NetSvcList);
|
|
}
|
|
|
|
// Change certificate of Cedar
|
|
void SetCedarCert(CEDAR *c, X *server_x, K *server_k)
|
|
{
|
|
// Validate arguments
|
|
if (server_x == NULL || server_k == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Lock(c->lock);
|
|
{
|
|
if (c->ServerX != NULL)
|
|
{
|
|
FreeX(c->ServerX);
|
|
}
|
|
|
|
if (c->ServerK != NULL)
|
|
{
|
|
FreeK(c->ServerK);
|
|
}
|
|
|
|
c->ServerX = CloneX(server_x);
|
|
c->ServerK = CloneK(server_k);
|
|
}
|
|
Unlock(c->lock);
|
|
}
|
|
|
|
// Set the Cedar into VPN Bridge mode
|
|
void SetCedarVpnBridge(CEDAR *c)
|
|
{
|
|
// Validate arguments
|
|
if (c == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
c->Bridge = true;
|
|
|
|
Free(c->ServerStr);
|
|
c->ServerStr = CopyStr(CEDAR_BRIDGE_STR);
|
|
}
|
|
|
|
void CedarForceLink()
|
|
{
|
|
}
|
|
|
|
// Get version of the Cedar
|
|
void GetCedarVersion(char *tmp, UINT size)
|
|
{
|
|
// Validate arguments
|
|
if (tmp == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Format(tmp, size, "%u.%02u.%u", CEDAR_VERSION_MAJOR, CEDAR_VERSION_MINOR, CEDAR_VERSION_BUILD);
|
|
}
|
|
|
|
UINT GetCedarVersionNumber()
|
|
{
|
|
return CEDAR_VERSION_MAJOR * 100 + CEDAR_VERSION_MINOR;
|
|
}
|
|
|
|
// Create Cedar object
|
|
CEDAR *NewCedar(X *server_x, K *server_k)
|
|
{
|
|
CEDAR *c;
|
|
char tmp[MAX_SIZE];
|
|
char tmp2[MAX_SIZE];
|
|
char *beta_str;
|
|
|
|
CedarForceLink();
|
|
|
|
c = ZeroMalloc(sizeof(CEDAR));
|
|
|
|
c->CurrentActiveLinks = NewCounter();
|
|
|
|
c->AcceptingSockets = NewCounter();
|
|
|
|
c->CedarSuperLock = NewLock();
|
|
|
|
c->CurrentRegionLock = NewLock();
|
|
|
|
#ifdef BETA_NUMBER
|
|
c->Beta = BETA_NUMBER;
|
|
#endif // BETA_NUMBER
|
|
|
|
InitNoSslList(c);
|
|
|
|
c->AssignedBridgeLicense = NewCounter();
|
|
c->AssignedClientLicense = NewCounter();
|
|
|
|
c->CurrentTcpQueueSizeLock = NewLock();
|
|
c->QueueBudgetLock = NewLock();
|
|
c->FifoBudgetLock = NewLock();
|
|
|
|
Rand(c->UniqueId, sizeof(c->UniqueId));
|
|
|
|
c->CreatedTick = Tick64();
|
|
|
|
c->lock = NewLock();
|
|
c->ref = NewRef();
|
|
|
|
c->OpenVPNPublicPortsLock = NewLock();
|
|
c->CurrentTcpConnections = GetNumTcpConnectionsCounter();
|
|
|
|
c->ListenerList = NewList(CompareListener);
|
|
c->UDPEntryList = NewList(CompareUDPEntry);
|
|
c->HubList = NewList(CompareHub);
|
|
c->ConnectionList = NewList(CompareConnection);
|
|
|
|
c->ConnectionIncrement = NewCounter();
|
|
c->CurrentSessions = NewCounter();
|
|
|
|
if (server_k && server_x)
|
|
{
|
|
c->ServerK = CloneK(server_k);
|
|
c->ServerX = CloneX(server_x);
|
|
}
|
|
|
|
c->Version = GetCedarVersionNumber();
|
|
c->Build = CEDAR_VERSION_BUILD;
|
|
c->ServerStr = CopyStr(CEDAR_SERVER_STR);
|
|
|
|
GetMachineName(tmp, sizeof(tmp));
|
|
c->MachineName = CopyStr(tmp);
|
|
|
|
c->HttpUserAgent = CopyStr(DEFAULT_USER_AGENT);
|
|
c->HttpAccept = CopyStr(DEFAULT_ACCEPT);
|
|
c->HttpAcceptLanguage = CopyStr("ja");
|
|
c->HttpAcceptEncoding = CopyStr(DEFAULT_ENCODING);
|
|
|
|
c->Traffic = NewTraffic();
|
|
c->TrafficLock = NewLock();
|
|
c->CaList = NewList(CompareCert);
|
|
c->WgkList = NewList(CompareWgk);
|
|
|
|
c->TrafficDiffList = NewList(NULL);
|
|
|
|
SetCedarCipherList(c, SERVER_DEFAULT_CIPHER_NAME);
|
|
|
|
c->ClientId = _II("CLIENT_ID");
|
|
|
|
c->UdpPortList = NewIntList(false);
|
|
|
|
c->DhParamBits = DH_PARAM_BITS_DEFAULT;
|
|
|
|
InitNetSvcList(c);
|
|
|
|
InitLocalBridgeList(c);
|
|
|
|
InitCedarLayer3(c);
|
|
|
|
c->WebUI = WuNewWebUI(c);
|
|
|
|
#ifdef ALPHA_VERSION
|
|
beta_str = "Alpha";
|
|
#else // ALPHA_VERSION
|
|
#ifndef RELEASE_CANDIDATE
|
|
beta_str = "Beta";
|
|
#else // RELEASE_CANDIDATE
|
|
beta_str = "Release Candidate";
|
|
#endif // RELEASE_CANDIDATE
|
|
#endif // ALPHA_VERSION
|
|
|
|
ToStr(tmp2, c->Beta);
|
|
|
|
Format(tmp, sizeof(tmp), "Version %u.%02u Build %u %s %s (%s)",
|
|
CEDAR_VERSION_MAJOR, CEDAR_VERSION_MINOR, CEDAR_VERSION_BUILD,
|
|
c->Beta == 0 ? "" : beta_str,
|
|
c->Beta == 0 ? "" : tmp2,
|
|
_SS("LANGSTR"));
|
|
Trim(tmp);
|
|
|
|
if (true)
|
|
{
|
|
SYSTEMTIME st;
|
|
Zero(&st, sizeof(st));
|
|
|
|
st.wYear = BUILD_DATE_Y;
|
|
st.wMonth = BUILD_DATE_M;
|
|
st.wDay = BUILD_DATE_D;
|
|
|
|
c->BuiltDate = SystemToUINT64(&st);
|
|
}
|
|
|
|
c->VerString = CopyStr(tmp);
|
|
|
|
Format(tmp, sizeof(tmp), "Compiled %04u/%02u/%02u %02u:%02u:%02u by %s at %s",
|
|
BUILD_DATE_Y, BUILD_DATE_M, BUILD_DATE_D, BUILD_DATE_HO, BUILD_DATE_MI, BUILD_DATE_SE, BUILDER_NAME, BUILD_PLACE);
|
|
|
|
c->BuildInfo = CopyStr(tmp);
|
|
|
|
return c;
|
|
}
|
|
|
|
// Cumulate traffic size
|
|
void AddTraffic(TRAFFIC *dst, TRAFFIC *diff)
|
|
{
|
|
// Validate arguments
|
|
if (dst == NULL || diff == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
dst->Recv.BroadcastBytes += diff->Recv.BroadcastBytes;
|
|
dst->Recv.BroadcastCount += diff->Recv.BroadcastCount;
|
|
dst->Recv.UnicastBytes += diff->Recv.UnicastBytes;
|
|
dst->Recv.UnicastCount += diff->Recv.UnicastCount;
|
|
|
|
dst->Send.BroadcastBytes += diff->Send.BroadcastBytes;
|
|
dst->Send.BroadcastCount += diff->Send.BroadcastCount;
|
|
dst->Send.UnicastBytes += diff->Send.UnicastBytes;
|
|
dst->Send.UnicastCount += diff->Send.UnicastCount;
|
|
}
|
|
|
|
// Create new traffic size object
|
|
TRAFFIC *NewTraffic()
|
|
{
|
|
TRAFFIC *t;
|
|
|
|
t = ZeroMalloc(sizeof(TRAFFIC));
|
|
return t;
|
|
}
|
|
|
|
// Free traffic size object
|
|
void FreeTraffic(TRAFFIC *t)
|
|
{
|
|
// Validate arguments
|
|
if (t == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Free(t);
|
|
}
|
|
|
|
// Initialize Cedar communication module
|
|
void InitCedar()
|
|
{
|
|
if ((init_cedar_counter++) > 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (sodium_init() == -1)
|
|
{
|
|
Debug("InitCedar(): sodium_init() failed!\n");
|
|
return;
|
|
}
|
|
|
|
// Initialize protocol module
|
|
InitProtocol();
|
|
}
|
|
|
|
// Free Cedar communication module
|
|
void FreeCedar()
|
|
{
|
|
if ((--init_cedar_counter) > 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Free protocol module
|
|
FreeProtocol();
|
|
}
|
|
|