1
0
mirror of https://github.com/SoftEtherVPN/SoftEtherVPN.git synced 2024-09-19 10:10:40 +03:00
SoftEtherVPN/src/Cedar/Server.c
Ilya Shipitsin c46871688b src/Cedar/Server.c: fix race condition
=================================================================
==1505093==ERROR: AddressSanitizer: heap-use-after-free on address 0x607000366b88 at pc 0x7f72afadc34a bp 0x7f72990fa390 sp 0x7f72990fa388
READ of size 4 at 0x607000366b88 thread T22
    #0 0x7f72afadc349 in GetCaps /home/ilia/SoftEtherVPN/src/Cedar/Server.c:1861
    #1 0x7f72afadc382 in GetCapsInt /home/ilia/SoftEtherVPN/src/Cedar/Server.c:1802
    #2 0x7f72afaf72a5 in GetServerCapsInt /home/ilia/SoftEtherVPN/src/Cedar/Server.c:1098
    #3 0x7f72afaf7318 in GetServerCapsBool /home/ilia/SoftEtherVPN/src/Cedar/Server.c:1104
    #4 0x7f72afaf771e in SiWriteHubCfg /home/ilia/SoftEtherVPN/src/Cedar/Server.c:4887
    #5 0x7f72afaf771e in SiWriteHubCfg /home/ilia/SoftEtherVPN/src/Cedar/Server.c:4824
    #6 0x7f72afaf7c0b in SiWriteHubs /home/ilia/SoftEtherVPN/src/Cedar/Server.c:5548
    #7 0x7f72afaf7c0b in SiWriteHubs /home/ilia/SoftEtherVPN/src/Cedar/Server.c:5515
    #8 0x7f72afaf81d6 in SiWriteConfigurationToCfg /home/ilia/SoftEtherVPN/src/Cedar/Server.c:3166
    #9 0x7f72afaf86bc in SiWriteConfigurationFile /home/ilia/SoftEtherVPN/src/Cedar/Server.c:6593
    #10 0x7f72afaf86bc in SiWriteConfigurationFile /home/ilia/SoftEtherVPN/src/Cedar/Server.c:6569
    #11 0x7f72afaf8914 in SiSaverThread /home/ilia/SoftEtherVPN/src/Cedar/Server.c:6561
    #12 0x7f72afaf8914 in SiSaverThread /home/ilia/SoftEtherVPN/src/Cedar/Server.c:6547
    #13 0x7f72af6e0cfa in ThreadPoolProc /home/ilia/SoftEtherVPN/src/Mayaqua/Kernel.c:872
    #14 0x7f72af6e0cfa in ThreadPoolProc /home/ilia/SoftEtherVPN/src/Mayaqua/Kernel.c:827
    #15 0x7f72af76eeb4 in UnixDefaultThreadProc /home/ilia/SoftEtherVPN/src/Mayaqua/Unix.c:1604
    #16 0x7f72af4ffc56 in start_thread (/lib64/libc.so.6+0x8cc56) (BuildId: 6107835fa7d4725691b2b7f6aaee7abe09f493b2)
    #17 0x7f72af585a6f in __clone3 (/lib64/libc.so.6+0x112a6f) (BuildId: 6107835fa7d4725691b2b7f6aaee7abe09f493b2)

0x607000366b88 is located 24 bytes inside of 72-byte region [0x607000366b70,0x607000366bb8)
freed by thread T0 here:
    #0 0x7f72afed7fc8 in __interceptor_free.part.0 (/lib64/libasan.so.8+0xd7fc8) (BuildId: 9501248886f79bf1482f3e153f794be742818172)
    #1 0x7f72af76ed6f in UnixMemoryFree /home/ilia/SoftEtherVPN/src/Mayaqua/Unix.c:2072

previously allocated by thread T22 here:
    #0 0x7f72afed92ff in malloc (/lib64/libasan.so.8+0xd92ff) (BuildId: 9501248886f79bf1482f3e153f794be742818172)
    #1 0x7f72af76f35d in UnixMemoryAlloc /home/ilia/SoftEtherVPN/src/Mayaqua/Unix.c:2053

Thread T22 created by T0 here:
    #0 0x7f72afe48966 in pthread_create (/lib64/libasan.so.8+0x48966) (BuildId: 9501248886f79bf1482f3e153f794be742818172)
    #1 0x7f72af76f713 in UnixInitThread /home/ilia/SoftEtherVPN/src/Mayaqua/Unix.c:1683

SUMMARY: AddressSanitizer: heap-use-after-free /home/ilia/SoftEtherVPN/src/Cedar/Server.c:1861 in GetCaps
Shadow bytes around the buggy address:
  0x607000366900: 00 00 00 fa fa fa fa fa 00 00 00 00 00 00 00 00
  0x607000366980: 00 fa fa fa fa fa 00 00 00 00 00 00 00 00 00 fa
  0x607000366a00: fa fa fa fa 00 00 00 00 00 00 00 00 00 fa fa fa
  0x607000366a80: fa fa 00 00 00 00 00 00 00 00 00 fa fa fa fa fa
  0x607000366b00: 00 00 00 00 00 00 00 00 00 fa fa fa fa fa fd fd
=>0x607000366b80: fd[fd]fd fd fd fd fd fa fa fa fa fa fd fd fd fd
  0x607000366c00: fd fd fd fd fd fa fa fa fa fa fd fd fd fd fd fd
  0x607000366c80: fd fd fd fa fa fa fa fa fd fd fd fd fd fd fd fd
  0x607000366d00: fd fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x607000366d80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x607000366e00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
2023-05-01 05:53:36 +02:00

10966 lines
248 KiB
C

// SoftEther VPN Source Code - Developer Edition Master Branch
// Cedar Communication Module
// Server.c
// VPN Server module
#include "Server.h"
#include "Admin.h"
#include "AzureClient.h"
#include "BridgeUnix.h"
#include "BridgeWin32.h"
#include "Connection.h"
#include "DDNS.h"
#include "Layer3.h"
#include "Link.h"
#include "Listener.h"
#include "Nat.h"
#include "Proto_IPsec.h"
#include "Protocol.h"
#include "Radius.h"
#include "Sam.h"
#include "SecureNAT.h"
#include "WinUi.h"
#include "Mayaqua/Cfg.h"
#include "Mayaqua/DNS.h"
#include "Mayaqua/FileIO.h"
#include "Mayaqua/Internat.h"
#include "Mayaqua/Memory.h"
#include "Mayaqua/Microsoft.h"
#include "Mayaqua/Object.h"
#include "Mayaqua/OS.h"
#include "Mayaqua/Pack.h"
#include "Mayaqua/Str.h"
#include "Mayaqua/Table.h"
#include "Mayaqua/TcpIp.h"
#include "Mayaqua/Tick64.h"
#include "Mayaqua/Win32.h"
static SERVER *server = NULL;
static LOCK *server_lock = NULL;
char *SERVER_CONFIG_FILE_NAME = "$vpn_server.config";
char *SERVER_CONFIG_FILE_NAME_IN_CLIENT = "$vpn_gate_svc.config";
char *SERVER_CONFIG_FILE_NAME_IN_CLIENT_RELAY = "$vpn_gate_relay.config";
char *BRIDGE_CONFIG_FILE_NAME = "$vpn_bridge.config";
char *SERVER_CONFIG_TEMPLATE_NAME = "$vpn_server_template.config";
char *BRIDGE_CONFIG_TEMPLATE_NAME = "$vpn_server_template.config";
static bool server_reset_setting = false;
static volatile UINT global_server_flags[NUM_GLOBAL_SERVER_FLAGS] = {0};
UINT vpn_global_parameters[NUM_GLOBAL_PARAMS] = {0};
// Get whether the number of user objects that are registered in the VPN Server is too many
bool SiTooManyUserObjectsInServer(SERVER *s, bool oneMore)
{
return false;
}
typedef struct SI_DEBUG_PROC_LIST
{
UINT Id;
char *Description;
char *Args;
SI_DEBUG_PROC *Proc;
} SI_DEBUG_PROC_LIST;
// Debugging function
UINT SiDebug(SERVER *s, RPC_TEST *ret, UINT i, char *str)
{
SI_DEBUG_PROC_LIST proc_list[] =
{
{1, "Hello World", "<test string>", SiDebugProcHelloWorld},
{2, "Terminate process now", "", SiDebugProcExit},
{3, "Write memory dumpfile", "", SiDebugProcDump},
{4, "Restore process priority", "", SiDebugProcRestorePriority},
{5, "Set the process priority high", "", SiDebugProcSetHighPriority},
{6, "Get the .exe filename of the process", "", SiDebugProcGetExeFileName},
{7, "Crash the process", "", SiDebugProcCrash},
{8, "Get IPsecMessageDisplayed Flag", "", SiDebugProcGetIPsecMessageDisplayedValue},
{9, "Set IPsecMessageDisplayed Flag", "", SiDebugProcSetIPsecMessageDisplayedValue},
{10, "Get VgsMessageDisplayed Flag", "", SiDebugProcGetVgsMessageDisplayedValue},
{11, "Set VgsMessageDisplayed Flag", "", SiDebugProcSetVgsMessageDisplayedValue},
{12, "Get the current TCP send queue length", "", SiDebugProcGetCurrentTcpSendQueueLength},
{13, "Get the current GetIP thread count", "", SiDebugProcGetCurrentGetIPThreadCount},
};
UINT num_proc_list = sizeof(proc_list) / sizeof(proc_list[0]);
UINT j;
UINT ret_value = ERR_NO_ERROR;
// Validate arguments
if (s == NULL || ret == NULL)
{
return ERR_INVALID_PARAMETER;
}
if (i == 0)
{
char tmp[MAX_SIZE];
Zero(ret, sizeof(RPC_TEST));
StrCat(ret->StrValue, sizeof(ret->StrValue),
"\n--- Debug Functions List --\n");
for (j = 0;j < num_proc_list;j++)
{
SI_DEBUG_PROC_LIST *p = &proc_list[j];
if (IsEmptyStr(p->Args) == false)
{
Format(tmp, sizeof(tmp),
" %u: %s - Usage: %u /ARG:\"%s\"\n",
p->Id, p->Description, p->Id, p->Args);
}
else
{
Format(tmp, sizeof(tmp),
" %u: %s - Usage: %u\n",
p->Id, p->Description, p->Id);
}
StrCat(ret->StrValue, sizeof(ret->StrValue), tmp);
}
}
else
{
ret_value = ERR_NOT_SUPPORTED;
for (j = 0;j < num_proc_list;j++)
{
SI_DEBUG_PROC_LIST *p = &proc_list[j];
if (p->Id == i)
{
ret_value = p->Proc(s, str, ret->StrValue, sizeof(ret->StrValue));
if (ret_value == ERR_NO_ERROR && IsEmptyStr(ret->StrValue))
{
StrCpy(ret->StrValue, sizeof(ret->StrValue), "Ok.");
}
break;
}
}
}
return ret_value;
}
UINT SiDebugProcHelloWorld(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size)
{
// Validate arguments
if (s == NULL || in_str == NULL || ret_str == NULL)
{
return ERR_INVALID_PARAMETER;
}
Format(ret_str, ret_str_size, "Hello World %s\n", in_str);
return ERR_NO_ERROR;
}
UINT SiDebugProcExit(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size)
{
// Validate arguments
if (s == NULL || in_str == NULL || ret_str == NULL)
{
return ERR_INVALID_PARAMETER;
}
_exit(1);
return ERR_NO_ERROR;
}
UINT SiDebugProcDump(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size)
{
// Validate arguments
if (s == NULL || in_str == NULL || ret_str == NULL)
{
return ERR_INVALID_PARAMETER;
}
#ifdef OS_WIN32
MsWriteMinidump(NULL, NULL);
#else // OS_WIN32
return ERR_NOT_SUPPORTED;
#endif // OS_WIN32
return ERR_NO_ERROR;
}
UINT SiDebugProcRestorePriority(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size)
{
// Validate arguments
if (s == NULL || in_str == NULL || ret_str == NULL)
{
return ERR_INVALID_PARAMETER;
}
OSRestorePriority();
return ERR_NO_ERROR;
}
UINT SiDebugProcSetHighPriority(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size)
{
// Validate arguments
if (s == NULL || in_str == NULL || ret_str == NULL)
{
return ERR_INVALID_PARAMETER;
}
OSSetHighPriority();
return ERR_NO_ERROR;
}
UINT SiDebugProcGetExeFileName(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size)
{
// Validate arguments
if (s == NULL || in_str == NULL || ret_str == NULL)
{
return ERR_INVALID_PARAMETER;
}
GetExeName(ret_str, ret_str_size);
return ERR_NO_ERROR;
}
UINT SiDebugProcCrash(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size)
{
// Validate arguments
if (s == NULL || in_str == NULL || ret_str == NULL)
{
return ERR_INVALID_PARAMETER;
}
CrashNow();
return ERR_NO_ERROR;
}
UINT SiDebugProcGetIPsecMessageDisplayedValue(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size)
{
// Validate arguments
if (s == NULL || in_str == NULL || ret_str == NULL)
{
return ERR_INVALID_PARAMETER;
}
ToStr(ret_str, s->IPsecMessageDisplayed);
return ERR_NO_ERROR;
}
UINT SiDebugProcSetIPsecMessageDisplayedValue(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size)
{
// Validate arguments
if (s == NULL || in_str == NULL || ret_str == NULL)
{
return ERR_INVALID_PARAMETER;
}
s->IPsecMessageDisplayed = ToInt(in_str);
return ERR_NO_ERROR;
}
UINT SiDebugProcGetVgsMessageDisplayedValue(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size)
{
// Validate arguments
if (s == NULL || in_str == NULL || ret_str == NULL)
{
return ERR_INVALID_PARAMETER;
}
#if 0
if (VgDoNotPopupMessage() == false)
{
ToStr(ret_str, s->VgsMessageDisplayed);
}
else
{
ToStr(ret_str, 1);
}
#else
// Do not show the VGS message in VPN Server of the current version
ToStr(ret_str, 1);
#endif
return ERR_NO_ERROR;
}
UINT SiDebugProcGetCurrentTcpSendQueueLength(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size)
{
char tmp1[64], tmp2[64], tmp3[64];
// Validate arguments
if (s == NULL || in_str == NULL || ret_str == NULL)
{
return ERR_INVALID_PARAMETER;
}
ToStr3(tmp1, 0, CedarGetCurrentTcpQueueSize(s->Cedar));
ToStr3(tmp2, 0, CedarGetQueueBudgetConsuming(s->Cedar));
ToStr3(tmp3, 0, CedarGetFifoBudgetConsuming(s->Cedar));
Format(ret_str, 0,
"CurrentTcpQueueSize = %s\n"
"QueueBudgetConsuming = %s\n"
"FifoBudgetConsuming = %s\n",
tmp1, tmp2, tmp3);
return ERR_NO_ERROR;
}
UINT SiDebugProcGetCurrentGetIPThreadCount(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size)
{
char tmp1[64], tmp2[64];
// Validate arguments
if (s == NULL || in_str == NULL || ret_str == NULL)
{
return ERR_INVALID_PARAMETER;
}
ToStr3(tmp1, 0, DnsThreadNum());
ToStr3(tmp2, 0, DnsThreadNumMax());
Format(ret_str, 0,
"Current threads = %s\n"
"Quota = %s\n",
tmp1, tmp2);
return ERR_NO_ERROR;
}
UINT SiDebugProcSetVgsMessageDisplayedValue(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size)
{
// Validate arguments
if (s == NULL || in_str == NULL || ret_str == NULL)
{
return ERR_INVALID_PARAMETER;
}
return ERR_NO_ERROR;
}
// Write the debug log
void SiDebugLog(SERVER *s, char *msg)
{
// Validate arguments
if (s == NULL || msg == NULL)
{
return;
}
if (s->DebugLog != NULL)
{
WriteTinyLog(s->DebugLog, msg);
}
}
// Deadlock inspection main
void SiCheckDeadLockMain(SERVER *s, UINT timeout)
{
CEDAR *cedar;
// Validate arguments
if (s == NULL)
{
return;
}
//Debug("SiCheckDeadLockMain Start.\n");
cedar = s->Cedar;
if (s->ServerListenerList != NULL)
{
CheckDeadLock(s->ServerListenerList->lock, timeout, "s->ServerListenerList->lock");
}
CheckDeadLock(s->lock, timeout, "s->lock");
if (s->FarmMemberList != NULL)
{
CheckDeadLock(s->FarmMemberList->lock, timeout, "s->FarmMemberList->lock");
}
if (s->HubCreateHistoryList != NULL)
{
CheckDeadLock(s->HubCreateHistoryList->lock, timeout, "s->HubCreateHistoryList->lock");
}
CheckDeadLock(s->CapsCacheLock, timeout, "s->CapsCacheLock");
CheckDeadLock(s->TasksFromFarmControllerLock, timeout, "s->TasksFromFarmControllerLock");
if (cedar != NULL)
{
if (cedar->HubList != NULL)
{
CheckDeadLock(cedar->HubList->lock, timeout, "cedar->HubList->lock");
}
if (cedar->ListenerList != NULL)
{
UINT i;
LIST *o = NewListFast(NULL);
CheckDeadLock(cedar->ListenerList->lock, timeout, "cedar->ListenerList->lock");
LockList(cedar->ListenerList);
{
for (i = 0;i < LIST_NUM(cedar->ListenerList);i++)
{
LISTENER *r = LIST_DATA(cedar->ListenerList, i);
AddRef(r->ref);
Add(o, r);
}
}
UnlockList(cedar->ListenerList);
for (i = 0;i < LIST_NUM(o);i++)
{
LISTENER *r = LIST_DATA(o, i);
ReleaseListener(r);
}
ReleaseList(o);
}
if (cedar->ConnectionList != NULL)
{
CheckDeadLock(cedar->ConnectionList->lock, timeout, "cedar->ConnectionList->lock");
}
if (cedar->CaList != NULL)
{
CheckDeadLock(cedar->CaList->lock, timeout, "cedar->CaList->lock");
}
if (cedar->WgkList != NULL)
{
CheckDeadLock(cedar->WgkList->lock, timeout, "cedar->WgkList->lock");
}
if (cedar->TrafficLock != NULL)
{
CheckDeadLock(cedar->TrafficLock, timeout, "cedar->TrafficLock");
}
if (cedar->TrafficDiffList != NULL)
{
CheckDeadLock(cedar->TrafficDiffList->lock, timeout, "cedar->TrafficDiffList->lock");
}
if (cedar->LocalBridgeList != NULL)
{
CheckDeadLock(cedar->LocalBridgeList->lock, timeout, "cedar->LocalBridgeList->lock");
}
if (cedar->L3SwList != NULL)
{
CheckDeadLock(cedar->L3SwList->lock, timeout, "cedar->L3SwList->lock");
}
}
//Debug("SiCheckDeadLockMain Finish.\n");
}
// Deadlock check thread
void SiDeadLockCheckThread(THREAD *t, void *param)
{
SERVER *s = (SERVER *)param;
// Validate arguments
if (s == NULL || t == NULL)
{
return;
}
while (true)
{
Wait(s->DeadLockWaitEvent, SERVER_DEADLOCK_CHECK_SPAN);
if (s->HaltDeadLockThread)
{
break;
}
SiCheckDeadLockMain(s, SERVER_DEADLOCK_CHECK_TIMEOUT);
}
}
// Initialize the deadlock check
void SiInitDeadLockCheck(SERVER *s)
{
// Validate arguments
if (s == NULL)
{
return;
}
if (s->DisableDeadLockCheck)
{
return;
}
s->HaltDeadLockThread = false;
s->DeadLockWaitEvent = NewEvent();
s->DeadLockCheckThread = NewThread(SiDeadLockCheckThread, s);
}
// Release the deadlock check
void SiFreeDeadLockCheck(SERVER *s)
{
// Validate arguments
if (s == NULL)
{
return;
}
if (s->DeadLockCheckThread == NULL)
{
return;
}
s->HaltDeadLockThread = true;
Set(s->DeadLockWaitEvent);
WaitThread(s->DeadLockCheckThread, INFINITE);
ReleaseThread(s->DeadLockCheckThread);
s->DeadLockCheckThread = NULL;
ReleaseEvent(s->DeadLockWaitEvent);
s->DeadLockWaitEvent = NULL;
s->HaltDeadLockThread = false;
}
// Check whether the specified virtual HUB has been registered to creation history
bool SiIsHubRegistedOnCreateHistory(SERVER *s, char *name)
{
UINT i;
bool ret = false;
// Validate arguments
if (s == NULL || name == NULL)
{
return false;
}
SiDeleteOldHubCreateHistory(s);
LockList(s->HubCreateHistoryList);
{
for (i = 0;i < LIST_NUM(s->HubCreateHistoryList);i++)
{
SERVER_HUB_CREATE_HISTORY *h = LIST_DATA(s->HubCreateHistoryList, i);
if (StrCmpi(h->HubName, name) == 0)
{
ret = true;
break;
}
}
}
UnlockList(s->HubCreateHistoryList);
return ret;
}
// Delete the Virtual HUB creation history
void SiDelHubCreateHistory(SERVER *s, char *name)
{
UINT i;
// Validate arguments
if (s == NULL || name == NULL)
{
return;
}
LockList(s->HubCreateHistoryList);
{
SERVER_HUB_CREATE_HISTORY *hh = NULL;
for (i = 0;i < LIST_NUM(s->HubCreateHistoryList);i++)
{
SERVER_HUB_CREATE_HISTORY *h = LIST_DATA(s->HubCreateHistoryList, i);
if (StrCmpi(h->HubName, name) == 0)
{
Delete(s->HubCreateHistoryList, h);
Free(h);
break;
}
}
}
UnlockList(s->HubCreateHistoryList);
SiDeleteOldHubCreateHistory(s);
}
// Register to the Virtual HUB creation history
void SiAddHubCreateHistory(SERVER *s, char *name)
{
UINT i;
// Validate arguments
if (s == NULL || name == NULL)
{
return;
}
LockList(s->HubCreateHistoryList);
{
SERVER_HUB_CREATE_HISTORY *hh = NULL;
for (i = 0;i < LIST_NUM(s->HubCreateHistoryList);i++)
{
SERVER_HUB_CREATE_HISTORY *h = LIST_DATA(s->HubCreateHistoryList, i);
if (StrCmpi(h->HubName, name) == 0)
{
hh = h;
break;
}
}
if (hh == NULL)
{
hh = ZeroMalloc(sizeof(SERVER_HUB_CREATE_HISTORY));
StrCpy(hh->HubName, sizeof(hh->HubName), name);
Add(s->HubCreateHistoryList, hh);
}
hh->CreatedTime = Tick64();
}
UnlockList(s->HubCreateHistoryList);
SiDeleteOldHubCreateHistory(s);
}
// Delete outdated Virtual HUB creation histories
void SiDeleteOldHubCreateHistory(SERVER *s)
{
UINT i;
LIST *o;
// Validate arguments
if (s == NULL)
{
return;
}
LockList(s->HubCreateHistoryList);
{
o = NewListFast(NULL);
for (i = 0;i < LIST_NUM(s->HubCreateHistoryList);i++)
{
SERVER_HUB_CREATE_HISTORY *h = LIST_DATA(s->HubCreateHistoryList, i);
if ((h->CreatedTime + ((UINT64)TICKET_EXPIRES)) <= Tick64())
{
// Expired
Add(o, h);
}
}
for (i = 0;i < LIST_NUM(o);i++)
{
SERVER_HUB_CREATE_HISTORY *h = LIST_DATA(o, i);
Delete(s->HubCreateHistoryList, h);
Free(h);
}
ReleaseList(o);
}
UnlockList(s->HubCreateHistoryList);
}
// Initialize the Virtual HUB creation history
void SiInitHubCreateHistory(SERVER *s)
{
// Validate arguments
if (s == NULL)
{
return;
}
s->HubCreateHistoryList = NewList(NULL);
}
// Release the Virtual HUB creation history
void SiFreeHubCreateHistory(SERVER *s)
{
UINT i;
// Validate arguments
if (s == NULL)
{
return;
}
for (i = 0;i < LIST_NUM(s->HubCreateHistoryList);i++)
{
SERVER_HUB_CREATE_HISTORY *h = LIST_DATA(s->HubCreateHistoryList, i);
Free(h);
}
ReleaseList(s->HubCreateHistoryList);
s->HubCreateHistoryList = NULL;
}
// Identify whether the server can be connected from the VPN Client that is
// created by the installer creating kit of Admin Pack
bool IsAdminPackSupportedServerProduct(char *name)
{
return true;
}
// Get the saving status of syslog
UINT SiGetSysLogSaveStatus(SERVER *s)
{
SYSLOG_SETTING set;
// Validate arguments
if (s == NULL)
{
return SYSLOG_NONE;
}
SiGetSysLogSetting(s, &set);
return set.SaveType;
}
// Send a syslog
void SiWriteSysLog(SERVER *s, char *typestr, char *hubname, wchar_t *message)
{
wchar_t tmp[1024];
char machinename[MAX_HOST_NAME_LEN + 1];
char datetime[MAX_PATH];
SYSTEMTIME st;
// Validate arguments
if (s == NULL || typestr == NULL || message == NULL)
{
return;
}
if (GetGlobalServerFlag(GSF_DISABLE_SYSLOG) != 0)
{
return;
}
// Host name
GetMachineName(machinename, sizeof(machinename));
// Date and time
LocalTime(&st);
if(s->StrictSyslogDatetimeFormat){
GetDateTimeStrRFC3339(datetime, sizeof(datetime), &st, GetCurrentTimezone());
}else{
GetDateTimeStrMilli(datetime, sizeof(datetime), &st);
}
if (IsEmptyStr(hubname) == false)
{
UniFormat(tmp, sizeof(tmp), L"[%S/VPN/%S] (%S) <%S>: %s",
machinename, hubname, datetime, typestr, message);
}
else
{
UniFormat(tmp, sizeof(tmp), L"[%S/VPN] (%S) <%S>: %s",
machinename, datetime, typestr, message);
}
Debug("Syslog send: %S\n",tmp);
SendSysLog(s->Syslog, tmp);
}
// Write the syslog configuration
void SiSetSysLogSetting(SERVER *s, SYSLOG_SETTING *setting)
{
SYSLOG_SETTING set;
// Validate arguments
if (s == NULL || setting == NULL)
{
return;
}
Zero(&set, sizeof(set));
Copy(&set, setting, sizeof(SYSLOG_SETTING));
if (IsEmptyStr(set.Hostname) || set.Port == 0)
{
set.SaveType = SYSLOG_NONE;
}
Lock(s->SyslogLock);
{
Copy(&s->SyslogSetting, &set, sizeof(SYSLOG_SETTING));
SetSysLog(s->Syslog, set.Hostname, set.Port);
}
Unlock(s->SyslogLock);
}
// Read the syslog configuration
void SiGetSysLogSetting(SERVER *s, SYSLOG_SETTING *setting)
{
// Validate arguments
if (s == NULL || setting == NULL)
{
return;
}
//Lock(s->SyslogLock);
{
Copy(setting, &s->SyslogSetting, sizeof(SYSLOG_SETTING));
}
//Unlock(s->SyslogLock);
}
// Get the server product name
void GetServerProductName(SERVER *s, char *name, UINT size)
{
char *cpu;
// Validate arguments
if (s == NULL || name == NULL)
{
return;
}
GetServerProductNameInternal(s, name, size);
#ifdef CPU_64
cpu = " (64 bit)";
#else // CPU_64
cpu = " (32 bit)";
#endif // CPU_64
StrCat(name, size, cpu);
StrCat(name, size, " (Open Source)");
}
void GetServerProductNameInternal(SERVER *s, char *name, UINT size)
{
// Validate arguments
if (s == NULL || name == NULL)
{
return;
}
#ifdef BETA_NUMBER
if (s->Cedar->Bridge)
{
StrCpy(name, size, CEDAR_BRIDGE_STR);
}
else
{
StrCpy(name, size, CEDAR_BETA_SERVER);
}
return;
#else // BETA_NUMBER
if (s->Cedar->Bridge)
{
StrCpy(name, size, CEDAR_BRIDGE_STR);
}
else
{
StrCpy(name, size, CEDAR_SERVER_STR);
}
#endif // BETA_NUMBER
}
// Check whether the log file with the specified name is contained in the enumerated list
bool CheckLogFileNameFromEnumList(LIST *o, char *name, char *server_name)
{
LOG_FILE t;
// Validate arguments
if (o == NULL || name == NULL || server_name == NULL)
{
return false;
}
Zero(&t, sizeof(t));
StrCpy(t.Path, sizeof(t.Path), name);
StrCpy(t.ServerName, sizeof(t.ServerName), server_name);
if (Search(o, &t) == NULL)
{
return false;
}
return true;
}
// Release the log file enumeration
void FreeEnumLogFile(LIST *o)
{
UINT i;
// Validate arguments
if (o == NULL)
{
return;
}
for (i = 0;i < LIST_NUM(o);i++)
{
LOG_FILE *f = LIST_DATA(o, i);
Free(f);
}
ReleaseList(o);
}
// Enumerate the log files associated with the virtual HUB (All logs are listed in the case of server administrator)
LIST *EnumLogFile(char *hubname)
{
char exe_dir[MAX_PATH];
char tmp[MAX_PATH];
LIST *o = NewListFast(CmpLogFile);
DIRLIST *dir;
if (StrLen(hubname) == 0)
{
hubname = NULL;
}
GetLogDir(exe_dir, sizeof(exe_dir));
// Enumerate in the server_log
if (hubname == NULL)
{
EnumLogFileDir(o, SERVER_LOG_DIR);
}
// Enumerate in the packet_log
Format(tmp, sizeof(tmp), "%s/"HUB_PACKET_LOG_DIR, exe_dir);
if (hubname == NULL)
{
dir = EnumDir(tmp);
if (dir != NULL)
{
UINT i;
for (i = 0;i < dir->NumFiles;i++)
{
DIRENT *e = dir->File[i];
if (e->Folder)
{
char dir_name[MAX_PATH];
Format(dir_name, sizeof(dir_name), HUB_PACKET_LOG_DIR"/%s", e->FileName);
EnumLogFileDir(o, dir_name);
}
}
FreeDir(dir);
}
}
else
{
char dir_name[MAX_PATH];
Format(dir_name, sizeof(dir_name), HUB_PACKET_LOG_DIR"/%s", hubname);
EnumLogFileDir(o, dir_name);
}
// Enumerate in the security_log
Format(tmp, sizeof(tmp), "%s/"HUB_SECURITY_LOG_DIR, exe_dir);
if (hubname == NULL)
{
dir = EnumDir(tmp);
if (dir != NULL)
{
UINT i;
for (i = 0;i < dir->NumFiles;i++)
{
DIRENT *e = dir->File[i];
if (e->Folder)
{
char dir_name[MAX_PATH];
Format(dir_name, sizeof(dir_name), HUB_SECURITY_LOG_DIR"/%s", e->FileName);
EnumLogFileDir(o, dir_name);
}
}
FreeDir(dir);
}
}
else
{
char dir_name[MAX_PATH];
Format(dir_name, sizeof(dir_name), HUB_SECURITY_LOG_DIR"/%s", hubname);
EnumLogFileDir(o, dir_name);
}
return o;
}
// Enumerate log files in the specified directory
void EnumLogFileDir(LIST *o, char *dirname)
{
UINT i;
char exe_dir[MAX_PATH];
char dir_full_path[MAX_PATH];
DIRLIST *dir;
// Validate arguments
if (o == NULL || dirname == NULL)
{
return;
}
GetLogDir(exe_dir, sizeof(exe_dir));
Format(dir_full_path, sizeof(dir_full_path), "%s/%s", exe_dir, dirname);
dir = EnumDir(dir_full_path);
if (dir == NULL)
{
return;
}
for (i = 0;i < dir->NumFiles;i++)
{
DIRENT *e = dir->File[i];
if (e->Folder == false && e->FileSize > 0)
{
char full_path[MAX_PATH];
char file_path[MAX_PATH];
Format(file_path, sizeof(file_path), "%s/%s", dirname, e->FileName);
Format(full_path, sizeof(full_path), "%s/%s", exe_dir, file_path);
if (EndWith(file_path, ".log"))
{
LOG_FILE *f = ZeroMalloc(sizeof(LOG_FILE));
StrCpy(f->Path, sizeof(f->Path), file_path);
f->FileSize = (UINT)(MIN(e->FileSize, 0xffffffffUL));
f->UpdatedTime = e->UpdateDate;
GetMachineName(f->ServerName, sizeof(f->ServerName));
Insert(o, f);
}
}
}
FreeDir(dir);
}
// Log file list entry comparison
int CmpLogFile(void *p1, void *p2)
{
LOG_FILE *f1, *f2;
UINT i;
if (p1 == NULL || p2 == NULL)
{
return 0;
}
f1 = *(LOG_FILE **)p1;
f2 = *(LOG_FILE **)p2;
if (f1 == NULL || f2 == NULL)
{
return 0;
}
i = StrCmpi(f1->Path, f2->Path);
if (i != 0)
{
return i;
}
return StrCmpi(f1->ServerName, f2->ServerName);
}
// Get the Caps of the server
UINT GetServerCapsInt(SERVER *s, char *name)
{
CAPSLIST t;
UINT ret;
// Validate arguments
if (s == NULL || name == NULL)
{
return 0;
}
Lock(s->CapsCacheLock);
{
Zero(&t, sizeof(t));
GetServerCaps(s, &t);
ret = GetCapsInt(&t, name);
}
Unlock(s->CapsCacheLock);
return ret;
}
bool GetServerCapsBool(SERVER *s, char *name)
{
return (GetServerCapsInt(s, name) == 0) ? false : true;
}
// Initialize the Caps cache of the server
void InitServerCapsCache(SERVER *s)
{
// Validate arguments
if (s == NULL)
{
return;
}
s->CapsCacheLock = NewLock();
s->CapsListCache = NULL;
}
// Release the Caps cache of the server
void FreeServerCapsCache(SERVER *s)
{
// Validate arguments
if (s == NULL)
{
return;
}
if (s->CapsListCache != NULL)
{
FreeCapsList(s->CapsListCache);
s->CapsListCache = NULL;
}
DeleteLock(s->CapsCacheLock);
}
// Dispose the Caps cache of the server
void DestroyServerCapsCache(SERVER *s)
{
// Validate arguments
if (s == NULL)
{
return;
}
Lock(s->CapsCacheLock);
{
if (s->CapsListCache != NULL)
{
FreeCapsList(s->CapsListCache);
s->CapsListCache = NULL;
}
}
Unlock(s->CapsCacheLock);
}
// Flush the Caps list for this server
void FlushServerCaps(SERVER *s)
{
CAPSLIST t;
// Validate arguments
if (s == NULL)
{
return;
}
Lock(s->CapsCacheLock);
{
DestroyServerCapsCache(s);
Zero(&t, sizeof(t));
GetServerCaps(s, &t);
}
Unlock(s->CapsCacheLock);
}
// Get the Caps list for this server
void GetServerCaps(SERVER *s, CAPSLIST *t)
{
// Validate arguments
if (s == NULL || t == NULL)
{
return;
}
Lock(s->CapsCacheLock);
{
if (s->CapsListCache == NULL)
{
s->CapsListCache = ZeroMalloc(sizeof(CAPSLIST));
GetServerCapsMain(s, s->CapsListCache);
}
Copy(t, s->CapsListCache, sizeof(CAPSLIST));
}
Unlock(s->CapsCacheLock);
}
// Update the global server flags
void UpdateGlobalServerFlags(SERVER *s, CAPSLIST *t)
{
bool is_restricted = false;
// Validate arguments
if (s == NULL || t == NULL)
{
return;
}
is_restricted = SiIsEnterpriseFunctionsRestrictedOnOpenSource(s->Cedar);
SetGlobalServerFlag(GSF_DISABLE_PUSH_ROUTE, is_restricted);
SetGlobalServerFlag(GSF_DISABLE_RADIUS_AUTH, is_restricted);
SetGlobalServerFlag(GSF_DISABLE_CERT_AUTH, is_restricted);
SetGlobalServerFlag(GSF_DISABLE_DEEP_LOGGING, is_restricted);
SetGlobalServerFlag(GSF_DISABLE_AC, is_restricted);
SetGlobalServerFlag(GSF_DISABLE_SYSLOG, is_restricted);
}
// Set a global server flag
void SetGlobalServerFlag(UINT index, UINT value)
{
// Validate arguments
if (index >= NUM_GLOBAL_SERVER_FLAGS)
{
return;
}
global_server_flags[index] = value;
}
// Get a global server flag
UINT GetGlobalServerFlag(UINT index)
{
// Validate arguments
if (index >= NUM_GLOBAL_SERVER_FLAGS)
{
return 0;
}
return global_server_flags[index];
}
// Main of the acquisition of Caps of the server
void GetServerCapsMain(SERVER *s, CAPSLIST *t)
{
bool is_restricted = false;
// Validate arguments
if (s == NULL || t == NULL)
{
return;
}
is_restricted = SiIsEnterpriseFunctionsRestrictedOnOpenSource(s->Cedar);
// Initialize
InitCapsList(t);
// Maximum Ethernet packet size
AddCapsInt(t, "i_max_packet_size", MAX_PACKET_SIZE);
if (s->Cedar->Bridge == false)
{
UINT max_sessions, max_clients, max_bridges, max_user_creations;
max_clients = INFINITE;
max_bridges = INFINITE;
max_sessions = SERVER_MAX_SESSIONS_FOR_CARRIER_EDITION;
max_user_creations = INFINITE;
// Maximum number of virtual HUBs
AddCapsInt(t, "i_max_hubs", SERVER_MAX_SESSIONS_FOR_CARRIER_EDITION);
// The maximum number of concurrent sessions
AddCapsInt(t, "i_max_sessions", max_sessions);
// Maximum number of creatable users
AddCapsInt(t, "i_max_user_creation", max_user_creations);
// Maximum number of clients
AddCapsInt(t, "i_max_clients", max_clients);
// Maximum number of bridges
AddCapsInt(t, "i_max_bridges", max_bridges);
if (s->ServerType != SERVER_TYPE_FARM_MEMBER)
{
// Maximum number of registrable users / Virtual HUB
AddCapsInt(t, "i_max_users_per_hub", MAX_USERS);
// Maximum number of registrable groups / Virtual HUB
AddCapsInt(t, "i_max_groups_per_hub", MAX_GROUPS);
// Maximum number of registrable access list entries / Virtual HUB
AddCapsInt(t, "i_max_access_lists", MAX_ACCESSLISTS);
}
else
{
// Maximum number of registrable users / Virtual HUB
AddCapsInt(t, "i_max_users_per_hub", 0);
// Maximum number of registrable groups / Virtual HUB
AddCapsInt(t, "i_max_groups_per_hub", 0);
// Maximum number of registrable access list entries / Virtual HUB
AddCapsInt(t, "i_max_access_lists", 0);
}
// The policy related to multiple logins
AddCapsBool(t, "b_support_limit_multilogin", true);
// QoS / VoIP
AddCapsBool(t, "b_support_qos", true);
// syslog
AddCapsBool(t, "b_support_syslog", true);
// IPsec
// (Only works in stand-alone mode currently)
AddCapsBool(t, "b_support_ipsec", (s->ServerType == SERVER_TYPE_STANDALONE));
// SSTP
// (Only works in stand-alone mode currently)
AddCapsBool(t, "b_support_sstp", (s->ServerType == SERVER_TYPE_STANDALONE));
// OpenVPN
// (Only works in stand-alone mode currently)
AddCapsBool(t, "b_support_openvpn", (s->ServerType == SERVER_TYPE_STANDALONE));
// DDNS
AddCapsBool(t, "b_support_ddns", (s->DDnsClient != NULL));
if (s->DDnsClient != NULL)
{
// DDNS via Proxy
AddCapsBool(t, "b_support_ddns_proxy", true);
}
// VPN over ICMP, VPN over DNS
AddCapsBool(t, "b_support_special_listener", true);
}
else
{
// Maximum number of virtual HUBs
AddCapsInt(t, "i_max_hubs", 0);
// The maximum number of concurrent sessions
AddCapsInt(t, "i_max_sessions", 0);
// Maximum number of clients
AddCapsInt(t, "i_max_clients", 0);
// Maximum number of bridges
AddCapsInt(t, "i_max_bridges", 0);
// Maximum number of registrable users / Virtual HUB
AddCapsInt(t, "i_max_users_per_hub", 0);
// Maximum number of registrable groups / Virtual HUB
AddCapsInt(t, "i_max_groups_per_hub", 0);
// Maximum number of registrable access list entries / Virtual HUB
AddCapsInt(t, "i_max_access_lists", 0);
// QoS / VoIP
AddCapsBool(t, "b_support_qos", true);
// syslog
AddCapsBool(t, "b_support_syslog", true);
// IPsec
AddCapsBool(t, "b_support_ipsec", false);
// SSTP
AddCapsBool(t, "b_support_sstp", false);
// OpenVPN
AddCapsBool(t, "b_support_openvpn", false);
// DDNS
AddCapsBool(t, "b_support_ddns", false);
// VPN over ICMP, VPN over DNS
AddCapsBool(t, "b_support_special_listener", false);
}
// Changing the type of Virtual HUB in cluster is prohibited
AddCapsBool(t, "b_cluster_hub_type_fixed", true);
// Maximum MAC address table size / Virtual HUB
AddCapsInt(t, "i_max_mac_tables", MAX_MAC_TABLES);
// Maximum IP address table size / Virtual HUB
AddCapsInt(t, "i_max_ip_tables", MAX_IP_TABLES);
// SecureNAT function is available
AddCapsBool(t, "b_support_securenat", true);
// Pushing routing table function of SecureNAT Virtual DHCP Server is available
AddCapsBool(t, "b_suppport_push_route", !is_restricted);
AddCapsBool(t, "b_suppport_push_route_config", true);
if (s->ServerType != SERVER_TYPE_STANDALONE)
{
AddCapsBool(t, "b_virtual_nat_disabled", true);
}
// Maximum NAT table size / Virtual HUB
AddCapsInt(t, "i_max_secnat_tables", NAT_MAX_SESSIONS);
// Cascade connection
if (s->ServerType == SERVER_TYPE_STANDALONE)
{
AddCapsBool(t, "b_support_cascade", true);
}
else
{
AddCapsBool(t, "b_support_cascade", false);
}
if (s->Cedar->Bridge)
{
// Bridge mode
AddCapsBool(t, "b_bridge", true);
}
else if (s->ServerType == SERVER_TYPE_STANDALONE)
{
// Stand-alone mode
AddCapsBool(t, "b_standalone", true);
}
else if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
{
// Cluster controller mode
AddCapsBool(t, "b_cluster_controller", true);
}
else
{
// Cluster member mode
AddCapsBool(t, "b_cluster_member", true);
}
// Virtual HUB is modifiable
AddCapsBool(t, "b_support_config_hub", s->ServerType != SERVER_TYPE_FARM_MEMBER &&
s->Cedar->Bridge == false);
// VPN client can be connected
AddCapsBool(t, "b_vpn_client_connect", s->Cedar->Bridge == false ? true : false);
// External authentication server is available
AddCapsBool(t, "b_support_radius", s->ServerType != SERVER_TYPE_FARM_MEMBER &&
s->Cedar->Bridge == false);
// Local-bridge function is available
AddCapsBool(t, "b_local_bridge", IsBridgeSupported());
if (OS_IS_WINDOWS(GetOsInfo()->OsType))
{
// Packet capture driver is not installed
AddCapsBool(t, "b_must_install_pcap", IsEthSupported() == false ? true : false);
}
else
{
// Regard that the driver is installed in the Linux version
AddCapsBool(t, "b_must_install_pcap", false);
}
if (IsBridgeSupported())
{
// TUN / TAP device availability (Linux and BSD)
const UINT OsType = GetOsInfo()->OsType;
AddCapsBool(t, "b_tap_supported", OsType == OSTYPE_LINUX || OsType == OSTYPE_BSD);
}
// Cascade connection
if (s->ServerType == SERVER_TYPE_STANDALONE)
{
AddCapsBool(t, "b_support_cascade", true);
}
else
{
AddCapsBool(t, "b_support_cascade", false);
}
// Server authentication can be used in cascade connection
AddCapsBool(t, "b_support_cascade_cert", true);
// the log file settings is modifiable
AddCapsBool(t, "b_support_config_log", s->ServerType != SERVER_TYPE_FARM_MEMBER);
// Automatic deletion of log file is available
AddCapsBool(t, "b_support_autodelete", true);
// Config file operation is available
AddCapsBool(t, "b_support_config_rw", true);
// Attribute of each Virtual HUB can be set
AddCapsBool(t, "b_support_hub_admin_option", true);
// Client certificate can be set in a cascade connection
AddCapsBool(t, "b_support_cascade_client_cert", true);
// Virtual HUB can be hidden
AddCapsBool(t, "b_support_hide_hub", true);
// Integrated management
AddCapsBool(t, "b_support_cluster_admin", true);
// Flag of open-source version
AddCapsBool(t, "b_is_softether", true);
if (s->Cedar->Bridge == false)
{
// The virtual layer 3 switch function is available
AddCapsBool(t, "b_support_layer3", true);
AddCapsInt(t, "i_max_l3_sw", MAX_NUM_L3_SWITCH);
AddCapsInt(t, "i_max_l3_if", MAX_NUM_L3_IF);
AddCapsInt(t, "i_max_l3_table", MAX_NUM_L3_TABLE);
// Can act as a part of a cluster
AddCapsBool(t, "b_support_cluster", true);
}
else
{
AddCapsBool(t, "b_support_layer3", false);
AddCapsInt(t, "i_max_l3_sw", 0);
AddCapsInt(t, "i_max_l3_if", 0);
AddCapsInt(t, "i_max_l3_table", 0);
AddCapsBool(t, "b_support_cluster", false);
}
if (s->ServerType != SERVER_TYPE_FARM_MEMBER && s->Cedar->Bridge == false)
{
// Support for CRL
AddCapsBool(t, "b_support_crl", true);
// Supports AC
AddCapsBool(t, "b_support_ac", true);
}
// Supports downloading a log file
AddCapsBool(t, "b_support_read_log", true);
// Cascade connection can be renamed
AddCapsBool(t, "b_support_rename_cascade", true);
if (s->Cedar->Beta)
{
// Beta version
AddCapsBool(t, "b_beta_version", true);
}
// VM discrimination
AddCapsBool(t, "b_is_in_vm", s->IsInVm);
// Support for display name of the network connection for the local bridge
#ifdef OS_WIN32
if (IsBridgeSupported() && IsNt() && GetOsInfo()->OsType >= OSTYPE_WINDOWS_2000_PROFESSIONAL)
{
AddCapsBool(t, "b_support_network_connection_name", true);
}
#else // OS_WIN32
if (IsBridgeSupported() && EthIsInterfaceDescriptionSupportedUnix())
{
AddCapsBool(t, "b_support_network_connection_name", true);
}
#endif // OS_WIN32
// Support for MAC address filtering
AddCapsBool(t, "b_support_check_mac", true);
// Support for status check of the TCP connection
AddCapsBool(t, "b_support_check_tcp_state", true);
// Can specify multiple server and retry intervals in Radius authentication
AddCapsBool(t, "b_support_radius_retry_interval_and_several_servers", s->ServerType != SERVER_TYPE_FARM_MEMBER &&
s->Cedar->Bridge == false);
// Can manage the ID of the tagged VLAN in the MAC address table
AddCapsBool(t, "b_support_vlan", true);
// Support for Virtual HUB extended options
if ((s->Cedar->Bridge == false) &&
(s->ServerType == SERVER_TYPE_STANDALONE || s->ServerType == SERVER_TYPE_FARM_CONTROLLER))
{
AddCapsBool(t, "b_support_hub_ext_options", true);
}
else
{
AddCapsBool(t, "b_support_hub_ext_options", false);
}
// Support for Security Policy version 3.0
AddCapsBool(t, "b_support_policy_ver_3", true);
// Support for IPv6 access list
AddCapsBool(t, "b_support_ipv6_acl", true);
// Support for setting of delay, jitter and packet loss in the access list
AddCapsBool(t, "b_support_ex_acl", true);
// Support for URL redirection in the access list
AddCapsBool(t, "b_support_redirect_url_acl", true);
// Supports the specification by the group name in the access list
AddCapsBool(t, "b_support_acl_group", true);
// Support for IPv6 in connection source IP restriction list
AddCapsBool(t, "b_support_ipv6_ac", true);
// Support for VLAN tagged packet transmission configuration tool
AddCapsBool(t, "b_support_eth_vlan", true);
// Support for the message display function when the VPN connect to the Virtual HUB
AddCapsBool(t, "b_support_msg", true);
// UDP acceleration feature
AddCapsBool(t, "b_support_udp_acceleration", true);
// AES acceleration function
AddCapsBool(t, "b_support_aes_ni", IsAesNiSupported());
#ifdef OS_WIN32
// SeLow driver
AddCapsBool(t, "b_using_selow_driver", Win32IsUsingSeLow());
#endif // OS_WIN32
// VPN Azure function
AddCapsBool(t, "b_support_azure", SiIsAzureSupported(s));
// VPN3
AddCapsBool(t, "b_vpn3", true);
// VPN4
AddCapsBool(t, "b_vpn4", true);
UpdateGlobalServerFlags(s, t);
}
// SYSLOG_SETTING
void InRpcSysLogSetting(SYSLOG_SETTING *t, PACK *p)
{
// Validate arguments
if (t == NULL || p == NULL)
{
return;
}
Zero(t, sizeof(SYSLOG_SETTING));
t->SaveType = PackGetInt(p, "SaveType");
t->Port = PackGetInt(p, "Port");
PackGetStr(p, "Hostname", t->Hostname, sizeof(t->Hostname));
}
void OutRpcSysLogSetting(PACK *p, SYSLOG_SETTING *t)
{
// Validate arguments
if (t == NULL || p == NULL)
{
return;
}
PackAddInt(p, "SaveType", t->SaveType);
PackAddInt(p, "Port", t->Port);
PackAddStr(p, "Hostname", t->Hostname);
}
// CAPSLIST
void InitCapsList(CAPSLIST *t)
{
// Validate arguments
if (t == NULL)
{
return;
}
Zero(t, sizeof(CAPSLIST));
t->CapsList = NewListFast(NULL);
}
void InRpcCapsList(CAPSLIST *t, PACK *p)
{
UINT i;
// Validate arguments
if (t == NULL || p == NULL)
{
return;
}
Zero(t, sizeof(CAPSLIST));
t->CapsList = NewListFast(CompareCaps);
for (i = 0;i < LIST_NUM(p->elements);i++)
{
ELEMENT *e = LIST_DATA(p->elements, i);
if (StartWith(e->name, "caps_") && e->type == VALUE_INT && e->num_value == 1)
{
CAPS *c = NewCaps(e->name + 5, e->values[0]->IntValue);
Insert(t->CapsList, c);
}
}
}
void OutRpcCapsList(PACK *p, CAPSLIST *t)
{
UINT i;
// Validate arguments
if (t == NULL || p == NULL)
{
return;
}
PackSetCurrentJsonGroupName(p, "CapsList");
for (i = 0;i < LIST_NUM(t->CapsList);i++)
{
char tmp[MAX_SIZE];
char ct_key[MAX_PATH];
wchar_t ct_description[MAX_PATH];
wchar_t *w;
CAPS *c = LIST_DATA(t->CapsList, i);
Format(tmp, sizeof(tmp), "caps_%s", c->Name);
Format(ct_key, sizeof(ct_key), "CT_%s", c->Name);
Zero(ct_description, sizeof(ct_description));
w = _UU(ct_key);
if (UniIsEmptyStr(w) == false)
{
UniStrCpy(ct_description, sizeof(ct_description), w);
}
else
{
StrToUni(ct_description, sizeof(ct_description), c->Name);
}
PackAddInt(p, tmp, c->Value);
PackAddStrEx(p, "CapsName", c->Name, i, LIST_NUM(t->CapsList));
PackAddIntEx(p, "CapsValue", c->Value, i, LIST_NUM(t->CapsList));
PackAddUniStrEx(p, "CapsDescrption", ct_description, i, LIST_NUM(t->CapsList));
}
PackSetCurrentJsonGroupName(p, NULL);
}
void FreeRpcCapsList(CAPSLIST *t)
{
UINT i;
// Validate arguments
if (t == NULL)
{
return;
}
for (i = 0;i < LIST_NUM(t->CapsList);i++)
{
CAPS *c = LIST_DATA(t->CapsList, i);
FreeCaps(c);
}
ReleaseList(t->CapsList);
}
// Add a bool type to Caps list
void AddCapsBool(CAPSLIST *caps, char *name, bool b)
{
CAPS *c;
// Validate arguments
if (caps == NULL || name == NULL)
{
return;
}
c = NewCaps(name, b == false ? 0 : 1);
AddCaps(caps, c);
}
// Add the int type to Caps list
void AddCapsInt(CAPSLIST *caps, char *name, UINT i)
{
CAPS *c;
// Validate arguments
if (caps == NULL || name == NULL)
{
return;
}
c = NewCaps(name, i);
AddCaps(caps, c);
}
// Get the int type from the Caps list
UINT GetCapsInt(CAPSLIST *caps, char *name)
{
CAPS *c;
// Validate arguments
if (caps == NULL || name == NULL)
{
return 0;
}
c = GetCaps(caps, name);
if (c == NULL)
{
return 0;
}
return c->Value;
}
// Get bool type from the Caps list
bool GetCapsBool(CAPSLIST *caps, char *name)
{
CAPS *c;
// Validate arguments
if (caps == NULL || name == NULL)
{
return false;
}
c = GetCaps(caps, name);
if (c == NULL)
{
return false;
}
return c->Value == 0 ? false : true;
}
// Release the Caps list
void FreeCapsList(CAPSLIST *caps)
{
UINT i;
// Validate arguments
if (caps == NULL)
{
return;
}
for (i = 0;i < LIST_NUM(caps->CapsList);i++)
{
CAPS *c = LIST_DATA(caps->CapsList, i);
FreeCaps(c);
}
ReleaseList(caps->CapsList);
Free(caps);
}
// Get the Caps
CAPS *GetCaps(CAPSLIST *caps, char *name)
{
UINT i;
// Validate arguments
if (caps == NULL || name == NULL)
{
return NULL;
}
for (i = 0;i < LIST_NUM(caps->CapsList);i++)
{
CAPS *c = LIST_DATA(caps->CapsList, i);
if (StrCmpi(c->Name, name) == 0)
{
return c;
}
}
return NULL;
}
// Add to the Caps
void AddCaps(CAPSLIST *caps, CAPS *c)
{
// Validate arguments
if (caps == NULL || c == NULL)
{
return;
}
Insert(caps->CapsList, c);
}
// Comparison of Caps
int CompareCaps(void *p1, void *p2)
{
CAPS *c1, *c2;
if (p1 == NULL || p2 == NULL)
{
return 0;
}
c1 = *(CAPS **)p1;
c2 = *(CAPS **)p2;
if (c1 == NULL || c2 == NULL)
{
return 0;
}
return StrCmpi(c1->Name, c2->Name);
}
// Create a Caps list
CAPSLIST *NewCapsList()
{
CAPSLIST *caps = ZeroMalloc(sizeof(CAPSLIST));
caps->CapsList = NewListFast(CompareCaps);
return caps;
}
// Release the Caps
void FreeCaps(CAPS *c)
{
// Validate arguments
if (c == NULL)
{
return;
}
Free(c->Name);
Free(c);
}
// Create a Caps
CAPS *NewCaps(char *name, UINT value)
{
CAPS *c;
// Validate arguments
if (name == NULL)
{
return NULL;
}
c = ZeroMalloc(sizeof(CAPS));
c->Name = CopyStr(name);
c->Value = value;
return c;
}
// Calculate the score from the current number of connections and weight
UINT SiCalcPoint(SERVER *s, UINT num, UINT weight)
{
UINT server_max_sessions = SERVER_MAX_SESSIONS;
if (s == NULL)
{
return 0;
}
if (weight == 0)
{
weight = 100;
}
server_max_sessions = GetServerCapsInt(s, "i_max_sessions");
if (server_max_sessions == 0)
{
// Avoid divide by zero
server_max_sessions = 1;
}
return (UINT)(((double)server_max_sessions -
MIN((double)num * 100.0 / (double)weight, (double)server_max_sessions))
* (double)FARM_BASE_POINT / (double)server_max_sessions);
}
// Get the server score
UINT SiGetPoint(SERVER *s)
{
UINT num_session;
// Validate arguments
if (s == NULL)
{
return 0;
}
num_session = Count(s->Cedar->CurrentSessions);
return SiCalcPoint(s, num_session, s->Weight);
}
// Generate the default certificate
void SiGenerateDefaultCert(X **server_x, K **server_k)
{
SiGenerateDefaultCertEx(server_x, server_k, NULL);
}
void SiGenerateDefaultCertEx(X **server_x, K **server_k, char *common_name)
{
X *x;
K *private_key, *public_key;
NAME *name;
char tmp[MAX_SIZE];
wchar_t cn[MAX_SIZE];
// Validate arguments
if (server_x == NULL || server_k == NULL)
{
return;
}
// Create a key pair
RsaGen(&private_key, &public_key, 2048);
if (IsEmptyStr(common_name))
{
// Get the host name
StrCpy(tmp, sizeof(tmp), "server.softether.vpn");
GetMachineName(tmp, sizeof(tmp));
StrToUni(cn, sizeof(cn), tmp);
}
else
{
StrToUni(cn, sizeof(cn), common_name);
}
name = NewName(cn, cn, cn,
L"US", NULL, NULL);
x = NewRootX(public_key, private_key, name, GetDaysUntil2038Ex(), NULL);
*server_x = x;
*server_k = private_key;
FreeName(name);
FreeK(public_key);
}
// Set the server certificate to default
void SiInitDefaultServerCert(SERVER *s)
{
X *x = NULL;
K *k = NULL;
// Validate arguments
if (s == NULL)
{
return;
}
// Generate a server certificate and private key
SiGenerateDefaultCert(&x, &k);
// Configure
SetCedarCert(s->Cedar, x, k);
FreeX(x);
FreeK(k);
}
// Set the encryption algorithm name to default
void SiInitCipherName(SERVER *s)
{
// Validate arguments
if (s == NULL)
{
return;
}
SetCedarCipherList(s->Cedar, SERVER_DEFAULT_CIPHER_NAME);
}
// Initialize the listener list
void SiInitListenerList(SERVER *s)
{
// Validate arguments
if (s == NULL)
{
return;
}
SiLockListenerList(s);
{
{
// Register the 4 ports (443, 992, 1194, 8888) as the default port
SiAddListener(s, SERVER_DEF_PORTS_1, true);
SiAddListener(s, SERVER_DEF_PORTS_2, true);
SiAddListener(s, SERVER_DEF_PORTS_3, true);
SiAddListener(s, SERVER_DEF_PORTS_4, true);
}
}
SiUnlockListenerList(s);
}
// Remove the listener
bool SiDeleteListener(SERVER *s, UINT port)
{
SERVER_LISTENER *e;
// Validate arguments
if (s == NULL || port == 0)
{
return false;
}
e = SiGetListener(s, port);
if (e == NULL)
{
return false;
}
// Stop if still alive
SiDisableListener(s, port);
if (e->Listener != NULL)
{
ReleaseListener(e->Listener);
}
Delete(s->ServerListenerList, e);
Free(e);
return true;
}
// Compare the SERVER_LISTENER
int CompareServerListener(void *p1, void *p2)
{
SERVER_LISTENER *s1, *s2;
if (p1 == NULL || p2 == NULL)
{
return 0;
}
s1 = *(SERVER_LISTENER **)p1;
s2 = *(SERVER_LISTENER **)p2;
if (s1 == NULL || s2 == NULL)
{
return 0;
}
if (s1->Port > s2->Port)
{
return 1;
}
else if (s1->Port < s2->Port)
{
return -1;
}
else
{
return 0;
}
}
// Stop the listener
bool SiDisableListener(SERVER *s, UINT port)
{
SERVER_LISTENER *e;
// Validate arguments
if (s == NULL || port == 0)
{
return false;
}
// Get the listener
e = SiGetListener(s, port);
if (e == NULL)
{
return false;
}
if (e->Enabled == false || e->Listener == NULL)
{
// Already stopped
return true;
}
// Stop the listener
StopListener(e->Listener);
// Release the listener
ReleaseListener(e->Listener);
e->Listener = NULL;
e->Enabled = false;
return true;
}
// Start the listener
bool SiEnableListener(SERVER *s, UINT port)
{
SERVER_LISTENER *e;
// Validate arguments
if (s == NULL || port == 0)
{
return false;
}
// Get the listener
e = SiGetListener(s, port);
if (e == NULL)
{
return false;
}
if (e->Enabled)
{
// It has already started
return true;
}
// Create a listener
e->Listener = NewListener(s->Cedar, LISTENER_TCP, e->Port);
if (e->Listener == NULL)
{
// Failure
return false;
}
e->Listener->DisableDos = e->DisableDos;
e->Enabled = true;
return true;
}
// Get the listener
SERVER_LISTENER *SiGetListener(SERVER *s, UINT port)
{
UINT i;
// Validate arguments
if (s == NULL || port == 0)
{
return NULL;
}
for (i = 0;i < LIST_NUM(s->ServerListenerList);i++)
{
SERVER_LISTENER *e = LIST_DATA(s->ServerListenerList, i);
if (e->Port == port)
{
return e;
}
}
return NULL;
}
// Add a listener
bool SiAddListener(SERVER *s, UINT port, bool enabled)
{
return SiAddListenerEx(s, port, enabled, false);
}
bool SiAddListenerEx(SERVER *s, UINT port, bool enabled, bool disable_dos)
{
SERVER_LISTENER *e;
UINT i;
// Validate arguments
if (s == NULL || port == 0)
{
return false;
}
// Check whether the listener exists already
for (i = 0;i < LIST_NUM(s->ServerListenerList);i++)
{
e = LIST_DATA(s->ServerListenerList, i);
if (e->Port == port)
{
// Already exist
return false;
}
}
// Register by initializing a new listener
e = ZeroMalloc(sizeof(SERVER_LISTENER));
e->Enabled = enabled;
e->Port = port;
e->DisableDos = disable_dos;
if (e->Enabled)
{
// Create a listener
e->Listener = NewListener(s->Cedar, LISTENER_TCP, e->Port);
if (e->Listener != NULL)
{
e->Listener->DisableDos = e->DisableDos;
}
}
Insert(s->ServerListenerList, e);
return true;
}
// Lock the listener list
void SiLockListenerList(SERVER *s)
{
// Validate arguments
if (s == NULL)
{
return;
}
LockList(s->ServerListenerList);
}
// Unlock the listener list
void SiUnlockListenerList(SERVER *s)
{
// Validate arguments
if (s == NULL)
{
return;
}
UnlockList(s->ServerListenerList);
}
// Set the default value of the Virtual HUB options
void SiSetDefaultHubOption(HUB_OPTION *o)
{
// Validate arguments
if (o == NULL)
{
return;
}
o->DefaultGateway = SetIP32(192, 168, 30, 1);
o->DefaultSubnet = SetIP32(255, 255, 255, 0);
o->MaxSession = 0;
o->VlanTypeId = MAC_PROTO_TAGVLAN;
o->NoIPv6DefaultRouterInRAWhenIPv6 = false;
o->ManageOnlyPrivateIP = true;
o->ManageOnlyLocalUnicastIPv6 = true;
o->NoMacAddressLog = true;
o->NoDhcpPacketLogOutsideHub = true;
o->AccessListIncludeFileCacheLifetime = ACCESS_LIST_INCLUDE_FILE_CACHE_LIFETIME;
o->RemoveDefGwOnDhcpForLocalhost = true;
o->FloodingSendQueueBufferQuota = DEFAULT_FLOODING_QUEUE_LENGTH;
}
// Create a default virtual HUB
void SiInitDefaultHubList(SERVER *s)
{
HUB *h;
HUB_OPTION o;
HUB_LOG g;
// Validate arguments
if (s == NULL)
{
return;
}
Zero(&o, sizeof(o));
// Configure a default Virtual HUB management options
SiSetDefaultHubOption(&o);
h = NewHub(s->Cedar, s->Cedar->Bridge == false ? SERVER_DEFAULT_HUB_NAME : SERVER_DEFAULT_BRIDGE_NAME, &o);
h->CreatedTime = SystemTime64();
AddHub(s->Cedar, h);
if (s->Cedar->Bridge)
{
// Randomize the password
Rand(h->HashedPassword, sizeof(h->HashedPassword));
Rand(h->SecurePassword, sizeof(h->SecurePassword));
}
h->Offline = true;
SetHubOnline(h);
// Log settings
SiSetDefaultLogSetting(&g);
SetHubLogSetting(h, &g);
ReleaseHub(h);
}
// Set the log settings to default
void SiSetDefaultLogSetting(HUB_LOG *g)
{
// Validate arguments
if (g == NULL)
{
return;
}
Zero(g, sizeof(HUB_LOG));
g->SaveSecurityLog = true;
g->SecurityLogSwitchType = LOG_SWITCH_DAY;
g->SavePacketLog = true;
g->PacketLogSwitchType = LOG_SWITCH_DAY;
g->PacketLogConfig[PACKET_LOG_TCP_CONN] =
g->PacketLogConfig[PACKET_LOG_DHCP] = PACKET_LOG_HEADER;
}
// Set the initial configuration
void SiLoadInitialConfiguration(SERVER *s)
{
RPC_KEEP k;
// Validate arguments
if (s == NULL)
{
return;
}
// Auto saving interval related
s->AutoSaveConfigSpan = SERVER_FILE_SAVE_INTERVAL_DEFAULT;
s->BackupConfigOnlyWhenModified = true;
s->Weight = FARM_DEFAULT_WEIGHT;
SiLoadGlobalParamsCfg(NULL);
// KEEP related
Zero(&k, sizeof(k));
{
k.UseKeepConnect = true;
}
k.KeepConnectPort = 80;
StrCpy(k.KeepConnectHost, sizeof(k.KeepConnectHost), CLIENT_DEFAULT_KEEPALIVE_HOST);
k.KeepConnectInterval = KEEP_INTERVAL_DEFAULT * 1000;
k.KeepConnectProtocol = CONNECTION_UDP;
Lock(s->Keep->lock);
{
KEEP *keep = s->Keep;
keep->Enable = k.UseKeepConnect;
keep->Server = true;
StrCpy(keep->ServerName, sizeof(keep->ServerName), k.KeepConnectHost);
keep->ServerPort = k.KeepConnectPort;
keep->UdpMode = k.KeepConnectProtocol;
keep->Interval = k.KeepConnectInterval;
}
Unlock(s->Keep->lock);
// Initialize the password
{
Sha0(s->HashedPassword, "", 0);
}
// Set the encryption algorithm name to default
SiInitCipherName(s);
// Set the server certificate to default
SiInitDefaultServerCert(s);
// Set the character which separates the username from the hub name
s->Cedar->UsernameHubSeparator = DEFAULT_USERNAME_HUB_SEPARATOR;
// Create a default HUB
{
SiInitDefaultHubList(s);
}
if (s->Cedar->Bridge == false)
{
// Create a DDNS client
s->DDnsClient = NewDDNSClient(s->Cedar, NULL, NULL);
}
// Set the listener list to default setting
SiInitListenerList(s);
if (s->Cedar->Bridge)
{
// NAT traversal can not be used in the bridge environment
s->DisableNatTraversal = true;
}
else
{
// Disable VPN-over-ICMP and VPN-over-DNS by default
s->EnableVpnOverIcmp = false;
s->EnableVpnOverDns = false;
{
LIST *ports = s->PortsUDP;
AddInt(ports, SERVER_DEF_PORTS_1);
AddInt(ports, SERVER_DEF_PORTS_2);
AddInt(ports, SERVER_DEF_PORTS_3);
AddInt(ports, SERVER_DEF_PORTS_4);
ProtoSetUdpPorts(s->Proto, ports);
}
}
s->Eraser = NewEraser(s->Logger, 0);
}
// Check whether the ports required for VPN-over-ICMP can be opened
bool SiCanOpenVpnOverIcmpPort()
{
// Whether the ICMP can be opened
SOCK *s = NewUDP(MAKE_SPECIAL_PORT(IP_PROTO_ICMPV4));
if (s == NULL)
{
// Failure
return false;
}
Disconnect(s);
ReleaseSock(s);
return true;
}
// Check whether the ports required for VPN-over-DNS can be opened
bool SiCanOpenVpnOverDnsPort()
{
// Whether UDP Port 53 can be listen on
SOCK *s = NewUDP(53);
if (s == NULL)
{
// Listening failure
return false;
}
Disconnect(s);
ReleaseSock(s);
return true;
}
// Read the configuration file (main)
bool SiLoadConfigurationFileMain(SERVER *s, FOLDER *root)
{
// Validate arguments
if (s == NULL || root == NULL)
{
return false;
}
return SiLoadConfigurationCfg(s, root);
}
// Read the configuration file
bool SiLoadConfigurationFile(SERVER *s)
{
// Validate arguments
bool ret = false;
FOLDER *root;
char *server_config_filename = SERVER_CONFIG_FILE_NAME;
if (s == NULL)
{
return false;
}
s->CfgRw = NewCfgRwEx2A(&root,
s->Cedar->Bridge == false ? server_config_filename : BRIDGE_CONFIG_FILE_NAME, false,
s->Cedar->Bridge == false ? SERVER_CONFIG_TEMPLATE_NAME : BRIDGE_CONFIG_TEMPLATE_NAME);
if (server_reset_setting)
{
CfgDeleteFolder(root);
root = NULL;
server_reset_setting = false;
}
if (root == NULL)
{
return false;
}
ret = SiLoadConfigurationFileMain(s, root);
CfgDeleteFolder(root);
return ret;
}
// Initialize the configuration
void SiInitConfiguration(SERVER *s)
{
// Validate arguments
if (s == NULL)
{
return;
}
s->AutoSaveConfigSpan = SERVER_FILE_SAVE_INTERVAL_DEFAULT;
s->BackupConfigOnlyWhenModified = true;
if (s->Cedar->Bridge == false)
{
// Protocols handler
s->Proto = ProtoNew(s->Cedar);
// IPsec server
s->IPsecServer = NewIPsecServer(s->Cedar);
}
SLog(s->Cedar, "LS_LOAD_CONFIG_1");
if (SiLoadConfigurationFile(s) == false)
{
// Ethernet initialization
InitEth();
SLog(s->Cedar, "LS_LOAD_CONFIG_3");
SiLoadInitialConfiguration(s);
SetFifoCurrentReallocMemSize(MEM_FIFO_REALLOC_MEM_SIZE);
server_reset_setting = false;
}
else
{
SLog(s->Cedar, "LS_LOAD_CONFIG_2");
}
s->CfgRw->DontBackup = s->DontBackupConfig;
// The arp_filter in Linux
if (GetOsInfo()->OsType == OSTYPE_LINUX)
{
if (s->NoLinuxArpFilter == false)
{
SetLinuxArpFilter();
}
}
if (s->DisableDosProtection)
{
DisableDosProtect();
}
else
{
EnableDosProtect();
}
s->AutoSaveConfigSpanSaved = s->AutoSaveConfigSpan;
// Create a VPN Azure client
if (s->DDnsClient != NULL && s->Cedar->Bridge == false && s->ServerType == SERVER_TYPE_STANDALONE)
{
s->AzureClient = NewAzureClient(s->Cedar, s);
AcSetEnable(s->AzureClient, s->EnableVpnAzure);
}
// Reduce the storage interval in the case of user mode
#ifdef OS_WIN32
if (MsIsUserMode())
{
s->AutoSaveConfigSpan = MIN(s->AutoSaveConfigSpan, SERVER_FILE_SAVE_INTERVAL_USERMODE);
}
#endif //OS_WIN32
// Create a saving thread
SLog(s->Cedar, "LS_INIT_SAVE_THREAD", s->AutoSaveConfigSpan / 1000);
s->SaveHaltEvent = NewEvent();
s->SaveThread = NewThread(SiSaverThread, s);
}
// Set the state of Enabled / Disabled of Azure Client
void SiSetAzureEnable(SERVER *s, bool enabled)
{
// Validate arguments
if (s == NULL)
{
return;
}
if (s->AzureClient != NULL)
{
AcSetEnable(s->AzureClient, enabled);
}
s->EnableVpnAzure = enabled;
}
// Apply the Config to the Azure Client
void SiApplyAzureConfig(SERVER *s, DDNS_CLIENT_STATUS *ddns_status)
{
// Validate arguments
if (s == NULL)
{
return;
}
AcApplyCurrentConfig(s->AzureClient, ddns_status);
}
// Get whether the Azure Client is enabled
bool SiIsAzureEnabled(SERVER *s)
{
// Validate arguments
if (s == NULL)
{
return false;
}
if (s->AzureClient == NULL)
{
return false;
}
return s->EnableVpnAzure;
}
// Get whether the Azure Client is supported
bool SiIsAzureSupported(SERVER *s)
{
// Validate arguments
if (s == NULL)
{
return false;
}
if (s->AzureClient == NULL)
{
return false;
}
return true;
}
// Read the server settings from the CFG
bool SiLoadConfigurationCfg(SERVER *s, FOLDER *root)
{
FOLDER *f1, *f2, *f3, *f4, *f5, *f6, *f7, *f8, *f9;
// Validate arguments
if (s == NULL || root == NULL)
{
return false;
}
f1 = CfgGetFolder(root, "ServerConfiguration");
f2 = CfgGetFolder(root, "VirtualHUB");
f3 = CfgGetFolder(root, "ListenerList");
f4 = CfgGetFolder(root, "LocalBridgeList");
f5 = CfgGetFolder(root, "VirtualLayer3SwitchList");
f6 = CfgGetFolder(root, "LicenseManager");
f7 = CfgGetFolder(root, "IPsec");
f8 = CfgGetFolder(root, "DDnsClient");
f9 = CfgGetFolder(root, "WireGuardKeyList");
if (f1 == NULL)
{
SLog(s->Cedar, "LS_BAD_CONFIG");
return false;
}
#ifdef OS_WIN32
if (f4 != NULL)
{
// Read the flag of using the SeLow driver
bool b = true;
if (CfgIsItem(f4, "EnableSoftEtherKernelModeDriver"))
{
b = CfgGetBool(f4, "EnableSoftEtherKernelModeDriver");
}
Win32SetEnableSeLow(b);
}
#endif // OS_WIN32
// Ethernet initialization
InitEth();
s->ConfigRevision = CfgGetInt(root, "ConfigRevision");
if (s->Cedar->Bridge == false && f6 != NULL)
{
if (GetServerCapsBool(s, "b_support_license"))
{
SiLoadLicenseManager(s, f6);
}
}
DestroyServerCapsCache(s);
SiLoadServerCfg(s, f1);
if (s->ServerType != SERVER_TYPE_FARM_MEMBER)
{
TOKEN_LIST *t = CfgEnumFolderToTokenList(f9);
if (t != NULL)
{
LockList(s->Cedar->WgkList);
{
UINT i;
for (i = 0; i < t->NumTokens; ++i)
{
const char *name = t->Token[i];
FOLDER *f = CfgGetFolder(f9, name);
if (f != NULL)
{
WGK *wgk = Malloc(sizeof(WGK));
StrCpy(wgk->Key, sizeof(wgk->Key), name);
CfgGetStr(f, "Hub", wgk->Hub, sizeof(wgk->Hub));
CfgGetStr(f, "User", wgk->User, sizeof(wgk->User));
Add(s->Cedar->WgkList, wgk);
}
}
}
UnlockList(s->Cedar->WgkList);
FreeToken(t);
}
SiLoadHubs(s, f2);
}
SiLoadListeners(s, f3);
if (f4 != NULL)
{
SiLoadLocalBridges(s, f4);
}
if (s->Cedar->Bridge == false && f5 != NULL)
{
SiLoadL3Switchs(s, f5);
}
if (f7 != NULL && GetServerCapsBool(s, "b_support_ipsec"))
{
SiLoadIPsec(s, f7);
}
if (s->Cedar->Bridge == false)
{
if (f8 == NULL)
{
// Create a DDNS client with a new key
s->DDnsClient = NewDDNSClient(s->Cedar, NULL, NULL);
}
else
{
// Create by reading the setting of the DDNS client
UCHAR key[SHA1_SIZE];
if (CfgGetBool(f8, "Disabled"))
{
// Disabled
}
else
{
char machine_name[MAX_SIZE];
char machine_name2[MAX_SIZE];
INTERNET_SETTING t;
BUF *pw;
// Proxy Setting
Zero(&t, sizeof(t));
t.ProxyType = CfgGetInt(f8, "ProxyType");
CfgGetStr(f8, "ProxyHostName", t.ProxyHostName, sizeof(t.ProxyHostName));
t.ProxyPort = CfgGetInt(f8, "ProxyPort");
CfgGetStr(f8, "ProxyUsername", t.ProxyUsername, sizeof(t.ProxyUsername));
pw = CfgGetBuf(f8, "ProxyPassword");
if (pw != NULL)
{
char *pw_str = DecryptPassword(pw);
StrCpy(t.ProxyPassword, sizeof(t.ProxyPassword), pw_str);
Free(pw_str);
FreeBuf(pw);
}
CfgGetStr(f8, "CustomHttpHeader", t.CustomHttpHeader, sizeof(t.CustomHttpHeader));
GetMachineHostName(machine_name, sizeof(machine_name));
CfgGetStr(f8, "LocalHostname", machine_name2, sizeof(machine_name2));
if (CfgGetByte(f8, "Key", key, sizeof(key)) != sizeof(key) || StrCmpi(machine_name, machine_name2) != 0)
{
// Create a DDNS client with a new key
s->DDnsClient = NewDDNSClient(s->Cedar, NULL, &t);
}
else
{
// Create the DDNS client with stored key
s->DDnsClient = NewDDNSClient(s->Cedar, key, &t);
}
}
}
}
s->IPsecMessageDisplayed = CfgGetBool(root, "IPsecMessageDisplayed");
return true;
}
// Write the listener configuration
void SiWriteListenerCfg(FOLDER *f, SERVER_LISTENER *r)
{
// Validate arguments
if (f == NULL || r == NULL)
{
return;
}
CfgAddBool(f, "Enabled", r->Enabled);
CfgAddInt(f, "Port", r->Port);
CfgAddBool(f, "DisableDos", r->DisableDos);
}
// Read the listener configuration
void SiLoadListenerCfg(SERVER *s, FOLDER *f)
{
bool enable;
UINT port;
bool disable_dos;
// Validate arguments
if (s == NULL || f == NULL)
{
return;
}
enable = CfgGetBool(f, "Enabled");
port = CfgGetInt(f, "Port");
disable_dos = CfgGetBool(f, "DisableDos");
if (port == 0)
{
return;
}
SiAddListenerEx(s, port, enable, disable_dos);
}
// Read the listener list
void SiLoadListeners(SERVER *s, FOLDER *f)
{
TOKEN_LIST *t;
UINT i;
// Validate arguments
if (s == NULL || f == NULL)
{
return;
}
t = CfgEnumFolderToTokenList(f);
for (i = 0;i < t->NumTokens;i++)
{
FOLDER *ff = CfgGetFolder(f, t->Token[i]);
if (ff != NULL)
{
SiLoadListenerCfg(s, ff);
}
}
FreeToken(t);
}
// Write the listener list
void SiWriteListeners(FOLDER *f, SERVER *s)
{
// Validate arguments
if (f == NULL || s == NULL)
{
return;
}
LockList(s->ServerListenerList);
{
UINT i;
for (i = 0;i < LIST_NUM(s->ServerListenerList);i++)
{
SERVER_LISTENER *r = LIST_DATA(s->ServerListenerList, i);
char name[MAX_SIZE];
Format(name, sizeof(name), "Listener%u", i);
SiWriteListenerCfg(CfgCreateFolder(f, name), r);
}
}
UnlockList(s->ServerListenerList);
}
// Write the bridge
void SiWriteLocalBridgeCfg(FOLDER *f, LOCALBRIDGE *br)
{
// Validate arguments
if (f == NULL || br == NULL)
{
return;
}
CfgAddStr(f, "DeviceName", br->DeviceName);
CfgAddStr(f, "HubName", br->HubName);
CfgAddBool(f, "NoPromiscuousMode", br->Local);
CfgAddBool(f, "MonitorMode", br->Monitor);
CfgAddBool(f, "LimitBroadcast", br->LimitBroadcast);
if (OS_IS_UNIX(GetOsInfo()->OsType))
{
CfgAddBool(f, "TapMode", br->TapMode);
if (br->TapMode)
{
char tmp[MAX_SIZE];
MacToStr(tmp, sizeof(tmp), br->TapMacAddress);
CfgAddStr(f, "TapMacAddress", tmp);
}
}
}
// Write the bridge list
void SiWriteLocalBridges(FOLDER *f, SERVER *s)
{
// Validate arguments
if (s == NULL || f == NULL)
{
return;
}
#ifdef OS_WIN32
CfgAddBool(f, "ShowAllInterfaces", Win32EthGetShowAllIf());
CfgAddBool(f, "EnableSoftEtherKernelModeDriver", Win32GetEnableSeLow());
#endif // OS_WIN32
#ifdef UNIX_LINUX
CfgAddBool(f, "DoNotDisableOffloading", GetGlobalServerFlag(GSF_LOCALBRIDGE_NO_DISABLE_OFFLOAD));
#endif // UNIX_LINUX
LockList(s->Cedar->LocalBridgeList);
{
UINT i;
for (i = 0;i < LIST_NUM(s->Cedar->LocalBridgeList);i++)
{
LOCALBRIDGE *br = LIST_DATA(s->Cedar->LocalBridgeList, i);
char name[MAX_SIZE];
Format(name, sizeof(name), "LocalBridge%u", i);
SiWriteLocalBridgeCfg(CfgCreateFolder(f, name), br);
}
}
UnlockList(s->Cedar->LocalBridgeList);
}
// Read the bridge
void SiLoadLocalBridgeCfg(SERVER *s, FOLDER *f)
{
char hub[MAX_SIZE];
char nic[MAX_SIZE];
bool tapmode = false;
UCHAR tapaddr[6];
// Validate arguments
if (s == NULL || f == NULL)
{
return;
}
Zero(hub, sizeof(hub));
Zero(nic, sizeof(nic));
CfgGetStr(f, "HubName", hub, sizeof(hub));
CfgGetStr(f, "DeviceName", nic, sizeof(nic));
if (IsEmptyStr(hub) || IsEmptyStr(nic)
)
{
return;
}
if (OS_IS_UNIX(GetOsInfo()->OsType))
{
if (CfgGetBool(f, "TapMode"))
{
char tmp[MAX_SIZE];
tapmode = true;
Zero(tapaddr, sizeof(tapaddr));
if (CfgGetStr(f, "TapMacAddress", tmp, sizeof(tmp)))
{
BUF *b;
b = StrToBin(tmp);
if (b != NULL && b->Size == 6)
{
Copy(tapaddr, b->Buf, sizeof(tapaddr));
}
FreeBuf(b);
}
}
}
AddLocalBridge(s->Cedar, hub, nic, CfgGetBool(f, "NoPromiscuousMode"), CfgGetBool(f, "MonitorMode"),
tapmode, tapaddr, CfgGetBool(f, "LimitBroadcast"));
}
// Read the bridge list
void SiLoadLocalBridges(SERVER *s, FOLDER *f)
{
TOKEN_LIST *t;
UINT i;
// Validate arguments
if (s == NULL || f == NULL)
{
return;
}
#ifdef OS_WIN32
Win32EthSetShowAllIf(CfgGetBool(f, "ShowAllInterfaces"));
#endif // OS_WIN32
#ifdef UNIX_LINUX
SetGlobalServerFlag(GSF_LOCALBRIDGE_NO_DISABLE_OFFLOAD, CfgGetBool(f, "DoNotDisableOffloading"));
#endif // UNIX_LINUX
t = CfgEnumFolderToTokenList(f);
for (i = 0;i < t->NumTokens;i++)
{
char *name = t->Token[i];
SiLoadLocalBridgeCfg(s, CfgGetFolder(f, name));
}
FreeToken(t);
}
// Increment the configuration revision of the server
void IncrementServerConfigRevision(SERVER *s)
{
// Validate arguments
if (s == NULL)
{
return;
}
s->ConfigRevision++;
}
// Write the server settings to CFG
FOLDER *SiWriteConfigurationToCfg(SERVER *s)
{
FOLDER *root;
char region[128];
// Validate arguments
if (s == NULL)
{
return NULL;
}
root = CfgCreateFolder(NULL, TAG_ROOT);
SiGetCurrentRegion(s->Cedar, region, sizeof(region));
CfgAddStr(root, "Region", region);
CfgAddInt(root, "ConfigRevision", s->ConfigRevision);
SiWriteListeners(CfgCreateFolder(root, "ListenerList"), s);
SiWriteLocalBridges(CfgCreateFolder(root, "LocalBridgeList"), s);
SiWriteServerCfg(CfgCreateFolder(root, "ServerConfiguration"), s);
if (s->UpdatedServerType != SERVER_TYPE_FARM_MEMBER)
{
FOLDER *f = CfgCreateFolder(root, "WireGuardKeyList");
if (f != NULL)
{
LockList(s->Cedar->WgkList);
{
UINT i;
for (i = 0; i < LIST_NUM(s->Cedar->WgkList); ++i)
{
WGK *wgk = LIST_DATA(s->Cedar->WgkList, i);
FOLDER *ff = CfgCreateFolder(f, wgk->Key);
if (ff != NULL)
{
CfgAddStr(ff, "Hub", wgk->Hub);
CfgAddStr(ff, "User", wgk->User);
}
}
}
UnlockList(s->Cedar->WgkList);
}
SiWriteHubs(CfgCreateFolder(root, "VirtualHUB"), s);
}
if (s->Cedar->Bridge == false)
{
SiWriteL3Switchs(CfgCreateFolder(root, "VirtualLayer3SwitchList"), s);
if (GetServerCapsBool(s, "b_support_license"))
{
SiWriteLicenseManager(CfgCreateFolder(root, "LicenseManager"), s);
}
}
if (s->Led)
{
CfgAddBool(root, "Led", true);
CfgAddBool(root, "LedSpecial", s->LedSpecial);
}
if (GetServerCapsBool(s, "b_support_ipsec"))
{
SiWriteIPsec(CfgCreateFolder(root, "IPsec"), s);
}
if (s->Cedar->Bridge == false)
{
FOLDER *ddns_folder = CfgCreateFolder(root, "DDnsClient");
if (s->DDnsClient == NULL)
{
// Disabled
CfgAddBool(ddns_folder, "Disabled", true);
}
else
{
char machine_name[MAX_SIZE];
BUF *pw;
INTERNET_SETTING *t;
// Enabled
CfgAddBool(ddns_folder, "Disabled", false);
CfgAddByte(ddns_folder, "Key", s->DDnsClient->Key, SHA1_SIZE);
GetMachineHostName(machine_name, sizeof(machine_name));
CfgAddStr(ddns_folder, "LocalHostname", machine_name);
t = &s->DDnsClient->InternetSetting;
CfgAddInt(ddns_folder, "ProxyType", t->ProxyType);
CfgAddStr(ddns_folder, "ProxyHostName", t->ProxyHostName);
CfgAddInt(ddns_folder, "ProxyPort", t->ProxyPort);
CfgAddStr(ddns_folder, "ProxyUsername", t->ProxyUsername);
if (IsEmptyStr(t->ProxyPassword) == false)
{
pw = EncryptPassword(t->ProxyPassword);
CfgAddBuf(ddns_folder, "ProxyPassword", pw);
FreeBuf(pw);
}
CfgAddStr(ddns_folder, "CustomHttpHeader", t->CustomHttpHeader);
}
}
CfgAddBool(root, "IPsecMessageDisplayed", s->IPsecMessageDisplayed);
return root;
}
// Read the policy
void SiLoadPolicyCfg(POLICY *p, FOLDER *f)
{
// Validate arguments
if (f == NULL || p == NULL)
{
return;
}
Zero(p, sizeof(POLICY));
// Ver 2
p->Access = CfgGetBool(f, "Access");
p->DHCPFilter = CfgGetBool(f, "DHCPFilter");
p->DHCPNoServer = CfgGetBool(f, "DHCPNoServer");
p->DHCPForce = CfgGetBool(f, "DHCPForce");
p->NoBridge = CfgGetBool(f, "NoBridge");
p->NoRouting = CfgGetBool(f, "NoRouting");
p->CheckMac = CfgGetBool(f, "CheckMac");
p->CheckIP = CfgGetBool(f, "CheckIP");
p->ArpDhcpOnly = CfgGetBool(f, "ArpDhcpOnly");
p->PrivacyFilter = CfgGetBool(f, "PrivacyFilter");
p->NoServer = CfgGetBool(f, "NoServer");
p->NoBroadcastLimiter = CfgGetBool(f, "NoBroadcastLimiter");
p->MonitorPort = CfgGetBool(f, "MonitorPort");
p->MaxConnection = CfgGetInt(f, "MaxConnection");
p->TimeOut = CfgGetInt(f, "TimeOut");
p->MaxMac = CfgGetInt(f, "MaxMac");
p->MaxIP = CfgGetInt(f, "MaxIP");
p->MaxUpload = CfgGetInt(f, "MaxUpload");
p->MaxDownload = CfgGetInt(f, "MaxDownload");
p->FixPassword = CfgGetBool(f, "FixPassword");
p->MultiLogins = CfgGetInt(f, "MultiLogins");
p->NoQoS = CfgGetBool(f, "NoQoS");
// Ver 3
p->RSandRAFilter = CfgGetBool(f, "RSandRAFilter");
p->RAFilter = CfgGetBool(f, "RAFilter");
p->DHCPv6Filter = CfgGetBool(f, "DHCPv6Filter");
p->DHCPv6NoServer = CfgGetBool(f, "DHCPv6NoServer");
p->NoRoutingV6 = CfgGetBool(f, "NoRoutingV6");
p->CheckIPv6 = CfgGetBool(f, "CheckIPv6");
p->NoServerV6 = CfgGetBool(f, "NoServerV6");
p->MaxIPv6 = CfgGetInt(f, "MaxIPv6");
p->NoSavePassword = CfgGetBool(f, "NoSavePassword");
p->AutoDisconnect = CfgGetInt(f, "AutoDisconnect");
p->FilterIPv4 = CfgGetBool(f, "FilterIPv4");
p->FilterIPv6 = CfgGetBool(f, "FilterIPv6");
p->FilterNonIP = CfgGetBool(f, "FilterNonIP");
p->NoIPv6DefaultRouterInRA = CfgGetBool(f, "NoIPv6DefaultRouterInRA");
p->NoIPv6DefaultRouterInRAWhenIPv6 = CfgGetBool(f, "NoIPv6DefaultRouterInRAWhenIPv6");
p->VLanId = CfgGetInt(f, "VLanId");
}
// Write the policy
void SiWritePolicyCfg(FOLDER *f, POLICY *p, bool cascade_mode)
{
// Validate arguments
if (f == NULL || p == NULL)
{
return;
}
// Ver 2.0
if (cascade_mode == false)
{
CfgAddBool(f, "Access", p->Access);
}
CfgAddBool(f, "DHCPFilter", p->DHCPFilter);
CfgAddBool(f, "DHCPNoServer", p->DHCPNoServer);
CfgAddBool(f, "DHCPForce", p->DHCPForce);
if (cascade_mode == false)
{
CfgAddBool(f, "NoBridge", p->NoBridge);
CfgAddBool(f, "NoRouting", p->NoRouting);
}
CfgAddBool(f, "CheckMac", p->CheckMac);
CfgAddBool(f, "CheckIP", p->CheckIP);
CfgAddBool(f, "ArpDhcpOnly", p->ArpDhcpOnly);
if (cascade_mode == false)
{
CfgAddBool(f, "PrivacyFilter", p->PrivacyFilter);
}
CfgAddBool(f, "NoServer", p->NoServer);
CfgAddBool(f, "NoBroadcastLimiter", p->NoBroadcastLimiter);
if (cascade_mode == false)
{
CfgAddBool(f, "MonitorPort", p->MonitorPort);
CfgAddInt(f, "MaxConnection", p->MaxConnection);
CfgAddInt(f, "TimeOut", p->TimeOut);
}
CfgAddInt(f, "MaxMac", p->MaxMac);
CfgAddInt(f, "MaxIP", p->MaxIP);
CfgAddInt(f, "MaxUpload", p->MaxUpload);
CfgAddInt(f, "MaxDownload", p->MaxDownload);
if (cascade_mode == false)
{
CfgAddBool(f, "FixPassword", p->FixPassword);
CfgAddInt(f, "MultiLogins", p->MultiLogins);
CfgAddBool(f, "NoQoS", p->NoQoS);
}
// Ver 3.0
CfgAddBool(f, "RSandRAFilter", p->RSandRAFilter);
CfgAddBool(f, "RAFilter", p->RAFilter);
CfgAddBool(f, "DHCPv6Filter", p->DHCPv6Filter);
CfgAddBool(f, "DHCPv6NoServer", p->DHCPv6NoServer);
if (cascade_mode == false)
{
CfgAddBool(f, "NoRoutingV6", p->NoRoutingV6);
}
CfgAddBool(f, "CheckIPv6", p->CheckIPv6);
CfgAddBool(f, "NoServerV6", p->NoServerV6);
CfgAddInt(f, "MaxIPv6", p->MaxIPv6);
if (cascade_mode == false)
{
CfgAddBool(f, "NoSavePassword", p->NoSavePassword);
CfgAddInt(f, "AutoDisconnect", p->AutoDisconnect);
}
CfgAddBool(f, "FilterIPv4", p->FilterIPv4);
CfgAddBool(f, "FilterIPv6", p->FilterIPv6);
CfgAddBool(f, "FilterNonIP", p->FilterNonIP);
CfgAddBool(f, "NoIPv6DefaultRouterInRA", p->NoIPv6DefaultRouterInRA);
CfgAddBool(f, "NoIPv6DefaultRouterInRAWhenIPv6", p->NoIPv6DefaultRouterInRAWhenIPv6);
CfgAddInt(f, "VLanId", p->VLanId);
}
// Write the link information of the Virtual HUB
void SiWriteHubLinkCfg(FOLDER *f, LINK *k)
{
// Validate arguments
if (f == NULL || k == NULL)
{
return;
}
Lock(k->lock);
{
// Online
CfgAddBool(f, "Online", k->Offline ? false : true);
// Client options
CiWriteClientOption(CfgCreateFolder(f, "ClientOption"), k->Option);
// Client authentication data
CiWriteClientAuth(CfgCreateFolder(f, "ClientAuth"), k->Auth);
// Policy
if (k->Policy != NULL)
{
SiWritePolicyCfg(CfgCreateFolder(f, "Policy"), k->Policy, true);
}
CfgAddBool(f, "CheckServerCert", k->CheckServerCert);
CfgAddBool(f, "AddDefaultCA", k->AddDefaultCA);
if (k->ServerCert != NULL)
{
BUF *b = XToBuf(k->ServerCert, false);
CfgAddBuf(f, "ServerCert", b);
FreeBuf(b);
}
}
Unlock(k->lock);
}
// Read the link information
void SiLoadHubLinkCfg(FOLDER *f, HUB *h)
{
bool online;
CLIENT_OPTION *o;
CLIENT_AUTH *a;
FOLDER *pf;
POLICY p;
LINK *k;
// Validate arguments
if (f == NULL || h == NULL)
{
return;
}
pf = CfgGetFolder(f, "Policy");
if (pf == NULL)
{
return;
}
SiLoadPolicyCfg(&p, pf);
online = CfgGetBool(f, "Online");
o = CiLoadClientOption(CfgGetFolder(f, "ClientOption"));
a = CiLoadClientAuth(CfgGetFolder(f, "ClientAuth"));
if (o == NULL || a == NULL)
{
Free(o);
CiFreeClientAuth(a);
return;
}
k = NewLink(h->Cedar, h, o, a, &p);
if (k != NULL)
{
BUF *b;
k->CheckServerCert = CfgGetBool(f, "CheckServerCert");
k->AddDefaultCA = CfgGetBool(f, "AddDefaultCA");
b = CfgGetBuf(f, "ServerCert");
if (b != NULL)
{
k->ServerCert = BufToX(b, false);
FreeBuf(b);
}
k->Offline = !online;
ReleaseLink(k);
}
Free(o);
CiFreeClientAuth(a);
}
// Write the SecureNAT of the Virtual HUB
void SiWriteSecureNAT(HUB *h, FOLDER *f)
{
// Validate arguments
if (h == NULL || f == NULL)
{
return;
}
CfgAddBool(f, "Disabled", h->EnableSecureNAT ? false : true);
NiWriteVhOptionEx(h->SecureNATOption, f);
}
// Read the administration options for the virtual HUB
void SiLoadHubAdminOptions(HUB *h, FOLDER *f)
{
TOKEN_LIST *t;
// Validate arguments
if (h == NULL || f == NULL)
{
return;
}
t = CfgEnumItemToTokenList(f);
if (t != NULL)
{
UINT i;
LockList(h->AdminOptionList);
{
DeleteAllHubAdminOption(h, false);
for (i = 0;i < t->NumTokens;i++)
{
char *name = t->Token[i];
ADMIN_OPTION *a;
UINT value = CfgGetInt(f, name);;
Trim(name);
a = ZeroMalloc(sizeof(ADMIN_OPTION));
StrCpy(a->Name, sizeof(a->Name), name);
a->Value = value;
Insert(h->AdminOptionList, a);
}
AddHubAdminOptionsDefaults(h, false);
}
UnlockList(h->AdminOptionList);
FreeToken(t);
}
}
// Write the administration options for the virtual HUB
void SiWriteHubAdminOptions(FOLDER *f, HUB *h)
{
// Validate arguments
if (f == NULL || h == NULL)
{
return;
}
LockList(h->AdminOptionList);
{
UINT i;
for (i = 0;i < LIST_NUM(h->AdminOptionList);i++)
{
ADMIN_OPTION *a = LIST_DATA(h->AdminOptionList, i);
CfgAddInt(f, a->Name, a->Value);
}
}
UnlockList(h->AdminOptionList);
}
// Write the link list of the Virtual HUB
void SiWriteHubLinks(FOLDER *f, HUB *h)
{
// Validate arguments
if (f == NULL || h == NULL)
{
return;
}
LockList(h->LinkList);
{
UINT i;
for (i = 0;i < LIST_NUM(h->LinkList);i++)
{
LINK *k = LIST_DATA(h->LinkList, i);
char name[MAX_SIZE];
Format(name, sizeof(name), "Cascade%u", i);
SiWriteHubLinkCfg(CfgCreateFolder(f, name), k);
}
}
UnlockList(h->LinkList);
}
// Read the link list
void SiLoadHubLinks(HUB *h, FOLDER *f)
{
TOKEN_LIST *t;
UINT i;
// Validate arguments
if (h == NULL || f == NULL)
{
return;
}
t = CfgEnumFolderToTokenList(f);
for (i = 0;i < t->NumTokens;i++)
{
char *name = t->Token[i];
SiLoadHubLinkCfg(CfgGetFolder(f, name), h);
}
FreeToken(t);
}
// Write an item of the access list
void SiWriteHubAccessCfg(FOLDER *f, ACCESS *a)
{
// Validate arguments
if (f == NULL || a == NULL)
{
return;
}
CfgAddUniStr(f, "Note", a->Note);
CfgAddBool(f, "Active", a->Active);
CfgAddInt(f, "Priority", a->Priority);
CfgAddBool(f, "Discard", a->Discard);
CfgAddBool(f, "IsIPv6", a->IsIPv6);
if (a->IsIPv6 == false)
{
CfgAddIp32(f, "SrcIpAddress", a->SrcIpAddress);
CfgAddIp32(f, "SrcSubnetMask", a->SrcSubnetMask);
CfgAddIp32(f, "DestIpAddress", a->DestIpAddress);
CfgAddIp32(f, "DestSubnetMask", a->DestSubnetMask);
}
else
{
CfgAddIp6Addr(f, "SrcIpAddress6", &a->SrcIpAddress6);
CfgAddIp6Addr(f, "SrcSubnetMask6", &a->SrcSubnetMask6);
CfgAddIp6Addr(f, "DestIpAddress6", &a->DestIpAddress6);
CfgAddIp6Addr(f, "DestSubnetMask6", &a->DestSubnetMask6);
}
CfgAddInt(f, "Protocol", a->Protocol);
CfgAddInt(f, "SrcPortStart", a->SrcPortStart);
CfgAddInt(f, "SrcPortEnd", a->SrcPortEnd);
CfgAddInt(f, "DestPortStart", a->DestPortStart);
CfgAddInt(f, "DestPortEnd", a->DestPortEnd);
CfgAddStr(f, "SrcUsername", a->SrcUsername);
CfgAddStr(f, "DestUsername", a->DestUsername);
CfgAddBool(f, "CheckSrcMac", a->CheckSrcMac);
if (a->CheckSrcMac)
{
char tmp[MAX_PATH];
MacToStr(tmp, sizeof(tmp), a->SrcMacAddress);
CfgAddStr(f, "SrcMacAddress", tmp);
MacToStr(tmp, sizeof(tmp), a->SrcMacMask);
CfgAddStr(f, "SrcMacMask", tmp);
}
CfgAddBool(f, "CheckDstMac", a->CheckDstMac);
if (a->CheckDstMac)
{
char tmp[MAX_PATH];
MacToStr(tmp, sizeof(tmp), a->DstMacAddress);
CfgAddStr(f, "DstMacAddress", tmp);
MacToStr(tmp, sizeof(tmp), a->DstMacMask);
CfgAddStr(f, "DstMacMask", tmp);
}
CfgAddBool(f, "CheckTcpState", a->CheckTcpState);
CfgAddBool(f, "Established", a->Established);
CfgAddStr(f, "RedirectUrl", a->RedirectUrl);
CfgAddInt(f, "Delay", a->Delay);
CfgAddInt(f, "Jitter", a->Jitter);
CfgAddInt(f, "Loss", a->Loss);
}
// Read an item of the access list
void SiLoadHubAccessCfg(HUB *h, FOLDER *f)
{
ACCESS a;
char tmp[MAX_PATH];
// Validate arguments
if (h == NULL || f == NULL)
{
return;
}
Zero(&a, sizeof(a));
CfgGetUniStr(f, "Note", a.Note, sizeof(a.Note));
a.Active = CfgGetBool(f, "Active");
a.Priority = CfgGetInt(f, "Priority");
a.Discard = CfgGetBool(f, "Discard");
a.IsIPv6 = CfgGetBool(f, "IsIPv6");
if (a.IsIPv6 == false)
{
a.SrcIpAddress = CfgGetIp32(f, "SrcIpAddress");
a.SrcSubnetMask = CfgGetIp32(f, "SrcSubnetMask");
a.DestIpAddress = CfgGetIp32(f, "DestIpAddress");
a.DestSubnetMask = CfgGetIp32(f, "DestSubnetMask");
}
else
{
CfgGetIp6Addr(f, "SrcIpAddress6", &a.SrcIpAddress6);
CfgGetIp6Addr(f, "SrcSubnetMask6", &a.SrcSubnetMask6);
CfgGetIp6Addr(f, "DestIpAddress6", &a.DestIpAddress6);
CfgGetIp6Addr(f, "DestSubnetMask6", &a.DestSubnetMask6);
}
a.Protocol = CfgGetInt(f, "Protocol");
a.SrcPortStart = CfgGetInt(f, "SrcPortStart");
a.SrcPortEnd = CfgGetInt(f, "SrcPortEnd");
a.DestPortStart = CfgGetInt(f, "DestPortStart");
a.DestPortEnd = CfgGetInt(f, "DestPortEnd");
CfgGetStr(f, "SrcUsername", a.SrcUsername, sizeof(a.SrcUsername));
CfgGetStr(f, "DestUsername", a.DestUsername, sizeof(a.DestUsername));
a.CheckSrcMac = CfgGetBool(f, "CheckSrcMac");
if (CfgGetByte(f, "SrcMacAddress", a.SrcMacAddress, sizeof(a.SrcMacAddress)) == 0)
{
CfgGetStr(f, "SrcMacAddress", tmp, sizeof(tmp));
if (StrToMac(a.SrcMacAddress, tmp) == false)
{
a.CheckSrcMac = false;
}
}
if (CfgGetByte(f, "SrcMacMask", a.SrcMacMask, sizeof(a.SrcMacMask)) == 0)
{
CfgGetStr(f, "SrcMacMask", tmp, sizeof(tmp));
if (StrToMac(a.SrcMacMask, tmp) == false)
{
a.CheckSrcMac = false;
}
}
a.CheckDstMac = CfgGetBool(f, "CheckDstMac");
if (CfgGetByte(f, "DstMacAddress", a.DstMacAddress, sizeof(a.DstMacAddress)) == 0)
{
CfgGetStr(f, "DstMacAddress", tmp, sizeof(tmp));
if (StrToMac(a.DstMacAddress, tmp) == false)
{
a.CheckDstMac = false;
}
}
if (CfgGetByte(f, "DstMacMask", a.DstMacMask, sizeof(a.DstMacMask)) == 0)
{
CfgGetStr(f, "DstMacMask", tmp, sizeof(tmp));
if (StrToMac(a.DstMacMask, tmp) == false)
{
a.CheckDstMac = false;
}
}
a.CheckTcpState = CfgGetBool(f, "CheckTcpState");
a.Established = CfgGetBool(f, "Established");
a.Delay = MAKESURE(CfgGetInt(f, "Delay"), 0, HUB_ACCESSLIST_DELAY_MAX);
a.Jitter = MAKESURE(CfgGetInt(f, "Jitter"), 0, HUB_ACCESSLIST_JITTER_MAX);
a.Loss = MAKESURE(CfgGetInt(f, "Loss"), 0, HUB_ACCESSLIST_LOSS_MAX);
CfgGetStr(f, "RedirectUrl", a.RedirectUrl, sizeof(a.RedirectUrl));
AddAccessList(h, &a);
}
// Write the access list
void SiWriteHubAccessLists(FOLDER *f, HUB *h)
{
// Validate arguments
if (f == NULL || h == NULL)
{
return;
}
LockList(h->AccessList);
{
UINT i;
for (i = 0;i < LIST_NUM(h->AccessList);i++)
{
ACCESS *a = LIST_DATA(h->AccessList, i);
char name[MAX_SIZE];
ToStr(name, a->Id);
SiWriteHubAccessCfg(CfgCreateFolder(f, name), a);
}
}
UnlockList(h->AccessList);
}
// Read the access list
void SiLoadHubAccessLists(HUB *h, FOLDER *f)
{
TOKEN_LIST *t;
UINT i;
// Validate arguments
if (f == NULL || h == NULL)
{
return;
}
t = CfgEnumFolderToTokenList(f);
for (i = 0;i < t->NumTokens;i++)
{
char *name = t->Token[i];
SiLoadHubAccessCfg(h, CfgGetFolder(f, name));
}
FreeToken(t);
}
// Read the HUB_OPTION
void SiLoadHubOptionCfg(FOLDER *f, HUB_OPTION *o)
{
char tmp[MAX_SIZE];
// Validate arguments
if (f == NULL || o == NULL)
{
return;
}
o->DefaultGateway = CfgGetIp32(f, "DefaultGateway");
o->DefaultSubnet = CfgGetIp32(f, "DefaultSubnet");
o->MaxSession = CfgGetInt(f, "MaxSession");
o->NoArpPolling = CfgGetBool(f, "NoArpPolling");
o->NoIPv6AddrPolling = CfgGetBool(f, "NoIPv6AddrPolling");
o->NoIpTable = CfgGetBool(f, "NoIpTable");
o->NoEnum = CfgGetBool(f, "NoEnum");
o->FilterPPPoE = CfgGetBool(f, "FilterPPPoE");
o->FilterOSPF = CfgGetBool(f, "FilterOSPF");
o->FilterIPv4 = CfgGetBool(f, "FilterIPv4");
o->FilterIPv6 = CfgGetBool(f, "FilterIPv6");
o->FilterNonIP = CfgGetBool(f, "FilterNonIP");
o->FilterBPDU = CfgGetBool(f, "FilterBPDU");
o->NoIPv4PacketLog = CfgGetBool(f, "NoIPv4PacketLog");
o->NoIPv6PacketLog = CfgGetBool(f, "NoIPv6PacketLog");
o->NoIPv6DefaultRouterInRAWhenIPv6 = CfgGetBool(f, "NoIPv6DefaultRouterInRAWhenIPv6");
o->DisableIPParsing = CfgGetBool(f, "DisableIPParsing");
o->YieldAfterStorePacket = CfgGetBool(f, "YieldAfterStorePacket");
o->NoSpinLockForPacketDelay = CfgGetBool(f, "NoSpinLockForPacketDelay");
o->BroadcastStormDetectionThreshold = CfgGetInt(f, "BroadcastStormDetectionThreshold");
o->ClientMinimumRequiredBuild = CfgGetInt(f, "ClientMinimumRequiredBuild");
o->RequiredClientId = CfgGetInt(f, "RequiredClientId");
o->NoManageVlanId = CfgGetBool(f, "NoManageVlanId");
o->VlanTypeId = 0;
if (CfgGetStr(f, "VlanTypeId", tmp, sizeof(tmp)))
{
o->VlanTypeId = HexToInt(tmp);
}
if (o->VlanTypeId == 0)
{
o->VlanTypeId = MAC_PROTO_TAGVLAN;
}
o->FixForDLinkBPDU = CfgGetBool(f, "FixForDLinkBPDU");
o->BroadcastLimiterStrictMode = CfgGetBool(f, "BroadcastLimiterStrictMode");
o->MaxLoggedPacketsPerMinute = CfgGetInt(f, "MaxLoggedPacketsPerMinute");
if (CfgIsItem(f, "FloodingSendQueueBufferQuota"))
{
o->FloodingSendQueueBufferQuota = CfgGetInt(f, "FloodingSendQueueBufferQuota");
}
else
{
o->FloodingSendQueueBufferQuota = DEFAULT_FLOODING_QUEUE_LENGTH;
}
o->DoNotSaveHeavySecurityLogs = CfgGetBool(f, "DoNotSaveHeavySecurityLogs");
if (CfgIsItem(f, "DropBroadcastsInPrivacyFilterMode"))
{
o->DropBroadcastsInPrivacyFilterMode = CfgGetBool(f, "DropBroadcastsInPrivacyFilterMode");
}
else
{
o->DropBroadcastsInPrivacyFilterMode = true;
}
if (CfgIsItem(f, "DropArpInPrivacyFilterMode"))
{
o->DropArpInPrivacyFilterMode = CfgGetBool(f, "DropArpInPrivacyFilterMode");
}
else
{
o->DropArpInPrivacyFilterMode = true;
}
if (CfgIsItem(f, "AllowSameUserInPrivacyFilterMode"))
{
o->AllowSameUserInPrivacyFilterMode = CfgGetBool(f, "AllowSameUserInPrivacyFilterMode");
}
else
{
o->AllowSameUserInPrivacyFilterMode = false;
}
o->NoLookBPDUBridgeId = CfgGetBool(f, "NoLookBPDUBridgeId");
o->AdjustTcpMssValue = CfgGetInt(f, "AdjustTcpMssValue");
o->DisableAdjustTcpMss = CfgGetBool(f, "DisableAdjustTcpMss");
if (CfgIsItem(f, "NoDhcpPacketLogOutsideHub"))
{
o->NoDhcpPacketLogOutsideHub = CfgGetBool(f, "NoDhcpPacketLogOutsideHub");
}
else
{
o->NoDhcpPacketLogOutsideHub = true;
}
o->DisableHttpParsing = CfgGetBool(f, "DisableHttpParsing");
o->DisableUdpAcceleration = CfgGetBool(f, "DisableUdpAcceleration");
o->DisableUdpFilterForLocalBridgeNic = CfgGetBool(f, "DisableUdpFilterForLocalBridgeNic");
o->ApplyIPv4AccessListOnArpPacket = CfgGetBool(f, "ApplyIPv4AccessListOnArpPacket");
if (CfgIsItem(f, "RemoveDefGwOnDhcpForLocalhost"))
{
o->RemoveDefGwOnDhcpForLocalhost = CfgGetBool(f, "RemoveDefGwOnDhcpForLocalhost");
}
else
{
o->RemoveDefGwOnDhcpForLocalhost = true;
}
o->SecureNAT_MaxTcpSessionsPerIp = CfgGetInt(f, "SecureNAT_MaxTcpSessionsPerIp");
o->SecureNAT_MaxTcpSynSentPerIp = CfgGetInt(f, "SecureNAT_MaxTcpSynSentPerIp");
o->SecureNAT_MaxUdpSessionsPerIp = CfgGetInt(f, "SecureNAT_MaxUdpSessionsPerIp");
o->SecureNAT_MaxDnsSessionsPerIp = CfgGetInt(f, "SecureNAT_MaxDnsSessionsPerIp");
o->SecureNAT_MaxIcmpSessionsPerIp = CfgGetInt(f, "SecureNAT_MaxIcmpSessionsPerIp");
o->AccessListIncludeFileCacheLifetime = CfgGetInt(f, "AccessListIncludeFileCacheLifetime");
if (o->AccessListIncludeFileCacheLifetime == 0)
{
o->AccessListIncludeFileCacheLifetime = ACCESS_LIST_INCLUDE_FILE_CACHE_LIFETIME;
}
o->DisableKernelModeSecureNAT = CfgGetBool(f, "DisableKernelModeSecureNAT");
o->DisableIpRawModeSecureNAT = CfgGetBool(f, "DisableIpRawModeSecureNAT");
o->DisableUserModeSecureNAT = CfgGetBool(f, "DisableUserModeSecureNAT");
o->DisableCheckMacOnLocalBridge = CfgGetBool(f, "DisableCheckMacOnLocalBridge");
o->DisableCorrectIpOffloadChecksum = CfgGetBool(f, "DisableCorrectIpOffloadChecksum");
o->SuppressClientUpdateNotification = CfgGetBool(f, "SuppressClientUpdateNotification");
o->AssignVLanIdByRadiusAttribute = CfgGetBool(f, "AssignVLanIdByRadiusAttribute");
o->DenyAllRadiusLoginWithNoVlanAssign = CfgGetBool(f, "DenyAllRadiusLoginWithNoVlanAssign");
o->SecureNAT_RandomizeAssignIp = CfgGetBool(f, "SecureNAT_RandomizeAssignIp");
o->DetectDormantSessionInterval = CfgGetInt(f, "DetectDormantSessionInterval");
o->NoPhysicalIPOnPacketLog = CfgGetBool(f, "NoPhysicalIPOnPacketLog");
o->UseHubNameAsDhcpUserClassOption = CfgGetBool(f, "UseHubNameAsDhcpUserClassOption");
o->UseHubNameAsRadiusNasId = CfgGetBool(f, "UseHubNameAsRadiusNasId");
o->AllowEapMatchUserByCert = CfgGetBool(f, "AllowEapMatchUserByCert");
// Enabled by default
if (CfgIsItem(f, "ManageOnlyPrivateIP"))
{
o->ManageOnlyPrivateIP = CfgGetBool(f, "ManageOnlyPrivateIP");
}
else
{
o->ManageOnlyPrivateIP = true;
}
if (CfgIsItem(f, "ManageOnlyLocalUnicastIPv6"))
{
o->ManageOnlyLocalUnicastIPv6 = CfgGetBool(f, "ManageOnlyLocalUnicastIPv6");
}
else
{
o->ManageOnlyLocalUnicastIPv6 = true;
}
if (CfgIsItem(f, "NoMacAddressLog"))
{
o->NoMacAddressLog = CfgGetBool(f, "NoMacAddressLog");
}
else
{
o->NoMacAddressLog = true;
}
}
// Write the HUB_OPTION
void SiWriteHubOptionCfg(FOLDER *f, HUB_OPTION *o)
{
char tmp[MAX_SIZE];
// Validate arguments
if (f == NULL || o == NULL)
{
return;
}
CfgAddIp32(f, "DefaultGateway", o->DefaultGateway);
CfgAddIp32(f, "DefaultSubnet", o->DefaultSubnet);
CfgAddInt(f, "MaxSession", o->MaxSession);
CfgAddBool(f, "NoArpPolling", o->NoArpPolling);
CfgAddBool(f, "NoIPv6AddrPolling", o->NoIPv6AddrPolling);
CfgAddBool(f, "NoIpTable", o->NoIpTable);
CfgAddBool(f, "NoEnum", o->NoEnum);
CfgAddBool(f, "FilterPPPoE", o->FilterPPPoE);
CfgAddBool(f, "FilterOSPF", o->FilterOSPF);
CfgAddBool(f, "FilterIPv4", o->FilterIPv4);
CfgAddBool(f, "FilterIPv6", o->FilterIPv6);
CfgAddBool(f, "FilterNonIP", o->FilterNonIP);
CfgAddBool(f, "NoIPv4PacketLog", o->NoIPv4PacketLog);
CfgAddBool(f, "NoIPv6PacketLog", o->NoIPv6PacketLog);
CfgAddBool(f, "FilterBPDU", o->FilterBPDU);
CfgAddBool(f, "NoIPv6DefaultRouterInRAWhenIPv6", o->NoIPv6DefaultRouterInRAWhenIPv6);
CfgAddBool(f, "NoMacAddressLog", o->NoMacAddressLog);
CfgAddBool(f, "ManageOnlyPrivateIP", o->ManageOnlyPrivateIP);
CfgAddBool(f, "ManageOnlyLocalUnicastIPv6", o->ManageOnlyLocalUnicastIPv6);
CfgAddBool(f, "DisableIPParsing", o->DisableIPParsing);
CfgAddBool(f, "YieldAfterStorePacket", o->YieldAfterStorePacket);
CfgAddBool(f, "NoSpinLockForPacketDelay", o->NoSpinLockForPacketDelay);
CfgAddInt(f, "BroadcastStormDetectionThreshold", o->BroadcastStormDetectionThreshold);
CfgAddInt(f, "ClientMinimumRequiredBuild", o->ClientMinimumRequiredBuild);
CfgAddInt(f, "RequiredClientId", o->RequiredClientId);
CfgAddBool(f, "NoManageVlanId", o->NoManageVlanId);
Format(tmp, sizeof(tmp), "0x%x", o->VlanTypeId);
CfgAddStr(f, "VlanTypeId", tmp);
if (o->FixForDLinkBPDU)
{
CfgAddBool(f, "FixForDLinkBPDU", o->FixForDLinkBPDU);
}
CfgAddBool(f, "BroadcastLimiterStrictMode", o->BroadcastLimiterStrictMode);
CfgAddInt(f, "MaxLoggedPacketsPerMinute", o->MaxLoggedPacketsPerMinute);
CfgAddInt(f, "FloodingSendQueueBufferQuota", o->FloodingSendQueueBufferQuota);
CfgAddBool(f, "DoNotSaveHeavySecurityLogs", o->DoNotSaveHeavySecurityLogs);
CfgAddBool(f, "DropBroadcastsInPrivacyFilterMode", o->DropBroadcastsInPrivacyFilterMode);
CfgAddBool(f, "DropArpInPrivacyFilterMode", o->DropArpInPrivacyFilterMode);
CfgAddBool(f, "AllowSameUserInPrivacyFilterMode", o->AllowSameUserInPrivacyFilterMode);
CfgAddBool(f, "SuppressClientUpdateNotification", o->SuppressClientUpdateNotification);
CfgAddBool(f, "AssignVLanIdByRadiusAttribute", o->AssignVLanIdByRadiusAttribute);
CfgAddBool(f, "DenyAllRadiusLoginWithNoVlanAssign", o->DenyAllRadiusLoginWithNoVlanAssign);
CfgAddBool(f, "SecureNAT_RandomizeAssignIp", o->SecureNAT_RandomizeAssignIp);
CfgAddBool(f, "NoPhysicalIPOnPacketLog", o->NoPhysicalIPOnPacketLog);
CfgAddInt(f, "DetectDormantSessionInterval", o->DetectDormantSessionInterval);
CfgAddBool(f, "NoLookBPDUBridgeId", o->NoLookBPDUBridgeId);
CfgAddInt(f, "AdjustTcpMssValue", o->AdjustTcpMssValue);
CfgAddBool(f, "DisableAdjustTcpMss", o->DisableAdjustTcpMss);
CfgAddBool(f, "NoDhcpPacketLogOutsideHub", o->NoDhcpPacketLogOutsideHub);
CfgAddBool(f, "DisableHttpParsing", o->DisableHttpParsing);
CfgAddBool(f, "DisableUdpAcceleration", o->DisableUdpAcceleration);
CfgAddBool(f, "DisableUdpFilterForLocalBridgeNic", o->DisableUdpFilterForLocalBridgeNic);
CfgAddBool(f, "ApplyIPv4AccessListOnArpPacket", o->ApplyIPv4AccessListOnArpPacket);
CfgAddBool(f, "RemoveDefGwOnDhcpForLocalhost", o->RemoveDefGwOnDhcpForLocalhost);
CfgAddInt(f, "SecureNAT_MaxTcpSessionsPerIp", o->SecureNAT_MaxTcpSessionsPerIp);
CfgAddInt(f, "SecureNAT_MaxTcpSynSentPerIp", o->SecureNAT_MaxTcpSynSentPerIp);
CfgAddInt(f, "SecureNAT_MaxUdpSessionsPerIp", o->SecureNAT_MaxUdpSessionsPerIp);
CfgAddInt(f, "SecureNAT_MaxDnsSessionsPerIp", o->SecureNAT_MaxDnsSessionsPerIp);
CfgAddInt(f, "SecureNAT_MaxIcmpSessionsPerIp", o->SecureNAT_MaxIcmpSessionsPerIp);
CfgAddInt(f, "AccessListIncludeFileCacheLifetime", o->AccessListIncludeFileCacheLifetime);
CfgAddBool(f, "DisableKernelModeSecureNAT", o->DisableKernelModeSecureNAT);
CfgAddBool(f, "DisableIpRawModeSecureNAT", o->DisableIpRawModeSecureNAT);
CfgAddBool(f, "DisableUserModeSecureNAT", o->DisableUserModeSecureNAT);
CfgAddBool(f, "DisableCheckMacOnLocalBridge", o->DisableCheckMacOnLocalBridge);
CfgAddBool(f, "DisableCorrectIpOffloadChecksum", o->DisableCorrectIpOffloadChecksum);
CfgAddBool(f, "UseHubNameAsDhcpUserClassOption", o->UseHubNameAsDhcpUserClassOption);
CfgAddBool(f, "UseHubNameAsRadiusNasId", o->UseHubNameAsRadiusNasId);
CfgAddBool(f, "AllowEapMatchUserByCert", o->AllowEapMatchUserByCert);
}
// Write the user
void SiWriteUserCfg(FOLDER *f, USER *u)
{
BUF *b;
AUTHPASSWORD *password;
AUTHRADIUS *radius;
AUTHNT *nt;
AUTHUSERCERT *usercert;
AUTHROOTCERT *rootcert;
// Validate arguments
if (f == NULL || u == NULL)
{
return;
}
Lock(u->lock);
{
CfgAddUniStr(f, "RealName", u->RealName);
CfgAddUniStr(f, "Note", u->Note);
if (u->Group != NULL)
{
CfgAddStr(f, "GroupName", u->GroupName);
}
CfgAddInt64(f, "CreatedTime", u->CreatedTime);
CfgAddInt64(f, "UpdatedTime", u->UpdatedTime);
CfgAddInt64(f, "ExpireTime", u->ExpireTime);
CfgAddInt64(f, "LastLoginTime", u->LastLoginTime);
CfgAddInt(f, "NumLogin", u->NumLogin);
if (u->Policy != NULL)
{
SiWritePolicyCfg(CfgCreateFolder(f, "Policy"), u->Policy, false);
}
SiWriteTraffic(f, "Traffic", u->Traffic);
CfgAddInt(f, "AuthType", u->AuthType);
if (u->AuthData != NULL)
{
switch (u->AuthType)
{
case AUTHTYPE_ANONYMOUS:
break;
case AUTHTYPE_PASSWORD:
password = (AUTHPASSWORD *)u->AuthData;
CfgAddByte(f, "AuthPassword", password->HashedKey, sizeof(password->HashedKey));
if (IsZero(password->NtLmSecureHash, sizeof(password->NtLmSecureHash)) == false)
{
CfgAddByte(f, "AuthNtLmSecureHash", password->NtLmSecureHash, sizeof(password->NtLmSecureHash));
}
break;
case AUTHTYPE_NT:
nt = (AUTHNT *)u->AuthData;
CfgAddUniStr(f, "AuthNtUserName", nt->NtUsername);
break;
case AUTHTYPE_RADIUS:
radius = (AUTHRADIUS *)u->AuthData;
CfgAddUniStr(f, "AuthRadiusUsername", radius->RadiusUsername);
break;
case AUTHTYPE_USERCERT:
usercert = (AUTHUSERCERT *)u->AuthData;
b = XToBuf(usercert->UserX, false);
if (b != NULL)
{
CfgAddBuf(f, "AuthUserCert", b);
FreeBuf(b);
}
break;
case AUTHTYPE_ROOTCERT:
rootcert = (AUTHROOTCERT *)u->AuthData;
if (rootcert->Serial != NULL && rootcert->Serial->size >= 1)
{
CfgAddByte(f, "AuthSerial", rootcert->Serial->data, rootcert->Serial->size);
}
if (rootcert->CommonName != NULL && UniIsEmptyStr(rootcert->CommonName) == false)
{
CfgAddUniStr(f, "AuthCommonName", rootcert->CommonName);
}
break;
}
}
}
Unlock(u->lock);
}
// Read an user
void SiLoadUserCfg(HUB *h, FOLDER *f)
{
char *username;
wchar_t realname[MAX_SIZE];
wchar_t note[MAX_SIZE];
char groupname[MAX_SIZE];
FOLDER *pf;
UINT64 created_time;
UINT64 updated_time;
UINT64 expire_time;
UINT64 last_login_time;
UINT num_login;
POLICY p;
TRAFFIC t;
BUF *b;
UINT authtype;
void *authdata;
X_SERIAL *serial = NULL;
wchar_t common_name[MAX_SIZE];
UCHAR hashed_password[SHA1_SIZE];
UCHAR md4_password[MD5_SIZE];
wchar_t tmp[MAX_SIZE];
USER *u;
USERGROUP *g;
// Validate arguments
if (h == NULL || f == NULL)
{
return;
}
username = f->Name;
CfgGetUniStr(f, "RealName", realname, sizeof(realname));
CfgGetUniStr(f, "Note", note, sizeof(note));
CfgGetStr(f, "GroupName", groupname, sizeof(groupname));
created_time = CfgGetInt64(f, "CreatedTime");
updated_time = CfgGetInt64(f, "UpdatedTime");
expire_time = CfgGetInt64(f, "ExpireTime");
last_login_time = CfgGetInt64(f, "LastLoginTime");
num_login = CfgGetInt(f, "NumLogin");
pf = CfgGetFolder(f, "Policy");
if (pf != NULL)
{
SiLoadPolicyCfg(&p, pf);
}
SiLoadTraffic(f, "Traffic", &t);
authtype = CfgGetInt(f, "AuthType");
authdata = NULL;
switch (authtype)
{
case AUTHTYPE_PASSWORD:
Zero(hashed_password, sizeof(hashed_password));
Zero(md4_password, sizeof(md4_password));
CfgGetByte(f, "AuthPassword", hashed_password, sizeof(hashed_password));
CfgGetByte(f, "AuthNtLmSecureHash", md4_password, sizeof(md4_password));
authdata = NewPasswordAuthDataRaw(hashed_password, md4_password);
break;
case AUTHTYPE_NT:
if (CfgGetUniStr(f, "AuthNtUserName", tmp, sizeof(tmp)))
{
authdata = NewNTAuthData(tmp);
}
else
{
authdata = NewNTAuthData(NULL);
}
break;
case AUTHTYPE_RADIUS:
if (CfgGetUniStr(f, "AuthRadiusUsername", tmp, sizeof(tmp)))
{
authdata = NewRadiusAuthData(tmp);
}
else
{
authdata = NewRadiusAuthData(NULL);
}
break;
case AUTHTYPE_USERCERT:
b = CfgGetBuf(f, "AuthUserCert");
if (b != NULL)
{
X *x = BufToX(b, false);
if (x != NULL)
{
authdata = NewUserCertAuthData(x);
FreeX(x);
}
FreeBuf(b);
}
break;
case AUTHTYPE_ROOTCERT:
b = CfgGetBuf(f, "AuthSerial");
if (b != NULL)
{
serial = NewXSerial(b->Buf, b->Size);
FreeBuf(b);
}
CfgGetUniStr(f, "AuthCommonName", common_name, sizeof(common_name));
authdata = NewRootCertAuthData(serial, common_name);
break;
}
// Add an user
AcLock(h);
{
if (StrLen(groupname) > 0)
{
g = AcGetGroup(h, groupname);
}
else
{
g = NULL;
}
u = NewUser(username, realname, note, authtype, authdata);
if (u != NULL)
{
if (g != NULL)
{
JoinUserToGroup(u, g);
}
SetUserTraffic(u, &t);
if (pf != NULL)
{
SetUserPolicy(u, &p);
}
Lock(u->lock);
{
u->CreatedTime = created_time;
u->UpdatedTime = updated_time;
u->ExpireTime = expire_time;
u->LastLoginTime = last_login_time;
u->NumLogin = num_login;
}
Unlock(u->lock);
AcAddUser(h, u);
ReleaseUser(u);
}
if (g != NULL)
{
ReleaseGroup(g);
}
}
AcUnlock(h);
if (serial != NULL)
{
FreeXSerial(serial);
}
}
// Write the user list
void SiWriteUserList(FOLDER *f, LIST *o)
{
// Validate arguments
if (f == NULL || o == NULL)
{
return;
}
LockList(o);
{
UINT i;
for (i = 0;i < LIST_NUM(o);i++)
{
USER *u = LIST_DATA(o, i);
SiWriteUserCfg(CfgCreateFolder(f, u->Name), u);
}
}
UnlockList(o);
}
// Read the user list
void SiLoadUserList(HUB *h, FOLDER *f)
{
TOKEN_LIST *t;
UINT i;
char *name;
// Validate arguments
if (f == NULL || h == NULL)
{
return;
}
t = CfgEnumFolderToTokenList(f);
for (i = 0;i < t->NumTokens;i++)
{
FOLDER *ff;
name = t->Token[i];
ff = CfgGetFolder(f, name);
SiLoadUserCfg(h, ff);
}
FreeToken(t);
}
// Write the group information
void SiWriteGroupCfg(FOLDER *f, USERGROUP *g)
{
// Validate arguments
if (f == NULL || g == NULL)
{
return;
}
Lock(g->lock);
{
CfgAddUniStr(f, "RealName", g->RealName);
CfgAddUniStr(f, "Note", g->Note);
if (g->Policy != NULL)
{
SiWritePolicyCfg(CfgCreateFolder(f, "Policy"), g->Policy, false);
}
SiWriteTraffic(f, "Traffic", g->Traffic);
}
Unlock(g->lock);
}
// Read the group information
void SiLoadGroupCfg(HUB *h, FOLDER *f)
{
wchar_t realname[MAX_SIZE];
wchar_t note[MAX_SIZE];
char *name;
FOLDER *pf;
POLICY p;
TRAFFIC t;
USERGROUP *g;
// Validate arguments
if (h == NULL || f == NULL)
{
return;
}
name = f->Name;
CfgGetUniStr(f, "RealName", realname, sizeof(realname));
CfgGetUniStr(f, "Note", note, sizeof(note));
pf = CfgGetFolder(f, "Policy");
if (pf != NULL)
{
SiLoadPolicyCfg(&p, pf);
}
SiLoadTraffic(f, "Traffic", &t);
g = NewGroup(name, realname, note);
if (g == NULL)
{
return;
}
if (pf != NULL)
{
SetGroupPolicy(g, &p);
}
SetGroupTraffic(g, &t);
AcLock(h);
{
AcAddGroup(h, g);
}
AcUnlock(h);
ReleaseGroup(g);
}
// Write the group list
void SiWriteGroupList(FOLDER *f, LIST *o)
{
// Validate arguments
if (f == NULL || o == NULL)
{
return;
}
LockList(o);
{
UINT i;
for (i = 0;i < LIST_NUM(o);i++)
{
USERGROUP *g = LIST_DATA(o, i);
SiWriteGroupCfg(CfgCreateFolder(f, g->Name), g);
}
}
UnlockList(o);
}
// Read the group List
void SiLoadGroupList(HUB *h, FOLDER *f)
{
TOKEN_LIST *t;
UINT i;
char *name;
// Validate arguments
if (f == NULL || h == NULL)
{
return;
}
t = CfgEnumFolderToTokenList(f);
for (i = 0;i < t->NumTokens;i++)
{
name = t->Token[i];
SiLoadGroupCfg(h, CfgGetFolder(f, name));
}
FreeToken(t);
}
// Write the AC list
void SiWriteAcList(FOLDER *f, LIST *o)
{
// Validate arguments
if (f == NULL || o == NULL)
{
return;
}
LockList(o);
{
UINT i;
for (i = 0;i < LIST_NUM(o);i++)
{
char name[MAX_SIZE];
AC *ac = LIST_DATA(o, i);
FOLDER *ff;
Format(name, sizeof(name), "Acl%u", i + 1);
ff = CfgCreateFolder(f, name);
CfgAddBool(ff, "Deny", ac->Deny);
CfgAddInt(ff, "Priority", ac->Priority);
CfgAddIp(ff, "IpAddress", &ac->IpAddress);
if (ac->Masked)
{
CfgAddIp(ff, "NetMask", &ac->SubnetMask);
}
}
}
UnlockList(o);
}
// Read the AC list
void SiLoadAcList(LIST *o, FOLDER *f)
{
// Validate arguments
if (o == NULL || f == NULL)
{
return;
}
LockList(o);
{
TOKEN_LIST *t = CfgEnumFolderToTokenList(f);
if (t != NULL)
{
UINT i;
for (i = 0;i < t->NumTokens;i++)
{
FOLDER *ff = CfgGetFolder(f, t->Token[i]);
if (ff != NULL)
{
AC ac;
Zero(&ac, sizeof(ac));
ac.Deny = CfgGetBool(ff, "Deny");
ac.Priority = CfgGetInt(ff, "Priority");
CfgGetIp(ff, "IpAddress", &ac.IpAddress);
if (CfgGetIp(ff, "NetMask", &ac.SubnetMask))
{
ac.Masked = true;
}
AddAc(o, &ac);
}
}
FreeToken(t);
}
}
UnlockList(o);
}
// Write the certificate revocation list
void SiWriteCrlList(FOLDER *f, LIST *o)
{
// Validate arguments
if (f == NULL || o == NULL)
{
return;
}
LockList(o);
{
UINT i;
for (i = 0;i < LIST_NUM(o);i++)
{
char name[MAX_SIZE];
CRL *crl = LIST_DATA(o, i);
FOLDER *ff;
NAME *n;
Format(name, sizeof(name), "Crl%u", i);
ff = CfgCreateFolder(f, name);
n = crl->Name;
if (UniIsEmptyStr(n->CommonName) == false)
{
CfgAddUniStr(ff, "CommonName", n->CommonName);
}
if (UniIsEmptyStr(n->Organization) == false)
{
CfgAddUniStr(ff, "Organization", n->Organization);
}
if (UniIsEmptyStr(n->Unit) == false)
{
CfgAddUniStr(ff, "Unit", n->Unit);
}
if (UniIsEmptyStr(n->Country) == false)
{
CfgAddUniStr(ff, "Country", n->Country);
}
if (UniIsEmptyStr(n->State) == false)
{
CfgAddUniStr(ff, "State", n->State);
}
if (UniIsEmptyStr(n->Local) == false)
{
CfgAddUniStr(ff, "Local", n->Local);
}
if (IsZero(crl->DigestMD5, MD5_SIZE) == false)
{
char tmp[MAX_SIZE];
BinToStr(tmp, sizeof(tmp), crl->DigestMD5, MD5_SIZE);
CfgAddStr(ff, "DigestMD5", tmp);
}
if (IsZero(crl->DigestSHA1, SHA1_SIZE) == false)
{
char tmp[MAX_SIZE];
BinToStr(tmp, sizeof(tmp), crl->DigestSHA1, SHA1_SIZE);
CfgAddStr(ff, "DigestSHA1", tmp);
}
if (crl->Serial != NULL)
{
char tmp[MAX_SIZE];
BinToStr(tmp, sizeof(tmp), crl->Serial->data, crl->Serial->size);
CfgAddStr(ff, "Serial", tmp);
}
}
}
UnlockList(o);
}
// Read the certificate revocation list
void SiLoadCrlList(LIST *o, FOLDER *f)
{
// Validate arguments
if (o == NULL || f == NULL)
{
return;
}
LockList(o);
{
UINT i;
TOKEN_LIST *t;
t = CfgEnumFolderToTokenList(f);
for (i = 0;i < t->NumTokens;i++)
{
CRL *crl;
FOLDER *ff = CfgGetFolder(f, t->Token[i]);
wchar_t cn[MAX_SIZE], org[MAX_SIZE], u[MAX_SIZE], c[MAX_SIZE],
st[MAX_SIZE], l[MAX_SIZE];
char tmp[MAX_SIZE];
if (ff != NULL)
{
BUF *b;
crl = ZeroMalloc(sizeof(CRL));
CfgGetUniStr(ff, "CommonName", cn, sizeof(cn));
CfgGetUniStr(ff, "Organization", org, sizeof(org));
CfgGetUniStr(ff, "Unit", u, sizeof(u));
CfgGetUniStr(ff, "Country", c, sizeof(c));
CfgGetUniStr(ff, "State", st, sizeof(st));
CfgGetUniStr(ff, "Local", l, sizeof(l));
crl->Name = NewName(cn, org, u, c, st, l);
if (CfgGetStr(ff, "Serial", tmp, sizeof(tmp)))
{
b = StrToBin(tmp);
if (b != NULL)
{
if (b->Size >= 1)
{
crl->Serial = NewXSerial(b->Buf, b->Size);
}
FreeBuf(b);
}
}
if (CfgGetStr(ff, "DigestMD5", tmp, sizeof(tmp)))
{
b = StrToBin(tmp);
if (b != NULL)
{
if (b->Size == MD5_SIZE)
{
Copy(crl->DigestMD5, b->Buf, MD5_SIZE);
}
FreeBuf(b);
}
}
if (CfgGetStr(ff, "DigestSHA1", tmp, sizeof(tmp)))
{
b = StrToBin(tmp);
if (b != NULL)
{
if (b->Size == SHA1_SIZE)
{
Copy(crl->DigestSHA1, b->Buf, SHA1_SIZE);
}
FreeBuf(b);
}
}
Insert(o, crl);
}
}
FreeToken(t);
}
UnlockList(o);
}
// Write the certificates list
void SiWriteCertList(FOLDER *f, LIST *o)
{
// Validate arguments
if (f == NULL || o == NULL)
{
return;
}
LockList(o);
{
UINT i;
X *x;
for (i = 0;i < LIST_NUM(o);i++)
{
char name[MAX_SIZE];
BUF *b;
x = LIST_DATA(o, i);
Format(name, sizeof(name), "Cert%u", i);
b = XToBuf(x, false);
if (b != NULL)
{
CfgAddBuf(CfgCreateFolder(f, name), "X509", b);
FreeBuf(b);
}
}
}
UnlockList(o);
}
// Read the certificates list
void SiLoadCertList(LIST *o, FOLDER *f)
{
// Validate arguments
if (o == NULL || f == NULL)
{
return;
}
LockList(o);
{
UINT i;
TOKEN_LIST *t;
t = CfgEnumFolderToTokenList(f);
for (i = 0;i < t->NumTokens;i++)
{
FOLDER *ff = CfgGetFolder(f, t->Token[i]);
BUF *b;
b = CfgGetBuf(ff, "X509");
if (b != NULL)
{
X *x = BufToX(b, false);
if (x != NULL)
{
Insert(o, x);
}
FreeBuf(b);
}
}
FreeToken(t);
}
UnlockList(o);
}
// Write the database
void SiWriteHubDb(FOLDER *f, HUBDB *db, bool no_save_ac_list)
{
// Validate arguments
if (f == NULL || db == NULL)
{
return;
}
SiWriteUserList(CfgCreateFolder(f, "UserList"), db->UserList);
SiWriteGroupList(CfgCreateFolder(f, "GroupList"), db->GroupList);
SiWriteCertList(CfgCreateFolder(f, "CertList"), db->RootCertList);
SiWriteCrlList(CfgCreateFolder(f, "CrlList"), db->CrlList);
if (no_save_ac_list == false)
{
SiWriteAcList(CfgCreateFolder(f, "IPAccessControlList"), db->AcList);
}
}
// Read the database
void SiLoadHubDb(HUB *h, FOLDER *f)
{
// Validate arguments
if (f == NULL || h == NULL)
{
return;
}
SiLoadGroupList(h, CfgGetFolder(f, "GroupList"));
SiLoadUserList(h, CfgGetFolder(f, "UserList"));
if (h->HubDb != NULL)
{
SiLoadCertList(h->HubDb->RootCertList, CfgGetFolder(f, "CertList"));
SiLoadCrlList(h->HubDb->CrlList, CfgGetFolder(f, "CrlList"));
SiLoadAcList(h->HubDb->AcList, CfgGetFolder(f, "IPAccessControlList"));
}
}
// Write the Virtual HUB setting
void SiWriteHubCfg(FOLDER *f, HUB *h)
{
// Validate arguments
if (f == NULL || h == NULL)
{
return;
}
// Radius server name
Lock(h->RadiusOptionLock);
{
if (h->RadiusServerName != NULL)
{
CfgAddStr(f, "RadiusServerName", h->RadiusServerName);
CfgAddBuf(f, "RadiusSecret", h->RadiusSecret);
}
CfgAddInt(f, "RadiusServerPort", h->RadiusServerPort);
CfgAddInt(f, "RadiusRetryInterval", h->RadiusRetryInterval);
CfgAddStr(f, "RadiusSuffixFilter", h->RadiusSuffixFilter);
CfgAddStr(f, "RadiusRealm", h->RadiusRealm);
CfgAddBool(f, "RadiusConvertAllMsChapv2AuthRequestToEap", h->RadiusConvertAllMsChapv2AuthRequestToEap);
CfgAddBool(f, "RadiusUsePeapInsteadOfEap", h->RadiusUsePeapInsteadOfEap);
}
Unlock(h->RadiusOptionLock);
// Password
CfgAddByte(f, "HashedPassword", h->HashedPassword, sizeof(h->HashedPassword));
CfgAddByte(f, "SecurePassword", h->SecurePassword, sizeof(h->SecurePassword));
// Online / Offline flag
if (h->Cedar->Bridge == false)
{
CfgAddBool(f, "Online", (h->Offline && (h->HubIsOnlineButHalting == false)) ? false : true);
}
// Traffic information
SiWriteTraffic(f, "Traffic", h->Traffic);
// HUB options
SiWriteHubOptionCfg(CfgCreateFolder(f, "Option"), h->Option);
// Message
{
FOLDER *folder = CfgCreateFolder(f, "Message");
if (IsEmptyUniStr(h->Msg) == false)
{
CfgAddUniStr(folder, "MessageText", h->Msg);
}
}
// HUB_LOG
SiWriteHubLogCfg(CfgCreateFolder(f, "LogSetting"), &h->LogSetting);
if (h->Type == HUB_TYPE_STANDALONE)
{
// Link list
SiWriteHubLinks(CfgCreateFolder(f, "CascadeList"), h);
}
if (h->Type != HUB_TYPE_FARM_STATIC)
{
if (GetServerCapsBool(h->Cedar->Server, "b_support_securenat"))
{
// SecureNAT
SiWriteSecureNAT(h, CfgCreateFolder(f, "SecureNAT"));
}
}
// Access list
SiWriteHubAccessLists(CfgCreateFolder(f, "AccessList"), h);
// Administration options
SiWriteHubAdminOptions(CfgCreateFolder(f, "AdminOption"), h);
// Type of HUB
CfgAddInt(f, "Type", h->Type);
// Database
if (h->Cedar->Bridge == false)
{
SiWriteHubDb(CfgCreateFolder(f, "SecurityAccountDatabase"), h->HubDb,
false
);
}
// Usage status
CfgAddInt64(f, "LastCommTime", h->LastCommTime);
CfgAddInt64(f, "LastLoginTime", h->LastLoginTime);
CfgAddInt64(f, "CreatedTime", h->CreatedTime);
CfgAddInt(f, "NumLogin", h->NumLogin);
}
// Read the logging options
void SiLoadHubLogCfg(HUB_LOG *g, FOLDER *f)
{
// Validate arguments
if (f == NULL || g == NULL)
{
return;
}
Zero(g, sizeof(HUB_LOG));
g->SaveSecurityLog = CfgGetBool(f, "SaveSecurityLog");
g->SecurityLogSwitchType = CfgGetInt(f, "SecurityLogSwitchType");
g->SavePacketLog = CfgGetBool(f, "SavePacketLog");
g->PacketLogSwitchType = CfgGetInt(f, "PacketLogSwitchType");
g->PacketLogConfig[PACKET_LOG_TCP_CONN] = CfgGetInt(f, "PACKET_LOG_TCP_CONN");
g->PacketLogConfig[PACKET_LOG_TCP] = CfgGetInt(f, "PACKET_LOG_TCP");
g->PacketLogConfig[PACKET_LOG_DHCP] = CfgGetInt(f, "PACKET_LOG_DHCP");
g->PacketLogConfig[PACKET_LOG_UDP] = CfgGetInt(f, "PACKET_LOG_UDP");
g->PacketLogConfig[PACKET_LOG_ICMP] = CfgGetInt(f, "PACKET_LOG_ICMP");
g->PacketLogConfig[PACKET_LOG_IP] = CfgGetInt(f, "PACKET_LOG_IP");
g->PacketLogConfig[PACKET_LOG_ARP] = CfgGetInt(f, "PACKET_LOG_ARP");
g->PacketLogConfig[PACKET_LOG_ETHERNET] = CfgGetInt(f, "PACKET_LOG_ETHERNET");
}
// Write the logging options
void SiWriteHubLogCfg(FOLDER *f, HUB_LOG *g)
{
SiWriteHubLogCfgEx(f, g, false);
}
void SiWriteHubLogCfgEx(FOLDER *f, HUB_LOG *g, bool el_mode)
{
// Validate arguments
if (f == NULL || g == NULL)
{
return;
}
if (el_mode == false)
{
CfgAddBool(f, "SaveSecurityLog", g->SaveSecurityLog);
CfgAddInt(f, "SecurityLogSwitchType", g->SecurityLogSwitchType);
CfgAddBool(f, "SavePacketLog", g->SavePacketLog);
}
CfgAddInt(f, "PacketLogSwitchType", g->PacketLogSwitchType);
CfgAddInt(f, "PACKET_LOG_TCP_CONN", g->PacketLogConfig[PACKET_LOG_TCP_CONN]);
CfgAddInt(f, "PACKET_LOG_TCP", g->PacketLogConfig[PACKET_LOG_TCP]);
CfgAddInt(f, "PACKET_LOG_DHCP", g->PacketLogConfig[PACKET_LOG_DHCP]);
CfgAddInt(f, "PACKET_LOG_UDP", g->PacketLogConfig[PACKET_LOG_UDP]);
CfgAddInt(f, "PACKET_LOG_ICMP", g->PacketLogConfig[PACKET_LOG_ICMP]);
CfgAddInt(f, "PACKET_LOG_IP", g->PacketLogConfig[PACKET_LOG_IP]);
CfgAddInt(f, "PACKET_LOG_ARP", g->PacketLogConfig[PACKET_LOG_ARP]);
CfgAddInt(f, "PACKET_LOG_ETHERNET", g->PacketLogConfig[PACKET_LOG_ETHERNET]);
}
// Read the Virtual HUB settings
void SiLoadHubCfg(SERVER *s, FOLDER *f, char *name)
{
HUB *h;
CEDAR *c;
HUB_OPTION o;
bool online;
UINT hub_old_type = 0;
// Validate arguments
if (s == NULL || f == NULL || name == NULL)
{
return;
}
c = s->Cedar;
// Get the option
Zero(&o, sizeof(o));
SiLoadHubOptionCfg(CfgGetFolder(f, "Option"), &o);
// Create a HUB
h = NewHub(c, name, &o);
if (h != NULL)
{
HUB_LOG g;
// Radius server settings
Lock(h->RadiusOptionLock);
{
char name[MAX_SIZE];
BUF *secret;
UINT port;
UINT interval;
port = CfgGetInt(f, "RadiusServerPort");
interval = CfgGetInt(f, "RadiusRetryInterval");
CfgGetStr(f, "RadiusSuffixFilter", h->RadiusSuffixFilter, sizeof(h->RadiusSuffixFilter));
CfgGetStr(f, "RadiusRealm", h->RadiusRealm, sizeof(h->RadiusRealm));
h->RadiusConvertAllMsChapv2AuthRequestToEap = CfgGetBool(f, "RadiusConvertAllMsChapv2AuthRequestToEap");
h->RadiusUsePeapInsteadOfEap = CfgGetBool(f, "RadiusUsePeapInsteadOfEap");
if (interval == 0)
{
interval = RADIUS_RETRY_INTERVAL;
}
if (port != 0 && CfgGetStr(f, "RadiusServerName", name, sizeof(name)))
{
secret = CfgGetBuf(f, "RadiusSecret");
if (secret != NULL)
{
char secret_str[MAX_SIZE];
Zero(secret_str, sizeof(secret_str));
if (secret->Size < sizeof(secret_str))
{
Copy(secret_str, secret->Buf, secret->Size);
}
secret_str[sizeof(secret_str) - 1] = 0;
//SetRadiusServer(h, name, port, secret_str);
SetRadiusServerEx(h, name, port, secret_str, interval);
FreeBuf(secret);
}
}
}
Unlock(h->RadiusOptionLock);
// Password
if (CfgGetByte(f, "HashedPassword", h->HashedPassword, sizeof(h->HashedPassword)) != sizeof(h->HashedPassword))
{
Sha0(h->HashedPassword, "", 0);
}
if (CfgGetByte(f, "SecurePassword", h->SecurePassword, sizeof(h->SecurePassword)) != sizeof(h->SecurePassword))
{
HashPassword(h->SecurePassword, ADMINISTRATOR_USERNAME, "");
}
// Log Settings
Zero(&g, sizeof(g));
SiLoadHubLogCfg(&g, CfgGetFolder(f, "LogSetting"));
SetHubLogSetting(h, &g);
// Online / Offline flag
if (h->Cedar->Bridge == false)
{
online = CfgGetBool(f, "Online");
}
else
{
online = true;
}
// Traffic information
SiLoadTraffic(f, "Traffic", h->Traffic);
// Access list
SiLoadHubAccessLists(h, CfgGetFolder(f, "AccessList"));
// Type of HUB
hub_old_type = h->Type = CfgGetInt(f, "Type");
if (s->ServerType == SERVER_TYPE_STANDALONE)
{
if (h->Type != HUB_TYPE_STANDALONE)
{
// Change the type of all HUB to a stand-alone if the server is a stand-alone
h->Type = HUB_TYPE_STANDALONE;
}
}
else
{
if (h->Type == HUB_TYPE_STANDALONE)
{
// If the server is a farm controller, change the type of HUB to the farm supported types
h->Type = HUB_TYPE_FARM_DYNAMIC;
}
}
if (h->Type == HUB_TYPE_FARM_DYNAMIC)
{
h->CurrentVersion = h->LastVersion = 1;
}
// Message
{
FOLDER *folder = CfgGetFolder(f, "Message");
if (folder != NULL)
{
wchar_t *tmp = Malloc(sizeof(wchar_t) * (HUB_MAXMSG_LEN + 1));
if (CfgGetUniStr(folder, "MessageText", tmp, sizeof(wchar_t) * (HUB_MAXMSG_LEN + 1)))
{
SetHubMsg(h, tmp);
}
Free(tmp);
}
}
// Link list
if (h->Type == HUB_TYPE_STANDALONE)
{
// The link list is used only on stand-alone HUB
// In VPN Gate hubs, don't load this
{
SiLoadHubLinks(h, CfgGetFolder(f, "CascadeList"));
}
}
// SecureNAT
if (GetServerCapsBool(h->Cedar->Server, "b_support_securenat"))
{
if (h->Type == HUB_TYPE_STANDALONE || h->Type == HUB_TYPE_FARM_DYNAMIC)
{
// SecureNAT is used only in the case of dynamic HUB or standalone HUB
SiLoadSecureNAT(h, CfgGetFolder(f, "SecureNAT"));
if (h->Type != HUB_TYPE_STANDALONE && h->Cedar != NULL && h->Cedar->Server != NULL &&
h->Cedar->Server->ServerType == SERVER_TYPE_FARM_CONTROLLER)
{
NiClearUnsupportedVhOptionForDynamicHub(h->SecureNATOption,
hub_old_type == HUB_TYPE_STANDALONE);
}
}
}
// Administration options
SiLoadHubAdminOptions(h, CfgGetFolder(f, "AdminOption"));
// Database
if (h->Cedar->Bridge == false)
{
SiLoadHubDb(h, CfgGetFolder(f, "SecurityAccountDatabase"));
}
// Usage status
h->LastCommTime = CfgGetInt64(f, "LastCommTime");
if (h->LastCommTime == 0)
{
h->LastCommTime = SystemTime64();
}
h->LastLoginTime = CfgGetInt64(f, "LastLoginTime");
if (h->LastLoginTime == 0)
{
h->LastLoginTime = SystemTime64();
}
h->CreatedTime = CfgGetInt64(f, "CreatedTime");
h->NumLogin = CfgGetInt(f, "NumLogin");
// Start the operation of the HUB
AddHub(c, h);
if (online)
{
h->Offline = true;
SetHubOnline(h);
}
else
{
h->Offline = false;
SetHubOffline(h);
}
WaitLogFlush(h->SecurityLogger);
WaitLogFlush(h->PacketLogger);
ReleaseHub(h);
}
}
// Read the SecureNAT configuration
void SiLoadSecureNAT(HUB *h, FOLDER *f)
{
VH_OPTION o;
// Validate arguments
if (h == NULL || f == NULL)
{
return;
}
// Read the VH_OPTION
NiLoadVhOptionEx(&o, f);
// Set the VH_OPTION
Copy(h->SecureNATOption, &o, sizeof(VH_OPTION));
EnableSecureNAT(h, CfgGetBool(f, "Disabled") ? false : true);
}
// Read the virtual layer 3 switch settings
void SiLoadL3SwitchCfg(L3SW *sw, FOLDER *f)
{
UINT i;
FOLDER *if_folder, *table_folder;
TOKEN_LIST *t;
bool active = false;
// Validate arguments
if (sw == NULL || f == NULL)
{
return;
}
active = CfgGetBool(f, "Active");
// Interface list
if_folder = CfgGetFolder(f, "InterfaceList");
if (if_folder != NULL)
{
t = CfgEnumFolderToTokenList(if_folder);
if (t != NULL)
{
for (i = 0;i < t->NumTokens;i++)
{
FOLDER *ff = CfgGetFolder(if_folder, t->Token[i]);
char name[MAX_HUBNAME_LEN + 1];
UINT ip, subnet;
CfgGetStr(ff, "HubName", name, sizeof(name));
ip = CfgGetIp32(ff, "IpAddress");
subnet = CfgGetIp32(ff, "SubnetMask");
{
L3AddIf(sw, name, ip, subnet);
}
}
FreeToken(t);
}
}
// Routing table
table_folder = CfgGetFolder(f, "RoutingTable");
if (table_folder != NULL)
{
t = CfgEnumFolderToTokenList(table_folder);
if (t != NULL)
{
for (i = 0;i < t->NumTokens;i++)
{
FOLDER *ff = CfgGetFolder(table_folder, t->Token[i]);
L3TABLE tbl;
Zero(&tbl, sizeof(tbl));
tbl.NetworkAddress = CfgGetIp32(ff, "NetworkAddress");
tbl.SubnetMask = CfgGetIp32(ff, "SubnetMask");
tbl.GatewayAddress = CfgGetIp32(ff, "GatewayAddress");
tbl.Metric = CfgGetInt(ff, "Metric");
L3AddTable(sw, &tbl);
}
FreeToken(t);
}
}
if (active)
{
L3SwStart(sw);
}
}
// Write the virtual layer 3 switch settings
void SiWriteL3SwitchCfg(FOLDER *f, L3SW *sw)
{
UINT i;
FOLDER *if_folder, *table_folder;
char tmp[MAX_SIZE];
// Validate arguments
if (f == NULL || sw == NULL)
{
return;
}
// Active flag
CfgAddBool(f, "Active", sw->Active);
// Interface list
if_folder = CfgCreateFolder(f, "InterfaceList");
for (i = 0;i < LIST_NUM(sw->IfList);i++)
{
L3IF *e = LIST_DATA(sw->IfList, i);
FOLDER *ff;
Format(tmp, sizeof(tmp), "Interface%u", i);
ff = CfgCreateFolder(if_folder, tmp);
CfgAddStr(ff, "HubName", e->HubName);
CfgAddIp32(ff, "IpAddress", e->IpAddress);
CfgAddIp32(ff, "SubnetMask", e->SubnetMask);
}
// Routing table
table_folder = CfgCreateFolder(f, "RoutingTable");
for (i = 0;i < LIST_NUM(sw->TableList);i++)
{
L3TABLE *e = LIST_DATA(sw->TableList, i);
FOLDER *ff;
Format(tmp, sizeof(tmp), "Entry%u", i);
ff = CfgCreateFolder(table_folder, tmp);
CfgAddIp32(ff, "NetworkAddress", e->NetworkAddress);
CfgAddIp32(ff, "SubnetMask", e->SubnetMask);
CfgAddIp32(ff, "GatewayAddress", e->GatewayAddress);
CfgAddInt(ff, "Metric", e->Metric);
}
}
// Read the Virtual Layer 3 switch list
void SiLoadL3Switchs(SERVER *s, FOLDER *f)
{
UINT i;
TOKEN_LIST *t;
CEDAR *c;
// Validate arguments
if (s == NULL || f == NULL)
{
return;
}
c = s->Cedar;
t = CfgEnumFolderToTokenList(f);
if (t != NULL)
{
for (i = 0;i < t->NumTokens;i++)
{
char *name = t->Token[i];
L3SW *sw = L3AddSw(c, name);
SiLoadL3SwitchCfg(sw, CfgGetFolder(f, name));
ReleaseL3Sw(sw);
}
}
FreeToken(t);
}
// Write the Virtual Layer 3 switch list
void SiWriteL3Switchs(FOLDER *f, SERVER *s)
{
UINT i;
FOLDER *folder;
CEDAR *c;
// Validate arguments
if (f == NULL || s == NULL)
{
return;
}
c = s->Cedar;
LockList(c->L3SwList);
{
for (i = 0;i < LIST_NUM(c->L3SwList);i++)
{
L3SW *sw = LIST_DATA(c->L3SwList, i);
Lock(sw->lock);
{
folder = CfgCreateFolder(f, sw->Name);
SiWriteL3SwitchCfg(folder, sw);
}
Unlock(sw->lock);
}
}
UnlockList(c->L3SwList);
}
// Read the IPsec server configuration
void SiLoadIPsec(SERVER *s, FOLDER *f)
{
IPSEC_SERVICES sl;
FOLDER *list_folder;
// Validate arguments
if (s == NULL || f == NULL)
{
return;
}
Zero(&sl, sizeof(sl));
CfgGetStr(f, "IPsec_Secret", sl.IPsec_Secret, sizeof(sl.IPsec_Secret));
CfgGetStr(f, "L2TP_DefaultHub", sl.L2TP_DefaultHub, sizeof(sl.L2TP_DefaultHub));
if (s->ServerType == SERVER_TYPE_STANDALONE)
{
// IPsec feature only be enabled on a standalone server
sl.L2TP_Raw = CfgGetBool(f, "L2TP_Raw");
sl.L2TP_IPsec = CfgGetBool(f, "L2TP_IPsec");
sl.EtherIP_IPsec = CfgGetBool(f, "EtherIP_IPsec");
}
IPsecServerSetServices(s->IPsecServer, &sl);
list_folder = CfgGetFolder(f, "EtherIP_IDSettingsList");
if (list_folder != NULL)
{
TOKEN_LIST *t = CfgEnumFolderToTokenList(list_folder);
if (t != NULL)
{
UINT i;
for (i = 0;i < t->NumTokens;i++)
{
char *name = t->Token[i];
FOLDER *f = CfgGetFolder(list_folder, name);
if (f != NULL)
{
ETHERIP_ID d;
BUF *b;
Zero(&d, sizeof(d));
StrCpy(d.Id, sizeof(d.Id), name);
CfgGetStr(f, "HubName", d.HubName, sizeof(d.HubName));
CfgGetStr(f, "UserName", d.UserName, sizeof(d.UserName));
b = CfgGetBuf(f, "EncryptedPassword");
if (b != NULL)
{
char *pass = DecryptPassword2(b);
StrCpy(d.Password, sizeof(d.Password), pass);
Free(pass);
AddEtherIPId(s->IPsecServer, &d);
FreeBuf(b);
}
}
}
FreeToken(t);
}
}
}
// Write the IPsec server configuration
void SiWriteIPsec(FOLDER *f, SERVER *s)
{
IPSEC_SERVICES sl;
FOLDER *list_folder;
UINT i;
// Validate arguments
if (s == NULL || f == NULL)
{
return;
}
if (s->IPsecServer == NULL)
{
return;
}
Zero(&sl, sizeof(sl));
IPsecServerGetServices(s->IPsecServer, &sl);
CfgAddStr(f, "IPsec_Secret", sl.IPsec_Secret);
CfgAddStr(f, "L2TP_DefaultHub", sl.L2TP_DefaultHub);
CfgAddBool(f, "L2TP_Raw", sl.L2TP_Raw);
CfgAddBool(f, "L2TP_IPsec", sl.L2TP_IPsec);
CfgAddBool(f, "EtherIP_IPsec", sl.EtherIP_IPsec);
list_folder = CfgCreateFolder(f, "EtherIP_IDSettingsList");
Lock(s->IPsecServer->LockSettings);
{
for (i = 0;i < LIST_NUM(s->IPsecServer->EtherIPIdList);i++)
{
ETHERIP_ID *d = LIST_DATA(s->IPsecServer->EtherIPIdList, i);
FOLDER *f;
BUF *b;
f = CfgCreateFolder(list_folder, d->Id);
CfgAddStr(f, "HubName", d->HubName);
CfgAddStr(f, "UserName", d->UserName);
b = EncryptPassword2(d->Password);
CfgAddBuf(f, "EncryptedPassword", b);
FreeBuf(b);
}
}
Unlock(s->IPsecServer->LockSettings);
}
// Write the license list
void SiWriteLicenseManager(FOLDER *f, SERVER *s)
{
}
// Read the license list
void SiLoadLicenseManager(SERVER *s, FOLDER *f)
{
}
// Write the Virtual HUB list
void SiWriteHubs(FOLDER *f, SERVER *s)
{
UINT i;
FOLDER *hub_folder;
CEDAR *c;
UINT num;
HUB **hubs;
// Validate arguments
if (f == NULL || s == NULL)
{
return;
}
c = s->Cedar;
LockList(c->HubList);
{
hubs = ToArray(c->HubList);
num = LIST_NUM(c->HubList);
for (i = 0;i < num;i++)
{
AddRef(hubs[i]->ref);
}
}
UnlockList(c->HubList);
for (i = 0;i < num;i++)
{
HUB *h = hubs[i];
Lock(h->lock);
{
hub_folder = CfgCreateFolder(f, h->Name);
SiWriteHubCfg(hub_folder, h);
}
Unlock(h->lock);
ReleaseHub(h);
if ((i % 30) == 1)
{
YieldCpu();
}
}
Free(hubs);
}
// Read the Virtual HUB list
void SiLoadHubs(SERVER *s, FOLDER *f)
{
UINT i;
FOLDER *hub_folder;
TOKEN_LIST *t;
bool b = false;
// Validate arguments
if (f == NULL || s == NULL)
{
return;
}
t = CfgEnumFolderToTokenList(f);
for (i = 0;i < t->NumTokens;i++)
{
char *name = t->Token[i];
if (s->Cedar->Bridge)
{
if (StrCmpi(name, SERVER_DEFAULT_BRIDGE_NAME) == 0)
{
// Read only the setting of Virtual HUB named "BRIDGE"
// in the case of the Bridge
b = true;
}
else
{
continue;
}
}
hub_folder = CfgGetFolder(f, name);
if (hub_folder != NULL)
{
SiLoadHubCfg(s, hub_folder, name);
}
}
FreeToken(t);
if (s->Cedar->Bridge && b == false)
{
// If there isn't "BRIDGE" virtual HUB setting, create it newly
SiInitDefaultHubList(s);
}
}
// Read the server-specific settings
void SiLoadServerCfg(SERVER *s, FOLDER *f)
{
BUF *b;
CEDAR *c;
char tmp[MAX_SIZE];
X *x = NULL;
K *k = NULL;
LIST *chain = NewList(NULL);
FOLDER *params_folder;
UINT i;
// Validate arguments
if (s == NULL || f == NULL)
{
return;
}
// Save interval related
s->AutoSaveConfigSpan = CfgGetInt(f, "AutoSaveConfigSpan") * 1000;
if (s->AutoSaveConfigSpan == 0)
{
s->AutoSaveConfigSpan = SERVER_FILE_SAVE_INTERVAL_DEFAULT;
}
else
{
s->AutoSaveConfigSpan = MAKESURE(s->AutoSaveConfigSpan, SERVER_FILE_SAVE_INTERVAL_MIN, SERVER_FILE_SAVE_INTERVAL_MAX);
}
i = CfgGetInt(f, "MaxConcurrentDnsClientThreads");
if (i != 0)
{
DnsThreadNumMaxSet(i);
}
else
{
DnsThreadNumMaxSet(DNS_THREAD_DEFAULT_NUM_MAX);
}
s->DontBackupConfig = CfgGetBool(f, "DontBackupConfig");
CfgGetIp(f, "ListenIP", &s->ListenIP);
ProtoSetListenIP(s->Proto, &s->ListenIP);
if (CfgIsItem(f, "BackupConfigOnlyWhenModified"))
{
s->BackupConfigOnlyWhenModified = CfgGetBool(f, "BackupConfigOnlyWhenModified");
}
else
{
s->BackupConfigOnlyWhenModified = true;
}
// Server log switch type
if (CfgIsItem(f, "ServerLogSwitchType"))
{
UINT st = CfgGetInt(f, "ServerLogSwitchType");
SetLogSwitchType(s->Logger, st);
}
SetMaxLogSize(CfgGetInt64(f, "LoggerMaxLogSize"));
params_folder = CfgGetFolder(f, "GlobalParams");
SiLoadGlobalParamsCfg(params_folder);
c = s->Cedar;
Lock(c->lock);
{
FOLDER *ff;
{
UINT i;
LIST *ports;
// Load and set UDP ports
CfgGetStr(f, "PortsUDP", tmp, sizeof(tmp));
NormalizeIntListStr(tmp, sizeof(tmp), tmp, true, ", ");
ports = StrToIntList(tmp, true);
for (i = 0; i < LIST_NUM(ports); ++i)
{
AddInt(s->PortsUDP, *(UINT *)LIST_DATA(ports, i));
}
ReleaseIntList(ports);
ProtoSetUdpPorts(s->Proto, s->PortsUDP);
}
{
RPC_KEEP k;
// Keep-alive related
Zero(&k, sizeof(k));
k.UseKeepConnect = CfgGetBool(f, "UseKeepConnect");
CfgGetStr(f, "KeepConnectHost", k.KeepConnectHost, sizeof(k.KeepConnectHost));
k.KeepConnectPort = CfgGetInt(f, "KeepConnectPort");
k.KeepConnectProtocol = CfgGetInt(f, "KeepConnectProtocol");
k.KeepConnectInterval = CfgGetInt(f, "KeepConnectInterval") * 1000;
if (k.KeepConnectPort == 0)
{
k.KeepConnectPort = 80;
}
if (StrLen(k.KeepConnectHost) == 0)
{
StrCpy(k.KeepConnectHost, sizeof(k.KeepConnectHost), CLIENT_DEFAULT_KEEPALIVE_HOST);
}
if (k.KeepConnectInterval == 0)
{
k.KeepConnectInterval = KEEP_INTERVAL_DEFAULT * 1000;
}
if (k.KeepConnectInterval < 5000)
{
k.KeepConnectInterval = 5000;
}
if (k.KeepConnectInterval > 600000)
{
k.KeepConnectInterval = 600000;
}
Lock(s->Keep->lock);
{
KEEP *keep = s->Keep;
keep->Enable = k.UseKeepConnect;
keep->Server = true;
StrCpy(keep->ServerName, sizeof(keep->ServerName), k.KeepConnectHost);
keep->ServerPort = k.KeepConnectPort;
keep->UdpMode = k.KeepConnectProtocol;
keep->Interval = k.KeepConnectInterval;
}
Unlock(s->Keep->lock);
}
// syslog
ff = CfgGetFolder(f, "SyslogSettings");
if (ff != NULL && GetServerCapsBool(s, "b_support_syslog"))
{
SYSLOG_SETTING set;
Zero(&set, sizeof(set));
set.SaveType = CfgGetInt(ff, "SaveType");
CfgGetStr(ff, "HostName", set.Hostname, sizeof(set.Hostname));
set.Port = CfgGetInt(ff, "Port");
SiSetSysLogSetting(s, &set);
}
// Proto
ff = CfgGetFolder(f, "Proto");
if (ff != NULL)
{
SiLoadProtoCfg(s->Proto, ff);
}
// Whether to disable the IPv6 listener
s->Cedar->DisableIPv6Listener = CfgGetBool(f, "DisableIPv6Listener");
// DoS
s->DisableDosProtection = CfgGetBool(f, "DisableDosProtection");
// Num Connections Per IP
SetMaxConnectionsPerIp(CfgGetInt(f, "MaxConnectionsPerIP"));
// MaxUnestablishedConnections
SetMaxUnestablishedConnections(CfgGetInt(f, "MaxUnestablishedConnections"));
// DeadLock
s->DisableDeadLockCheck = CfgGetBool(f, "DisableDeadLockCheck");
// Eraser
SetEraserCheckInterval(CfgGetInt(f, "AutoDeleteCheckIntervalSecs"));
s->Eraser = NewEraser(s->Logger, CfgGetInt64(f, "AutoDeleteCheckDiskFreeSpaceMin"));
// WebUI
s->UseWebUI = CfgGetBool(f, "UseWebUI");
// WebTimePage
s->UseWebTimePage = CfgGetBool(f, "UseWebTimePage");
// NoLinuxArpFilter
s->NoLinuxArpFilter = CfgGetBool(f, "NoLinuxArpFilter");
// NoHighPriorityProcess
s->NoHighPriorityProcess = CfgGetBool(f, "NoHighPriorityProcess");
// NoDebugDump
s->NoDebugDump = CfgGetBool(f, "NoDebugDump");
if (s->NoDebugDump)
{
#ifdef OS_WIN32
MsSetEnableMinidump(false);
#endif // OS_WIN32
}
// Disable the NAT-traversal feature
s->DisableNatTraversal = CfgGetBool(f, "DisableNatTraversal");
// Disable IPsec's aggressive mode
s->DisableIPsecAggressiveMode = CfgGetBool(f, "DisableIPsecAggressiveMode");
if (s->Cedar->Bridge == false)
{
// Enable the VPN-over-ICMP
if (CfgIsItem(f, "EnableVpnOverIcmp"))
{
s->EnableVpnOverIcmp = CfgGetBool(f, "EnableVpnOverIcmp");
}
else
{
s->EnableVpnOverIcmp = false;
}
// Enable the VPN-over-DNS
if (CfgIsItem(f, "EnableVpnOverDns"))
{
s->EnableVpnOverDns = CfgGetBool(f, "EnableVpnOverDns");
}
else
{
s->EnableVpnOverDns = false;
}
}
// Debug log
s->SaveDebugLog = CfgGetBool(f, "SaveDebugLog");
if (s->SaveDebugLog)
{
s->DebugLog = NewTinyLog();
}
// Let the client not to send a signature
s->NoSendSignature = CfgGetBool(f, "NoSendSignature");
// Server certificate
b = CfgGetBuf(f, "ServerCert");
if (b != NULL)
{
x = BufToX(b, false);
FreeBuf(b);
}
// Server private key
b = CfgGetBuf(f, "ServerKey");
if (b != NULL)
{
k = BufToK(b, true, false, NULL);
FreeBuf(b);
}
// Server trust chain
SiLoadCertList(chain, CfgGetFolder(f, "ServerChain"));
if (x == NULL || k == NULL || CheckXandK(x, k) == false)
{
FreeX(x);
FreeK(k);
FreeXList(chain);
SiGenerateDefaultCert(&x, &k);
SetCedarCert(c, x, k);
FreeX(x);
FreeK(k);
}
else
{
if (LIST_NUM(chain) == 0)
{
SetCedarCert(c, x, k);
}
else
{
SetCedarCertAndChain(c, x, k, chain);
}
FreeX(x);
FreeK(k);
FreeXList(chain);
}
// Character which separates the username from the hub name
if (CfgGetStr(f, "UsernameHubSeparator", tmp, sizeof(tmp)))
{
c->UsernameHubSeparator = IsPrintableAsciiChar(tmp[0]) ? tmp[0] : DEFAULT_USERNAME_HUB_SEPARATOR;
}
// Cipher Name
if (CfgGetStr(f, "CipherName", tmp, sizeof(tmp)))
{
StrUpper(tmp);
SetCedarCipherList(c, tmp);
}
// Traffic information
Lock(c->TrafficLock);
{
SiLoadTraffic(f, "ServerTraffic", c->Traffic);
}
Unlock(c->TrafficLock);
// Type of server
s->UpdatedServerType = s->ServerType = CfgGetInt(f, "ServerType");
// Password
if (CfgGetByte(f, "HashedPassword", s->HashedPassword, sizeof(s->HashedPassword)) != sizeof(s->HashedPassword))
{
Sha0(s->HashedPassword, "", 0);
}
if (s->ServerType != SERVER_TYPE_STANDALONE)
{
// Performance ratio of the server
s->Weight = CfgGetInt(f, "ClusterMemberWeight");
if (s->Weight == 0)
{
s->Weight = FARM_DEFAULT_WEIGHT;
}
}
else
{
s->Weight = FARM_DEFAULT_WEIGHT;
}
if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
{
s->ControllerOnly = CfgGetBool(f, "ControllerOnly");
}
if (s->ServerType != SERVER_TYPE_STANDALONE)
{
// NAT traversal can not be used in a cluster environment
s->DisableNatTraversal = true;
}
if (s->Cedar->Bridge)
{
// NAT traversal function can not be used in the bridge environment
s->DisableNatTraversal = true;
}
if (CfgGetStr(f, "PortsUDP", tmp, sizeof(tmp)))
{
UINT i;
TOKEN_LIST *tokens;
LIST *ports = s->PortsUDP;
for (i = 0; i < LIST_NUM(ports); ++i)
{
Free(LIST_DATA(ports, i));
}
DeleteAll(ports);
NormalizeIntListStr(tmp, sizeof(tmp), tmp, true, ", ");
tokens = ParseTokenWithoutNullStr(tmp, ", ");
for (i = 0; i < tokens->NumTokens; ++i)
{
char *str = tokens->Token[i];
if (IsNum(str))
{
InsertIntDistinct(ports, ToInt(str));
}
}
FreeToken(tokens);
}
if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
{
char tmp[6 * MAX_PUBLIC_PORT_NUM + 1];
// Load the settings item in the case of farm members
CfgGetStr(f, "ControllerName", s->ControllerName, sizeof(s->ControllerName));
s->ControllerPort = CfgGetInt(f, "ControllerPort");
CfgGetByte(f, "MemberPassword", s->MemberPassword, SHA1_SIZE);
s->PublicIp = CfgGetIp32(f, "PublicIp");
if (CfgGetStr(f, "PublicPorts", tmp, sizeof(tmp)))
{
TOKEN_LIST *t = ParseToken(tmp, ", ");
UINT i;
s->NumPublicPort = t->NumTokens;
s->PublicPorts = ZeroMalloc(s->NumPublicPort * sizeof(UINT));
for (i = 0;i < s->NumPublicPort;i++)
{
s->PublicPorts[i] = ToInt(t->Token[i]);
}
FreeToken(t);
}
}
// Configuration of VPN Azure Client
s->EnableVpnAzure = CfgGetBool(f, "EnableVpnAzure");
// Disable GetHostName when accepting TCP
s->DisableGetHostNameWhenAcceptTcp = CfgGetBool(f, "DisableGetHostNameWhenAcceptTcp");
if (s->DisableGetHostNameWhenAcceptTcp)
{
DisableGetHostNameWhenAcceptInit();
}
// Disable core dump on UNIX
s->DisableCoreDumpOnUnix = CfgGetBool(f, "DisableCoreDumpOnUnix");
// Disable session reconnect
SetGlobalServerFlag(GSF_DISABLE_SESSION_RECONNECT, CfgGetBool(f, "DisableSessionReconnect"));
c->SslAcceptSettings.Tls_Disable1_0 = CfgGetBool(f, "Tls_Disable1_0");
c->SslAcceptSettings.Tls_Disable1_1 = CfgGetBool(f, "Tls_Disable1_1");
c->SslAcceptSettings.Tls_Disable1_2 = CfgGetBool(f, "Tls_Disable1_2");
c->SslAcceptSettings.Tls_Disable1_3 = CfgGetBool(f, "Tls_Disable1_3");
c->SslAcceptSettings.Override_Security_Level = CfgGetBool(f, "Override_Security_Level");
c->SslAcceptSettings.Override_Security_Level_Value = CfgGetInt(f, "Override_Security_Level_Value");
s->StrictSyslogDatetimeFormat = CfgGetBool(f, "StrictSyslogDatetimeFormat");
// Disable JSON-RPC Web API
s->DisableJsonRpcWebApi = CfgGetBool(f, "DisableJsonRpcWebApi");
// Bits of Diffie-Hellman parameters
c->DhParamBits = CfgGetInt(f, "DhParamBits");
if (c->DhParamBits == 0)
{
c->DhParamBits = DH_PARAM_BITS_DEFAULT;
}
SetDhParam(DhNewFromBits(c->DhParamBits));
}
Unlock(c->lock);
#ifdef OS_UNIX
if (s->DisableCoreDumpOnUnix)
{
UnixDisableCoreDump();
}
#endif // OS_UNIX
}
// Load global params
void SiLoadGlobalParamsCfg(FOLDER *f)
{
SiLoadGlobalParamItem(GP_MAX_SEND_SOCKET_QUEUE_SIZE, CfgGetInt(f, "MAX_SEND_SOCKET_QUEUE_SIZE"));
SiLoadGlobalParamItem(GP_MIN_SEND_SOCKET_QUEUE_SIZE, CfgGetInt(f, "MIN_SEND_SOCKET_QUEUE_SIZE"));
SiLoadGlobalParamItem(GP_MAX_SEND_SOCKET_QUEUE_NUM, CfgGetInt(f, "MAX_SEND_SOCKET_QUEUE_NUM"));
SiLoadGlobalParamItem(GP_SELECT_TIME, CfgGetInt(f, "SELECT_TIME"));
SiLoadGlobalParamItem(GP_SELECT_TIME_FOR_NAT, CfgGetInt(f, "SELECT_TIME_FOR_NAT"));
SiLoadGlobalParamItem(GP_MAX_STORED_QUEUE_NUM, CfgGetInt(f, "MAX_STORED_QUEUE_NUM"));
SiLoadGlobalParamItem(GP_MAX_BUFFERING_PACKET_SIZE, CfgGetInt(f, "MAX_BUFFERING_PACKET_SIZE"));
SiLoadGlobalParamItem(GP_HUB_ARP_SEND_INTERVAL, CfgGetInt(f, "HUB_ARP_SEND_INTERVAL"));
SiLoadGlobalParamItem(GP_MAC_TABLE_EXPIRE_TIME, CfgGetInt(f, "MAC_TABLE_EXPIRE_TIME"));
SiLoadGlobalParamItem(GP_IP_TABLE_EXPIRE_TIME, CfgGetInt(f, "IP_TABLE_EXPIRE_TIME"));
SiLoadGlobalParamItem(GP_IP_TABLE_EXPIRE_TIME_DHCP, CfgGetInt(f, "IP_TABLE_EXPIRE_TIME_DHCP"));
SiLoadGlobalParamItem(GP_STORM_CHECK_SPAN, CfgGetInt(f, "STORM_CHECK_SPAN"));
SiLoadGlobalParamItem(GP_STORM_DISCARD_VALUE_START, CfgGetInt(f, "STORM_DISCARD_VALUE_START"));
SiLoadGlobalParamItem(GP_STORM_DISCARD_VALUE_END, CfgGetInt(f, "STORM_DISCARD_VALUE_END"));
SiLoadGlobalParamItem(GP_MAX_MAC_TABLES, CfgGetInt(f, "MAX_MAC_TABLES"));
SiLoadGlobalParamItem(GP_MAX_IP_TABLES, CfgGetInt(f, "MAX_IP_TABLES"));
SiLoadGlobalParamItem(GP_MAX_HUB_LINKS, CfgGetInt(f, "MAX_HUB_LINKS"));
SiLoadGlobalParamItem(GP_MEM_FIFO_REALLOC_MEM_SIZE, CfgGetInt(f, "MEM_FIFO_REALLOC_MEM_SIZE"));
SiLoadGlobalParamItem(GP_QUEUE_BUDGET, CfgGetInt(f, "QUEUE_BUDGET"));
SiLoadGlobalParamItem(GP_FIFO_BUDGET, CfgGetInt(f, "FIFO_BUDGET"));
SetFifoCurrentReallocMemSize(MEM_FIFO_REALLOC_MEM_SIZE);
}
// Load global param itesm
void SiLoadGlobalParamItem(UINT id, UINT value)
{
// Validate arguments
if (id == 0)
{
return;
}
vpn_global_parameters[id] = value;
}
// Write global params
void SiWriteGlobalParamsCfg(FOLDER *f)
{
// Validate arguments
if (f == NULL)
{
return;
}
CfgAddInt(f, "MAX_SEND_SOCKET_QUEUE_SIZE", MAX_SEND_SOCKET_QUEUE_SIZE);
CfgAddInt(f, "MIN_SEND_SOCKET_QUEUE_SIZE", MIN_SEND_SOCKET_QUEUE_SIZE);
CfgAddInt(f, "MAX_SEND_SOCKET_QUEUE_NUM", MAX_SEND_SOCKET_QUEUE_NUM);
CfgAddInt(f, "SELECT_TIME", SELECT_TIME);
CfgAddInt(f, "SELECT_TIME_FOR_NAT", SELECT_TIME_FOR_NAT);
CfgAddInt(f, "MAX_STORED_QUEUE_NUM", MAX_STORED_QUEUE_NUM);
CfgAddInt(f, "MAX_BUFFERING_PACKET_SIZE", MAX_BUFFERING_PACKET_SIZE);
CfgAddInt(f, "HUB_ARP_SEND_INTERVAL", HUB_ARP_SEND_INTERVAL);
CfgAddInt(f, "MAC_TABLE_EXPIRE_TIME", MAC_TABLE_EXPIRE_TIME);
CfgAddInt(f, "IP_TABLE_EXPIRE_TIME", IP_TABLE_EXPIRE_TIME);
CfgAddInt(f, "IP_TABLE_EXPIRE_TIME_DHCP", IP_TABLE_EXPIRE_TIME_DHCP);
CfgAddInt(f, "STORM_CHECK_SPAN", STORM_CHECK_SPAN);
CfgAddInt(f, "STORM_DISCARD_VALUE_START", STORM_DISCARD_VALUE_START);
CfgAddInt(f, "STORM_DISCARD_VALUE_END", STORM_DISCARD_VALUE_END);
CfgAddInt(f, "MAX_MAC_TABLES", MAX_MAC_TABLES);
CfgAddInt(f, "MAX_IP_TABLES", MAX_IP_TABLES);
CfgAddInt(f, "MAX_HUB_LINKS", MAX_HUB_LINKS);
CfgAddInt(f, "MEM_FIFO_REALLOC_MEM_SIZE", MEM_FIFO_REALLOC_MEM_SIZE);
CfgAddInt(f, "QUEUE_BUDGET", QUEUE_BUDGET);
CfgAddInt(f, "FIFO_BUDGET", FIFO_BUDGET);
}
// Write the server-specific settings
void SiWriteServerCfg(FOLDER *f, SERVER *s)
{
BUF *b;
CEDAR *c;
FOLDER *params_folder;
// Validate arguments
if (f == NULL || s == NULL)
{
return;
}
CfgAddInt(f, "MaxConcurrentDnsClientThreads", DnsThreadNumMax());
CfgAddInt(f, "CurrentBuild", s->Cedar->Build);
CfgAddInt(f, "AutoSaveConfigSpan", s->AutoSaveConfigSpanSaved / 1000);
CfgAddBool(f, "DontBackupConfig", s->DontBackupConfig);
CfgAddBool(f, "BackupConfigOnlyWhenModified", s->BackupConfigOnlyWhenModified);
CfgAddIp(f, "ListenIP", &s->ListenIP);
{
char str[MAX_SIZE];
IntListToStr(str, sizeof(str), s->PortsUDP, ", ");
CfgAddStr(f, "PortsUDP", str);
}
if (s->Logger != NULL)
{
CfgAddInt(f, "ServerLogSwitchType", s->Logger->SwitchType);
}
CfgAddInt64(f, "LoggerMaxLogSize", GetMaxLogSize());
params_folder = CfgCreateFolder(f, "GlobalParams");
if (params_folder != NULL)
{
SiWriteGlobalParamsCfg(params_folder);
}
c = s->Cedar;
Lock(c->lock);
{
FOLDER *ff;
Lock(s->Keep->lock);
{
KEEP *k = s->Keep;
CfgAddBool(f, "UseKeepConnect", k->Enable);
CfgAddStr(f, "KeepConnectHost", k->ServerName);
CfgAddInt(f, "KeepConnectPort", k->ServerPort);
CfgAddInt(f, "KeepConnectProtocol", k->UdpMode);
CfgAddInt(f, "KeepConnectInterval", k->Interval / 1000);
}
Unlock(s->Keep->lock);
// syslog
ff = CfgCreateFolder(f, "SyslogSettings");
if (ff != NULL)
{
SYSLOG_SETTING set;
SiGetSysLogSetting(s, &set);
CfgAddInt(ff, "SaveType", set.SaveType);
CfgAddStr(ff, "HostName", set.Hostname);
CfgAddInt(ff, "Port", set.Port);
}
// Proto
ff = CfgCreateFolder(f, "Proto");
if (ff != NULL)
{
SiWriteProtoCfg(ff, s->Proto);
}
// IPv6 listener disable setting
CfgAddBool(f, "DisableIPv6Listener", s->Cedar->DisableIPv6Listener);
// DoS
CfgAddBool(f, "DisableDosProtection", s->DisableDosProtection);
// MaxConnectionsPerIP
CfgAddInt(f, "MaxConnectionsPerIP", GetMaxConnectionsPerIp());
// MaxUnestablishedConnections
CfgAddInt(f, "MaxUnestablishedConnections", GetMaxUnestablishedConnections());
// DeadLock
CfgAddBool(f, "DisableDeadLockCheck", s->DisableDeadLockCheck);
// Eraser related
CfgAddInt64(f, "AutoDeleteCheckDiskFreeSpaceMin", s->Eraser->MinFreeSpace);
CfgAddInt(f, "AutoDeleteCheckIntervalSecs", GetEraserCheckInterval());
// WebUI
CfgAddBool(f, "UseWebUI", s->UseWebUI);
// NoLinuxArpFilter
if (GetOsInfo()->OsType == OSTYPE_LINUX)
{
CfgAddBool(f, "NoLinuxArpFilter", s->NoLinuxArpFilter);
}
// NoHighPriorityProcess
CfgAddBool(f, "NoHighPriorityProcess", s->NoHighPriorityProcess);
#ifdef OS_WIN32
CfgAddBool(f, "NoDebugDump", s->NoDebugDump);
#endif // OS_WIN32
if (s->ServerType == SERVER_TYPE_STANDALONE)
{
if (c->Bridge == false)
{
// Disable the NAT-traversal feature
CfgAddBool(f, "DisableNatTraversal", s->DisableNatTraversal);
}
}
CfgAddBool(f, "DisableIPsecAggressiveMode", s->DisableIPsecAggressiveMode);
if (c->Bridge == false)
{
// VPN over ICMP
CfgAddBool(f, "EnableVpnOverIcmp", s->EnableVpnOverIcmp);
// VPN over DNS
CfgAddBool(f, "EnableVpnOverDns", s->EnableVpnOverDns);
}
// WebTimePage
CfgAddBool(f, "UseWebTimePage", s->UseWebTimePage);
// Debug log
CfgAddBool(f, "SaveDebugLog", s->SaveDebugLog);
// Let the client not to send a signature
CfgAddBool(f, "NoSendSignature", s->NoSendSignature);
// Server certificate
b = XToBuf(c->ServerX, false);
CfgAddBuf(f, "ServerCert", b);
FreeBuf(b);
// Server private key
b = KToBuf(c->ServerK, false, NULL);
CfgAddBuf(f, "ServerKey", b);
FreeBuf(b);
// Server trust chain
SiWriteCertList(CfgCreateFolder(f, "ServerChain"), c->ServerChain);
{
// Character which separates the username from the hub name
char str[2];
StrCpy(str, sizeof(str), &c->UsernameHubSeparator);
CfgAddStr(f, "UsernameHubSeparator", str);
}
// Traffic information
Lock(c->TrafficLock);
{
SiWriteTraffic(f, "ServerTraffic", c->Traffic);
}
Unlock(c->TrafficLock);
// Type of server
if (s->Cedar->Bridge == false)
{
CfgAddInt(f, "ServerType", s->UpdatedServerType);
}
// Cipher Name
CfgAddStr(f, "CipherName", s->Cedar->CipherList);
// Password
CfgAddByte(f, "HashedPassword", s->HashedPassword, sizeof(s->HashedPassword));
if (s->UpdatedServerType == SERVER_TYPE_FARM_MEMBER)
{
char tmp[6 * MAX_PUBLIC_PORT_NUM + 1];
UINT i;
// Setting items in the case of farm members
CfgAddStr(f, "ControllerName", s->ControllerName);
CfgAddInt(f, "ControllerPort", s->ControllerPort);
CfgAddByte(f, "MemberPassword", s->MemberPassword, SHA1_SIZE);
CfgAddIp32(f, "PublicIp", s->PublicIp);
tmp[0] = 0;
for (i = 0;i < s->NumPublicPort;i++)
{
char tmp2[MAX_SIZE];
ToStr(tmp2, s->PublicPorts[i]);
StrCat(tmp, sizeof(tmp), tmp2);
StrCat(tmp, sizeof(tmp), ",");
}
if (StrLen(tmp) >= 1)
{
if (tmp[StrLen(tmp) - 1] == ',')
{
tmp[StrLen(tmp) - 1] = 0;
}
}
CfgAddStr(f, "PublicPorts", tmp);
}
if (s->UpdatedServerType != SERVER_TYPE_STANDALONE)
{
CfgAddInt(f, "ClusterMemberWeight", s->Weight);
}
if (s->UpdatedServerType == SERVER_TYPE_FARM_CONTROLLER)
{
CfgAddBool(f, "ControllerOnly", s->ControllerOnly);
}
// VPN Azure Client
if (s->AzureClient != NULL)
{
CfgAddBool(f, "EnableVpnAzure", s->EnableVpnAzure);
}
CfgAddBool(f, "DisableGetHostNameWhenAcceptTcp", s->DisableGetHostNameWhenAcceptTcp);
CfgAddBool(f, "DisableCoreDumpOnUnix", s->DisableCoreDumpOnUnix);
CfgAddBool(f, "Tls_Disable1_0", c->SslAcceptSettings.Tls_Disable1_0);
CfgAddBool(f, "Tls_Disable1_1", c->SslAcceptSettings.Tls_Disable1_1);
CfgAddBool(f, "Tls_Disable1_2", c->SslAcceptSettings.Tls_Disable1_2);
CfgAddBool(f, "Tls_Disable1_3", c->SslAcceptSettings.Tls_Disable1_3);
CfgAddBool(f, "Override_Security_Level", c->SslAcceptSettings.Override_Security_Level);
CfgAddInt(f, "Override_Security_Level_Value", c->SslAcceptSettings.Override_Security_Level_Value);
CfgAddInt(f, "DhParamBits", c->DhParamBits);
// Disable session reconnect
CfgAddBool(f, "DisableSessionReconnect", GetGlobalServerFlag(GSF_DISABLE_SESSION_RECONNECT));
CfgAddBool(f, "StrictSyslogDatetimeFormat", s->StrictSyslogDatetimeFormat);
// Disable JSON-RPC Web API
CfgAddBool(f, "DisableJsonRpcWebApi", s->DisableJsonRpcWebApi);
}
Unlock(c->lock);
}
void SiLoadProtoCfg(PROTO *p, FOLDER *f)
{
UINT i;
if (p == NULL || f == NULL)
{
return;
}
for (i = 0; i < LIST_NUM(p->Containers); ++i)
{
UINT j;
const PROTO_CONTAINER *container = LIST_DATA(p->Containers, i);
LIST *options = container->Options;
FOLDER *ff = CfgGetFolder(f, container->Name);
if (ff == NULL)
{
continue;
}
LockList(options);
for (j = 0; j < LIST_NUM(options); ++j)
{
PROTO_OPTION *option = LIST_DATA(options, j);
if (CfgIsItem(ff, option->Name) == false)
{
continue;
}
switch (option->Type)
{
case PROTO_OPTION_BOOL:
option->Bool = CfgGetBool(ff, option->Name);
break;
case PROTO_OPTION_UINT32:
option->UInt32 = CfgGetInt(ff, option->Name);
break;
case PROTO_OPTION_STRING:
{
UINT size;
char buf[MAX_SIZE];
if (CfgGetStr(ff, option->Name, buf, sizeof(buf)) == false)
{
continue;
}
size = StrLen(buf) + 1;
option->String = ReAlloc(option->String, size);
StrCpy(option->String, size, buf);
break;
}
default:
Debug("SiLoadProtoCfg(): unhandled option type %u!\n", option->Type);
}
}
UnlockList(options);
}
}
void SiWriteProtoCfg(FOLDER *f, PROTO *p)
{
UINT i;
if (f == NULL || p == NULL)
{
return;
}
for (i = 0; i < LIST_NUM(p->Containers); ++i)
{
UINT j;
const PROTO_CONTAINER *container = LIST_DATA(p->Containers, i);
LIST *options = container->Options;
FOLDER *ff = CfgCreateFolder(f, container->Name);
LockList(options);
for (j = 0; j < LIST_NUM(options); ++j)
{
const PROTO_OPTION *option = LIST_DATA(options, j);
switch (option->Type)
{
case PROTO_OPTION_STRING:
CfgAddStr(ff, option->Name, option->String);
break;
case PROTO_OPTION_BOOL:
CfgAddBool(ff, option->Name, option->Bool);
break;
case PROTO_OPTION_UINT32:
CfgAddInt(ff, option->Name, option->UInt32);
break;
default:
Debug("SiWriteProtoCfg(): unhandled option type %u!\n", option->Type);
}
}
UnlockList(options);
}
}
// Read the traffic information
void SiLoadTraffic(FOLDER *parent, char *name, TRAFFIC *t)
{
FOLDER *f;
// Validate arguments
if (t != NULL)
{
Zero(t, sizeof(TRAFFIC));
}
if (parent == NULL || name == NULL || t == NULL)
{
return;
}
f = CfgGetFolder(parent, name);
if (f == NULL)
{
return;
}
SiLoadTrafficInner(f, "SendTraffic", &t->Send);
SiLoadTrafficInner(f, "RecvTraffic", &t->Recv);
}
void SiLoadTrafficInner(FOLDER *parent, char *name, TRAFFIC_ENTRY *e)
{
FOLDER *f;
// Validate arguments
if (e != NULL)
{
Zero(e, sizeof(TRAFFIC_ENTRY));
}
if (parent == NULL || name == NULL || e == NULL)
{
return;
}
f = CfgGetFolder(parent, name);
if (f == NULL)
{
return;
}
e->BroadcastCount = CfgGetInt64(f, "BroadcastCount");
e->BroadcastBytes = CfgGetInt64(f, "BroadcastBytes");
e->UnicastCount = CfgGetInt64(f, "UnicastCount");
e->UnicastBytes = CfgGetInt64(f, "UnicastBytes");
}
// Write the traffic information
void SiWriteTraffic(FOLDER *parent, char *name, TRAFFIC *t)
{
FOLDER *f;
// Validate arguments
if (parent == NULL || name == NULL || t == NULL)
{
return;
}
f = CfgCreateFolder(parent, name);
SiWriteTrafficInner(f, "SendTraffic", &t->Send);
SiWriteTrafficInner(f, "RecvTraffic", &t->Recv);
}
void SiWriteTrafficInner(FOLDER *parent, char *name, TRAFFIC_ENTRY *e)
{
FOLDER *f;
// Validate arguments
if (parent == NULL || name == NULL || e == NULL)
{
return;
}
f = CfgCreateFolder(parent, name);
CfgAddInt64(f, "BroadcastCount", e->BroadcastCount);
CfgAddInt64(f, "BroadcastBytes", e->BroadcastBytes);
CfgAddInt64(f, "UnicastCount", e->UnicastCount);
CfgAddInt64(f, "UnicastBytes", e->UnicastBytes);
}
// Thread for writing configuration file
void SiSaverThread(THREAD *thread, void *param)
{
SERVER *s = (SERVER *)param;
// Validate arguments
if (thread == NULL || param == NULL)
{
return;
}
while (s->Halt == false)
{
// Save to the configuration file
if (s->NoMoreSave == false)
{
SiWriteConfigurationFile(s);
}
Wait(s->SaveHaltEvent, s->AutoSaveConfigSpan);
}
}
// Write to the configuration file
UINT SiWriteConfigurationFile(SERVER *s)
{
UINT ret;
// Validate arguments
if (s == NULL)
{
return 0;
}
if (s->CfgRw == NULL)
{
return 0;
}
if (s->NoMoreSave)
{
return 0;
}
Lock(s->SaveCfgLock);
{
FOLDER *f;
Debug("save: SiWriteConfigurationToCfg() start.\n");
f = SiWriteConfigurationToCfg(s);
Debug("save: SiWriteConfigurationToCfg() finished.\n");
Debug("save: SaveCfgRw() start.\n");
ret = SaveCfgRwEx(s->CfgRw, f, s->BackupConfigOnlyWhenModified ? s->ConfigRevision : INFINITE);
Debug("save: SaveCfgRw() finished.\n");
Debug("save: CfgDeleteFolder() start.\n");
CfgDeleteFolder(f);
Debug("save: CfgDeleteFolder() finished.\n");
}
Unlock(s->SaveCfgLock);
return ret;
}
// Release the configuration
void SiFreeConfiguration(SERVER *s)
{
// Validate arguments
if (s == NULL)
{
return;
}
// Write to the configuration file
SiWriteConfigurationFile(s);
// Terminate the configuration file saving thread
s->NoMoreSave = true;
s->Halt = true;
Set(s->SaveHaltEvent);
WaitThread(s->SaveThread, INFINITE);
ReleaseEvent(s->SaveHaltEvent);
ReleaseThread(s->SaveThread);
s->SaveHaltEvent = NULL;
s->SaveThread = NULL;
// Stop the protocols handler
if (s->Proto != NULL)
{
ProtoDelete(s->Proto);
}
// Stop the IPsec server
if (s->IPsecServer != NULL)
{
FreeIPsecServer(s->IPsecServer);
s->IPsecServer = NULL;
}
// Terminate the DDNS client
if (s->DDnsClient != NULL)
{
FreeDDNSClient(s->DDnsClient);
s->DDnsClient = NULL;
}
// Terminate the VPN Azure client
if (s->AzureClient != NULL)
{
FreeAzureClient(s->AzureClient);
s->AzureClient = NULL;
}
FreeCfgRw(s->CfgRw);
s->CfgRw = NULL;
// Release the Ethernet
FreeEth();
}
// Initialize the StXxx related function
void StInit()
{
if (server_lock != NULL)
{
return;
}
server_lock = NewLock();
}
// Release the StXxx related function
void StFree()
{
DeleteLock(server_lock);
server_lock = NULL;
}
// Start the server
void StStartServer(bool bridge)
{
Lock(server_lock);
{
if (server != NULL)
{
// It has already started
Unlock(server_lock);
return;
}
// Create a server
server = SiNewServer(bridge);
}
Unlock(server_lock);
// StartCedarLog();
}
// Stop the server
void StStopServer()
{
Lock(server_lock);
{
if (server == NULL)
{
// Not started
Unlock(server_lock);
return;
}
// Release the server
SiReleaseServer(server);
server = NULL;
}
Unlock(server_lock);
StopCedarLog();
}
// Set the type of server
void SiSetServerType(SERVER *s, UINT type,
UINT ip, UINT num_port, UINT *ports,
char *controller_name, UINT controller_port, UCHAR *password, UINT weight, bool controller_only)
{
bool bridge;
// Validate arguments
if (s == NULL)
{
return;
}
if (type == SERVER_TYPE_FARM_MEMBER &&
(num_port == 0 || ports == NULL || controller_name == NULL ||
controller_port == 0 || password == NULL || num_port > MAX_PUBLIC_PORT_NUM))
{
return;
}
if (weight == 0)
{
weight = FARM_DEFAULT_WEIGHT;
}
bridge = s->Cedar->Bridge;
Lock(s->lock);
{
// Update types
s->UpdatedServerType = type;
s->Weight = weight;
// Set the value
if (type == SERVER_TYPE_FARM_MEMBER)
{
StrCpy(s->ControllerName, sizeof(s->ControllerName), controller_name);
s->ControllerPort = controller_port;
if (IsZero(password, SHA1_SIZE) == false)
{
Copy(s->MemberPassword, password, SHA1_SIZE);
}
s->PublicIp = ip;
s->NumPublicPort = num_port;
if (s->PublicPorts != NULL)
{
Free(s->PublicPorts);
}
s->PublicPorts = ZeroMalloc(num_port * sizeof(UINT));
Copy(s->PublicPorts, ports, num_port * sizeof(UINT));
}
if (type == SERVER_TYPE_FARM_CONTROLLER)
{
s->ControllerOnly = controller_only;
}
}
Unlock(s->lock);
// Restart the server
SiRebootServer(bridge);
}
// Thread to restart the server
void SiRebootServerThread(THREAD *thread, void *param)
{
// Validate arguments
if (thread == NULL)
{
return;
}
if (server == NULL)
{
return;
}
// Stop the server
StStopServer();
// Start the server
StStartServer((bool)param);
}
// Restart the server
void SiRebootServer(bool bridge)
{
SiRebootServerEx(bridge, false);
}
void SiRebootServerEx(bool bridge, bool reset_setting)
{
THREAD *t;
server_reset_setting = reset_setting;
t = NewThread(SiRebootServerThread, (void *)bridge);
ReleaseThread(t);
}
// Set the state of the special listener
void SiApplySpecialListenerStatus(SERVER *s)
{
// Validate arguments
if (s == NULL)
{
return;
}
if (s->DynListenerDns != NULL)
{
*s->DynListenerDns->EnablePtr = s->EnableVpnOverDns;
ApplyDynamicListener(s->DynListenerDns);
}
if (s->DynListenerIcmp != NULL)
{
*s->DynListenerIcmp->EnablePtr = s->EnableVpnOverIcmp;
ApplyDynamicListener(s->DynListenerIcmp);
}
}
// Stop all listeners
void SiStopAllListener(SERVER *s)
{
// Validate arguments
if (s == NULL)
{
return;
}
SiLockListenerList(s);
{
UINT i;
LIST *o = NewListFast(NULL);
for (i = 0;i < LIST_NUM(s->ServerListenerList);i++)
{
SERVER_LISTENER *e = LIST_DATA(s->ServerListenerList, i);
Add(o, e);
}
for (i = 0;i < LIST_NUM(o);i++)
{
SERVER_LISTENER *e = LIST_DATA(o, i);
SiDeleteListener(s, e->Port);
}
ReleaseList(o);
}
SiUnlockListenerList(s);
ReleaseList(s->ServerListenerList);
// Stop the VPN over ICMP listener
FreeDynamicListener(s->DynListenerIcmp);
s->DynListenerIcmp = NULL;
// Stop the VPN over DNS listener
FreeDynamicListener(s->DynListenerDns);
s->DynListenerDns = NULL;
}
// Clean-up the server
void SiCleanupServer(SERVER *s)
{
UINT i;
CEDAR *c;
LISTENER **listener_list;
UINT num_listener;
HUB **hub_list;
UINT num_hub;
// Validate arguments
if (s == NULL)
{
return;
}
SiFreeDeadLockCheck(s);
c = s->Cedar;
if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
{
// In the case of farm members, stop the connection to the farm controller
SLog(c, "LS_STOP_FARM_MEMBER");
SiStopConnectToController(s->FarmController);
s->FarmController = NULL;
SLog(c, "LS_STOP_FARM_MEMBER_2");
}
IncrementServerConfigRevision(s);
SLog(c, "LS_END_2");
SLog(c, "LS_STOP_ALL_LISTENER");
// Stop all listeners
LockList(c->ListenerList);
{
listener_list = ToArray(c->ListenerList);
num_listener = LIST_NUM(c->ListenerList);
for (i = 0;i < num_listener;i++)
{
AddRef(listener_list[i]->ref);
}
}
UnlockList(c->ListenerList);
for (i = 0;i < num_listener;i++)
{
StopListener(listener_list[i]);
ReleaseListener(listener_list[i]);
}
Free(listener_list);
SLog(c, "LS_STOP_ALL_LISTENER_2");
SLog(c, "LS_STOP_ALL_HUB");
// Stop all HUBs
LockList(c->HubList);
{
hub_list = ToArray(c->HubList);
num_hub = LIST_NUM(c->HubList);
for (i = 0;i < num_hub;i++)
{
AddRef(hub_list[i]->ref);
}
}
UnlockList(c->HubList);
for (i = 0;i < num_hub;i++)
{
StopHub(hub_list[i]);
ReleaseHub(hub_list[i]);
}
Free(hub_list);
SLog(c, "LS_STOP_ALL_HUB_2");
// Release the configuration
SiFreeConfiguration(s);
// Stop the Cedar
SLog(c, "LS_STOP_CEDAR");
StopCedar(s->Cedar);
SLog(c, "LS_STOP_CEDAR_2");
// Stop all listeners
SiStopAllListener(s);
ReleaseIntList(s->PortsUDP);
if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
{
// In the case of farm controller
UINT i;
SLog(c, "LS_STOP_FARM_CONTROL");
// Stop the farm controling
SiStopFarmControl(s);
// Release the farm member information
ReleaseList(s->FarmMemberList);
s->FarmMemberList = NULL;
for (i = 0;i < LIST_NUM(s->Me->HubList);i++)
{
Free(LIST_DATA(s->Me->HubList, i));
}
ReleaseList(s->Me->HubList);
Free(s->Me);
SLog(c, "LS_STOP_FARM_CONTROL_2");
}
if (s->PublicPorts != NULL)
{
Free(s->PublicPorts);
}
SLog(s->Cedar, "LS_END_1");
SLog(s->Cedar, "L_LINE");
#ifdef ENABLE_AZURE_SERVER
if (s->AzureServer != NULL)
{
FreeAzureServer(s->AzureServer);
}
#endif // ENABLE_AZURE_SERVER
ReleaseCedar(s->Cedar);
DeleteLock(s->lock);
DeleteLock(s->SaveCfgLock);
StopKeep(s->Keep);
FreeEraser(s->Eraser);
FreeLog(s->Logger);
FreeSysLog(s->Syslog);
DeleteLock(s->SyslogLock);
FreeServerCapsCache(s);
SiFreeHubCreateHistory(s);
// Stop the debug log
FreeTinyLog(s->DebugLog);
DeleteLock(s->TasksFromFarmControllerLock);
DeleteLock(s->OpenVpnSstpConfigLock);
Free(s);
}
// Release the server
void SiReleaseServer(SERVER *s)
{
// Validate arguments
if (s == NULL)
{
return;
}
if (Release(s->ref) == 0)
{
SiCleanupServer(s);
}
}
// Get the URL of the member selector
bool SiGetMemberSelectorUrl(char *url, UINT url_size)
{
BUF *b;
bool ret = false;
// Validate arguments
if (url == NULL)
{
return false;
}
b = ReadDump(MEMBER_SELECTOR_TXT_FILENAME);
if (b == NULL)
{
return false;
}
while (true)
{
char *line = CfgReadNextLine(b);
if (line == NULL)
{
break;
}
Trim(line);
if (IsEmptyStr(line) == false && ret == false)
{
StrCpy(url, url_size, line);
ret = true;
}
Free(line);
}
FreeBuf(b);
return ret;
}
// Specify the farm member for the next processing
FARM_MEMBER *SiGetNextFarmMember(SERVER *s, CONNECTION *c, HUB *h)
{
UINT i, num;
UINT min_point = 0;
FARM_MEMBER *ret = NULL;
PACK *p;
char url[MAX_SIZE];
// Validate arguments
if (s == NULL || s->ServerType != SERVER_TYPE_FARM_CONTROLLER || c == NULL || h == NULL)
{
return NULL;
}
num = LIST_NUM(s->FarmMemberList);
if (num == 0)
{
return NULL;
}
if (SiGetMemberSelectorUrl(url, sizeof(url)))
{
UINT64 ret_key = 0;
// Generate the data for the member selector
p = NewPack();
for (i = 0;i < num;i++)
{
UINT num_sessions;
UINT max_sessions;
FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
bool do_not_select = false;
if (s->ControllerOnly)
{
if (f->Me)
{
// No to select myself in the case of ControllerOnly
do_not_select = true;
}
}
if (f->Me == false)
{
num_sessions = f->NumSessions;
max_sessions = f->MaxSessions;
}
else
{
num_sessions = Count(s->Cedar->CurrentSessions);
max_sessions = GetServerCapsInt(s, "i_max_sessions");
}
if (max_sessions == 0)
{
max_sessions = GetServerCapsInt(s, "i_max_sessions");
}
if (num_sessions >= max_sessions)
{
do_not_select = true;
}
if (true)
{
UINT point = f->Point;
char public_ip_str[MAX_SIZE];
IPToStr32(public_ip_str, sizeof(public_ip_str), f->Ip);
PackAddIntEx(p, "Point", point, i, num);
PackAddInt64Ex(p, "Key", (UINT64)f, i, num);
PackAddStrEx(p, "Hostname", f->hostname, i, num);
PackAddStrEx(p, "PublicIp", public_ip_str, i, num);
PackAddIntEx(p, "NumSessions", num_sessions, i, num);
PackAddIntEx(p, "MaxSessions", max_sessions, i, num);
PackAddIntEx(p, "AssignedClientLicense", f->AssignedClientLicense, i, num);
PackAddIntEx(p, "AssignedBridgeLicense", f->AssignedBridgeLicense, i, num);
PackAddIntEx(p, "Weight", f->Weight, i, num);
PackAddDataEx(p, "RandomKey", f->RandomKey, SHA1_SIZE, i, num);
PackAddIntEx(p, "NumTcpConnections", f->NumTcpConnections, i, num);
PackAddIntEx(p, "NumHubs", LIST_NUM(f->HubList), i, num);
PackAddBoolEx(p, "Me", f->Me, i, num);
PackAddTime64Ex(p, "ConnectedTime", f->ConnectedTime, i, num);
PackAddInt64Ex(p, "SystemId", f->SystemId, i, num);
PackAddBoolEx(p, "DoNotSelect", do_not_select, i, num);
}
}
if (true)
{
char client_ip_str[MAX_SIZE];
UINT client_port = 0;
UINT server_port = 0;
SOCK *s = c->FirstSock;
Zero(client_ip_str, sizeof(client_ip_str));
if (s != NULL)
{
IPToStr(client_ip_str, sizeof(client_ip_str), &s->RemoteIP);
client_port = s->RemotePort;
server_port = s->LocalPort;
}
PackAddStr(p, "ClientIp", client_ip_str);
PackAddInt(p, "ClientPort", client_port);
PackAddInt(p, "ServerPort", server_port);
PackAddInt(p, "ClientBuild", c->ClientBuild);
PackAddStr(p, "CipherName", c->CipherName);
PackAddStr(p, "ClientStr", c->ClientStr);
PackAddInt(p, "ClientVer", c->ClientVer);
PackAddTime64(p, "ConnectedTime", Tick64ToTime64(c->ConnectedTick));
PackAddStr(p, "HubName", h->Name);
PackAddBool(p, "StaticHub", h->Type == HUB_TYPE_FARM_STATIC);
}
PackAddInt(p, "NumMembers", num);
// Make the member selector choose a member
UnlockList(s->FarmMemberList);
Unlock(s->Cedar->CedarSuperLock);
{
PACK *ret;
Debug("Calling %s ...\n", url);
ret = WpcCall(url, NULL, MEMBER_SELECTOR_CONNECT_TIMEOUT, MEMBER_SELECTOR_DATA_TIMEOUT,
"Select", p, NULL, NULL, NULL);
if (GetErrorFromPack(ret) == ERR_NO_ERROR)
{
ret_key = PackGetInt64(ret, "Key");
Debug("Ret Key = %I64u\n", ret_key);
}
else
{
Debug("Error: %u\n", GetErrorFromPack(ret));
}
FreePack(ret);
}
Lock(s->Cedar->CedarSuperLock);
LockList(s->FarmMemberList);
FreePack(p);
if (ret_key != 0)
{
FARM_MEMBER *f = (FARM_MEMBER *)ret_key;
if (IsInList(s->FarmMemberList, f))
{
Debug("Farm Member Selected by Selector: %s\n", f->hostname);
return f;
}
else
{
Debug("Farm Member Key = %I64u Not Found.\n", ret_key);
}
}
else
{
// The member selector failed to select a member
return NULL;
}
}
num = LIST_NUM(s->FarmMemberList);
if (num == 0)
{
return NULL;
}
for (i = 0;i < num;i++)
{
UINT num_sessions;
UINT max_sessions;
FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
if (s->ControllerOnly)
{
if (f->Me)
{
// No to select myself in the case of ControllerOnly
continue;
}
}
if (f->Me == false)
{
num_sessions = f->NumSessions;
max_sessions = f->MaxSessions;
}
else
{
num_sessions = Count(s->Cedar->CurrentSessions);
max_sessions = GetServerCapsInt(s, "i_max_sessions");
}
if (max_sessions == 0)
{
max_sessions = GetServerCapsInt(s, "i_max_sessions");
}
if (num_sessions < max_sessions)
{
if (f->Point >= min_point)
{
min_point = f->Point;
ret = f;
}
}
}
return ret;
}
// Receive a HUB enumeration directive
void SiCalledEnumHub(SERVER *s, PACK *p, PACK *req)
{
UINT i;
CEDAR *c;
// Validate arguments
if (s == NULL || p == NULL || req == NULL)
{
return;
}
c = s->Cedar;
LockList(c->HubList);
{
UINT num = LIST_NUM(c->HubList);
for (i = 0;i < num;i++)
{
HUB *h = LIST_DATA(c->HubList, i);
Lock(h->lock);
{
PackAddStrEx(p, "HubName", h->Name, i, num);
PackAddIntEx(p, "HubType", h->Type, i, num);
PackAddIntEx(p, "NumSession", Count(h->NumSessions), i, num);
PackAddIntEx(p, "NumSessions", LIST_NUM(h->SessionList), i, num);
PackAddIntEx(p, "NumSessionsClient", Count(h->NumSessionsClient), i, num);
PackAddIntEx(p, "NumSessionsBridge", Count(h->NumSessionsBridge), i, num);
PackAddIntEx(p, "NumMacTables", HASH_LIST_NUM(h->MacHashTable), i, num);
PackAddIntEx(p, "NumIpTables", LIST_NUM(h->IpTable), i, num);
PackAddTime64Ex(p, "LastCommTime", h->LastCommTime, i, num);
PackAddTime64Ex(p, "CreatedTime", h->CreatedTime, i, num);
}
Unlock(h->lock);
}
}
UnlockList(c->HubList);
PackAddInt(p, "Point", SiGetPoint(s));
PackAddInt(p, "NumTcpConnections", Count(s->Cedar->CurrentTcpConnections));
PackAddInt(p, "NumTotalSessions", Count(s->Cedar->CurrentSessions));
PackAddInt(p, "MaxSessions", GetServerCapsInt(s, "i_max_sessions"));
PackAddInt(p, "AssignedClientLicense", Count(s->Cedar->AssignedClientLicense));
PackAddInt(p, "AssignedBridgeLicense", Count(s->Cedar->AssignedBridgeLicense));
PackAddData(p, "RandomKey", s->MyRandomKey, SHA1_SIZE);
Lock(c->TrafficLock);
{
OutRpcTraffic(p, c->Traffic);
}
Unlock(c->TrafficLock);
LockList(c->TrafficDiffList);
{
UINT num = LIST_NUM(c->TrafficDiffList);
UINT i;
for (i = 0;i < num;i++)
{
TRAFFIC_DIFF *d = LIST_DATA(c->TrafficDiffList, i);
PackAddIntEx(p, "TdType", d->Type, i, num);
PackAddStrEx(p, "TdHubName", d->HubName, i, num);
PackAddStrEx(p, "TdName", d->Name, i, num);
OutRpcTrafficEx(&d->Traffic, p, i, num);
Free(d->HubName);
Free(d->Name);
Free(d);
}
DeleteAll(c->TrafficDiffList);
}
UnlockList(c->TrafficDiffList);
}
// Receive a HUB delete directive
void SiCalledDeleteHub(SERVER *s, PACK *p)
{
char name[MAX_SIZE];
HUB *h;
// Validate arguments
if (s == NULL || p == NULL)
{
return;
}
if (PackGetStr(p, "HubName", name, sizeof(name)) == false)
{
return;
}
LockHubList(s->Cedar);
h = GetHub(s->Cedar, name);
if (h == NULL)
{
UnlockHubList(s->Cedar);
return;
}
UnlockHubList(s->Cedar);
SetHubOffline(h);
LockHubList(s->Cedar);
DelHubEx(s->Cedar, h, true);
UnlockHubList(s->Cedar);
ReleaseHub(h);
}
// Receive a HUB update directive
void SiCalledUpdateHub(SERVER *s, PACK *p)
{
char name[MAX_SIZE];
UINT type;
HUB_OPTION o;
HUB_LOG log;
bool save_packet_log;
UINT packet_log_switch_type;
UINT packet_log_config[NUM_PACKET_LOG];
bool save_security_log;
bool type_changed = false;
UINT security_log_switch_type;
UINT i;
HUB *h;
// Validate arguments
if (s == NULL || p == NULL)
{
return;
}
PackGetStr(p, "HubName", name, sizeof(name));
type = PackGetInt(p, "HubType");
Zero(&o, sizeof(o));
o.MaxSession = PackGetInt(p, "MaxSession");
o.NoArpPolling = PackGetBool(p, "NoArpPolling");
o.NoIPv6AddrPolling = PackGetBool(p, "NoIPv6AddrPolling");
o.FilterPPPoE = PackGetBool(p, "FilterPPPoE");
o.YieldAfterStorePacket = PackGetBool(p, "YieldAfterStorePacket");
o.NoSpinLockForPacketDelay = PackGetBool(p, "NoSpinLockForPacketDelay");
o.BroadcastStormDetectionThreshold = PackGetInt(p, "BroadcastStormDetectionThreshold");
o.ClientMinimumRequiredBuild = PackGetInt(p, "ClientMinimumRequiredBuild");
o.FixForDLinkBPDU = PackGetBool(p, "FixForDLinkBPDU");
o.BroadcastLimiterStrictMode = PackGetBool(p, "BroadcastLimiterStrictMode");
o.NoLookBPDUBridgeId = PackGetBool(p, "NoLookBPDUBridgeId");
o.NoManageVlanId = PackGetBool(p, "NoManageVlanId");
o.MaxLoggedPacketsPerMinute = PackGetInt(p, "MaxLoggedPacketsPerMinute");
o.FloodingSendQueueBufferQuota = PackGetInt(p, "FloodingSendQueueBufferQuota");
o.DoNotSaveHeavySecurityLogs = PackGetBool(p, "DoNotSaveHeavySecurityLogs");
o.DropBroadcastsInPrivacyFilterMode = PackGetBool(p, "DropBroadcastsInPrivacyFilterMode");
o.DropArpInPrivacyFilterMode = PackGetBool(p, "DropArpInPrivacyFilterMode");
o.AllowSameUserInPrivacyFilterMode= PackGetBool(p, "AllowSameUserInPrivacyFilterMode");
o.SuppressClientUpdateNotification = PackGetBool(p, "SuppressClientUpdateNotification");
o.AssignVLanIdByRadiusAttribute = PackGetBool(p, "AssignVLanIdByRadiusAttribute");
o.DenyAllRadiusLoginWithNoVlanAssign = PackGetBool(p, "DenyAllRadiusLoginWithNoVlanAssign");
o.SecureNAT_RandomizeAssignIp = PackGetBool(p, "SecureNAT_RandomizeAssignIp");
o.DetectDormantSessionInterval = PackGetInt(p, "DetectDormantSessionInterval");
o.VlanTypeId = PackGetInt(p, "VlanTypeId");
o.NoPhysicalIPOnPacketLog = PackGetBool(p, "NoPhysicalIPOnPacketLog");
if (o.VlanTypeId == 0)
{
o.VlanTypeId = MAC_PROTO_TAGVLAN;
}
o.FilterOSPF = PackGetBool(p, "FilterOSPF");
o.FilterIPv4 = PackGetBool(p, "FilterIPv4");
o.FilterIPv6 = PackGetBool(p, "FilterIPv6");
o.FilterNonIP = PackGetBool(p, "FilterNonIP");
o.NoIPv4PacketLog = PackGetBool(p, "NoIPv4PacketLog");
o.NoIPv6PacketLog = PackGetBool(p, "NoIPv6PacketLog");
o.FilterBPDU = PackGetBool(p, "FilterBPDU");
o.NoIPv6DefaultRouterInRAWhenIPv6 = PackGetBool(p, "NoIPv6DefaultRouterInRAWhenIPv6");
o.NoMacAddressLog = PackGetBool(p, "NoMacAddressLog");
o.ManageOnlyPrivateIP = PackGetBool(p, "ManageOnlyPrivateIP");
o.ManageOnlyLocalUnicastIPv6 = PackGetBool(p, "ManageOnlyLocalUnicastIPv6");
o.DisableIPParsing = PackGetBool(p, "DisableIPParsing");
o.NoIpTable = PackGetBool(p, "NoIpTable");
o.NoEnum = PackGetBool(p, "NoEnum");
o.AdjustTcpMssValue = PackGetInt(p, "AdjustTcpMssValue");
o.DisableAdjustTcpMss = PackGetBool(p, "DisableAdjustTcpMss");
o.NoDhcpPacketLogOutsideHub = PackGetBool(p, "NoDhcpPacketLogOutsideHub");
o.DisableHttpParsing = PackGetBool(p, "DisableHttpParsing");
o.DisableUdpAcceleration = PackGetBool(p, "DisableUdpAcceleration");
o.DisableUdpFilterForLocalBridgeNic = PackGetBool(p, "DisableUdpFilterForLocalBridgeNic");
o.ApplyIPv4AccessListOnArpPacket = PackGetBool(p, "ApplyIPv4AccessListOnArpPacket");
o.RemoveDefGwOnDhcpForLocalhost = PackGetBool(p, "RemoveDefGwOnDhcpForLocalhost");
o.SecureNAT_MaxTcpSessionsPerIp = PackGetInt(p, "SecureNAT_MaxTcpSessionsPerIp");
o.SecureNAT_MaxTcpSynSentPerIp = PackGetInt(p, "SecureNAT_MaxTcpSynSentPerIp");
o.SecureNAT_MaxUdpSessionsPerIp = PackGetInt(p, "SecureNAT_MaxUdpSessionsPerIp");
o.SecureNAT_MaxDnsSessionsPerIp = PackGetInt(p, "SecureNAT_MaxDnsSessionsPerIp");
o.SecureNAT_MaxIcmpSessionsPerIp = PackGetInt(p, "SecureNAT_MaxIcmpSessionsPerIp");
o.AccessListIncludeFileCacheLifetime = PackGetInt(p, "AccessListIncludeFileCacheLifetime");
if (o.AccessListIncludeFileCacheLifetime == 0)
{
o.AccessListIncludeFileCacheLifetime = ACCESS_LIST_INCLUDE_FILE_CACHE_LIFETIME;
}
o.DisableKernelModeSecureNAT = PackGetBool(p, "DisableKernelModeSecureNAT");
o.DisableIpRawModeSecureNAT = PackGetBool(p, "DisableIpRawModeSecureNAT");
o.DisableUserModeSecureNAT = PackGetBool(p, "DisableUserModeSecureNAT");
o.DisableCheckMacOnLocalBridge = PackGetBool(p, "DisableCheckMacOnLocalBridge");
o.DisableCorrectIpOffloadChecksum = PackGetBool(p, "DisableCorrectIpOffloadChecksum");
o.UseHubNameAsDhcpUserClassOption = PackGetBool(p, "UseHubNameAsDhcpUserClassOption");
o.UseHubNameAsRadiusNasId = PackGetBool(p, "UseHubNameAsRadiusNasId");
o.AllowEapMatchUserByCert = PackGetBool(p, "AllowEapMatchUserByCert");
save_packet_log = PackGetInt(p, "SavePacketLog");
packet_log_switch_type = PackGetInt(p, "PacketLogSwitchType");
for (i = 0;i < NUM_PACKET_LOG;i++)
{
packet_log_config[i] = PackGetIntEx(p, "PacketLogConfig", i);
}
save_security_log = PackGetInt(p, "SaveSecurityLog");
security_log_switch_type = PackGetInt(p, "SecurityLogSwitchType");
Zero(&log, sizeof(log));
log.SavePacketLog = save_packet_log;
log.PacketLogSwitchType = packet_log_switch_type;
Copy(log.PacketLogConfig, packet_log_config, sizeof(log.PacketLogConfig));
log.SaveSecurityLog = save_security_log;
log.SecurityLogSwitchType = security_log_switch_type;
h = GetHub(s->Cedar, name);
if (h == NULL)
{
return;
}
h->FarmMember_MaxSessionClient = PackGetInt(p, "MaxSessionClient");
h->FarmMember_MaxSessionBridge = PackGetInt(p, "MaxSessionBridge");
h->FarmMember_MaxSessionClientBridgeApply = PackGetBool(p, "MaxSessionClientBridgeApply");
if (h->FarmMember_MaxSessionClientBridgeApply == false)
{
h->FarmMember_MaxSessionClient = INFINITE;
h->FarmMember_MaxSessionBridge = INFINITE;
}
Lock(h->lock);
{
Copy(h->Option, &o, sizeof(HUB_OPTION));
PackGetData2(p, "SecurePassword", h->SecurePassword, SHA1_SIZE);
PackGetData2(p, "HashedPassword", h->HashedPassword, SHA1_SIZE);
}
Unlock(h->lock);
SetHubLogSetting(h, &log);
if (h->Type != type)
{
h->Type = type;
type_changed = true;
}
LockList(h->AccessList);
{
UINT i;
for (i = 0;i < LIST_NUM(h->AccessList);i++)
{
ACCESS *a = LIST_DATA(h->AccessList, i);
Free(a);
}
DeleteAll(h->AccessList);
}
UnlockList(h->AccessList);
for (i = 0;i < SiNumAccessFromPack(p);i++)
{
ACCESS *a = SiPackToAccess(p, i);
AddAccessList(h, a);
Free(a);
}
if (PackGetBool(p, "EnableSecureNAT"))
{
VH_OPTION t;
bool changed;
InVhOption(&t, p);
changed = Cmp(h->SecureNATOption, &t, sizeof(VH_OPTION)) == 0 ? false : true;
Copy(h->SecureNATOption, &t, sizeof(VH_OPTION));
EnableSecureNAT(h, true);
if (changed)
{
Lock(h->lock_online);
{
if (h->SecureNAT != NULL)
{
SetVirtualHostOption(h->SecureNAT->Nat->Virtual, &t);
Debug("SiCalledUpdateHub: SecureNAT Updated.\n");
}
}
Unlock(h->lock_online);
}
}
else
{
EnableSecureNAT(h, false);
Debug("SiCalledUpdateHub: SecureNAT Disabled.\n");
}
if (type_changed)
{
// Remove all sessions since the type of HUB has been changed
if (h->Offline == false)
{
SetHubOffline(h);
SetHubOnline(h);
}
}
ReleaseHub(h);
}
// Inspect the ticket
bool SiCheckTicket(HUB *h, UCHAR *ticket, char *username, UINT username_size, char *usernamereal, UINT usernamereal_size, POLICY *policy, char *sessionname, UINT sessionname_size, char *groupname, UINT groupname_size)
{
bool ret = false;
// Validate arguments
if (h == NULL || ticket == NULL || username == NULL || usernamereal == NULL || policy == NULL || sessionname == NULL)
{
return false;
}
LockList(h->TicketList);
{
UINT i;
for (i = 0;i < LIST_NUM(h->TicketList);i++)
{
TICKET *t = LIST_DATA(h->TicketList, i);
if (Cmp(t->Ticket, ticket, SHA1_SIZE) == 0)
{
ret = true;
StrCpy(username, username_size, t->Username);
StrCpy(usernamereal, usernamereal_size, t->UsernameReal);
StrCpy(sessionname, sessionname_size, t->SessionName);
StrCpy(groupname, groupname_size, t->GroupName);
Copy(policy, &t->Policy, sizeof(POLICY));
Delete(h->TicketList, t);
Free(t);
break;
}
}
}
UnlockList(h->TicketList);
return ret;
}
// Receive a MAC address deletion directive
void SiCalledDeleteMacTable(SERVER *s, PACK *p)
{
UINT key;
char hubname[MAX_HUBNAME_LEN + 1];
HUB *h;
// Validate arguments
if (s == NULL || p == NULL)
{
return;
}
if (PackGetStr(p, "HubName", hubname, sizeof(hubname)) == false)
{
return;
}
key = PackGetInt(p, "Key");
LockHubList(s->Cedar);
{
h = GetHub(s->Cedar, hubname);
}
UnlockHubList(s->Cedar);
if (h == NULL)
{
return;
}
LockHashList(h->MacHashTable);
{
MAC_TABLE_ENTRY *e = HashListKeyToPointer(h->MacHashTable, key);
DeleteHash(h->MacHashTable, e);
Free(e);
}
UnlockHashList(h->MacHashTable);
ReleaseHub(h);
}
// Receive an IP address delete directive
void SiCalledDeleteIpTable(SERVER *s, PACK *p)
{
UINT key;
char hubname[MAX_HUBNAME_LEN + 1];
HUB *h;
// Validate arguments
if (s == NULL || p == NULL)
{
return;
}
if (PackGetStr(p, "HubName", hubname, sizeof(hubname)) == false)
{
return;
}
key = PackGetInt(p, "Key");
LockHubList(s->Cedar);
{
h = GetHub(s->Cedar, hubname);
}
UnlockHubList(s->Cedar);
if (h == NULL)
{
return;
}
LockList(h->IpTable);
{
if (IsInList(h->IpTable, (void *)key))
{
IP_TABLE_ENTRY *e = (IP_TABLE_ENTRY *)key;
Delete(h->IpTable, e);
Free(e);
}
}
UnlockList(h->IpTable);
ReleaseHub(h);
}
// Receive a session deletion directive
void SiCalledDeleteSession(SERVER *s, PACK *p)
{
char name[MAX_SESSION_NAME_LEN + 1];
char hubname[MAX_HUBNAME_LEN + 1];
HUB *h;
SESSION *sess;
// Validate arguments
if (s == NULL || p == NULL)
{
return;
}
if (PackGetStr(p, "HubName", hubname, sizeof(hubname)) == false)
{
return;
}
if (PackGetStr(p, "SessionName", name, sizeof(name)) == false)
{
return;
}
LockHubList(s->Cedar);
{
h = GetHub(s->Cedar, hubname);
}
UnlockHubList(s->Cedar);
if (h == NULL)
{
return;
}
sess = GetSessionByName(h, name);
if (sess != NULL)
{
if (sess->BridgeMode == false && sess->LinkModeServer == false && sess->SecureNATMode == false)
{
StopSession(sess);
}
ReleaseSession(sess);
}
ReleaseHub(h);
}
// Receive a log file reading directive
PACK *SiCalledReadLogFile(SERVER *s, PACK *p)
{
RPC_READ_LOG_FILE t;
PACK *ret;
char filepath[MAX_PATH];
UINT offset;
// Validate arguments
if (s == NULL || p == NULL)
{
return NULL;
}
PackGetStr(p, "FilePath", filepath, sizeof(filepath));
offset = PackGetInt(p, "Offset");
Zero(&t, sizeof(t));
SiReadLocalLogFile(s, filepath, offset, &t);
ret = NewPack();
OutRpcReadLogFile(ret, &t);
FreeRpcReadLogFile(&t);
return ret;
}
// Receive a log file enumeration directive
PACK *SiCalledEnumLogFileList(SERVER *s, PACK *p)
{
RPC_ENUM_LOG_FILE t;
PACK *ret;
char hubname[MAX_HUBNAME_LEN + 1];
// Validate arguments
if (s == NULL || p == NULL)
{
return NULL;
}
PackGetStr(p, "HubName", hubname, sizeof(hubname));
Zero(&t, sizeof(t));
SiEnumLocalLogFileList(s, hubname, &t);
ret = NewPack();
OutRpcEnumLogFile(ret, &t);
FreeRpcEnumLogFile(&t);
return ret;
}
// Receive a session information directive
PACK *SiCalledGetSessionStatus(SERVER *s, PACK *p)
{
RPC_SESSION_STATUS t;
ADMIN a;
PACK *ret;
// Validate arguments
if (s == NULL || p == NULL)
{
return NULL;
}
Zero(&t, sizeof(t));
InRpcSessionStatus(&t, p);
Zero(&a, sizeof(a));
a.Server = s;
a.ServerAdmin = true;
if (StGetSessionStatus(&a, &t) != ERR_NO_ERROR)
{
FreeRpcSessionStatus(&t);
return NULL;
}
ret = NewPack();
OutRpcSessionStatus(ret, &t);
FreeRpcSessionStatus(&t);
return ret;
}
// IP table enumeration directive
PACK *SiCalledEnumIpTable(SERVER *s, PACK *p)
{
char hubname[MAX_HUBNAME_LEN + 1];
RPC_ENUM_IP_TABLE t;
PACK *ret;
// Validate arguments
if (s == NULL || p == NULL)
{
return NewPack();
}
if (PackGetStr(p, "HubName", hubname, sizeof(hubname)) == false)
{
return NewPack();
}
Zero(&t, sizeof(t));
SiEnumIpTable(s, hubname, &t);
ret = NewPack();
OutRpcEnumIpTable(ret, &t);
FreeRpcEnumIpTable(&t);
return ret;
}
// MAC table enumeration directive
PACK *SiCalledEnumMacTable(SERVER *s, PACK *p)
{
char hubname[MAX_HUBNAME_LEN + 1];
RPC_ENUM_MAC_TABLE t;
PACK *ret;
// Validate arguments
if (s == NULL || p == NULL)
{
return NewPack();
}
if (PackGetStr(p, "HubName", hubname, sizeof(hubname)) == false)
{
return NewPack();
}
Zero(&t, sizeof(t));
SiEnumMacTable(s, hubname, &t);
ret = NewPack();
OutRpcEnumMacTable(ret, &t);
FreeRpcEnumMacTable(&t);
return ret;
}
// NAT status acquisition directive
PACK *SiCalledGetNatStatus(SERVER *s, PACK *p)
{
char hubname[MAX_HUBNAME_LEN + 1];
RPC_NAT_STATUS t;
PACK *ret;
HUB *h;
// Validate arguments
if (s == NULL || p == NULL)
{
return NewPack();
}
if (PackGetStr(p, "HubName", hubname, sizeof(hubname)) == false)
{
return NewPack();
}
Zero(&t, sizeof(t));
LockHubList(s->Cedar);
{
h = GetHub(s->Cedar, hubname);
}
UnlockHubList(s->Cedar);
if (h != NULL)
{
Lock(h->lock_online);
{
if (h->SecureNAT != NULL)
{
NtGetStatus(h->SecureNAT->Nat, &t);
}
}
Unlock(h->lock_online);
}
ReleaseHub(h);
ret = NewPack();
OutRpcNatStatus(ret, &t);
FreeRpcNatStatus(&t);
return ret;
}
// DHCP table enumeration directive
PACK *SiCalledEnumDhcp(SERVER *s, PACK *p)
{
char hubname[MAX_HUBNAME_LEN + 1];
RPC_ENUM_DHCP t;
PACK *ret;
HUB *h;
// Validate arguments
if (s == NULL || p == NULL)
{
return NewPack();
}
if (PackGetStr(p, "HubName", hubname, sizeof(hubname)) == false)
{
return NewPack();
}
Zero(&t, sizeof(t));
LockHubList(s->Cedar);
{
h = GetHub(s->Cedar, hubname);
}
UnlockHubList(s->Cedar);
if (h != NULL)
{
Lock(h->lock_online);
{
if (h->SecureNAT != NULL)
{
NtEnumDhcpList(h->SecureNAT->Nat, &t);
}
}
Unlock(h->lock_online);
}
ReleaseHub(h);
ret = NewPack();
OutRpcEnumDhcp(ret, &t);
FreeRpcEnumDhcp(&t);
return ret;
}
// NAT table enumeration directive
PACK *SiCalledEnumNat(SERVER *s, PACK *p)
{
char hubname[MAX_HUBNAME_LEN + 1];
RPC_ENUM_NAT t;
PACK *ret;
HUB *h;
// Validate arguments
if (s == NULL || p == NULL)
{
return NewPack();
}
if (PackGetStr(p, "HubName", hubname, sizeof(hubname)) == false)
{
return NewPack();
}
Zero(&t, sizeof(t));
LockHubList(s->Cedar);
{
h = GetHub(s->Cedar, hubname);
}
UnlockHubList(s->Cedar);
if (h != NULL)
{
Lock(h->lock_online);
{
if (h->SecureNAT != NULL)
{
NtEnumNatList(h->SecureNAT->Nat, &t);
}
}
Unlock(h->lock_online);
}
ReleaseHub(h);
ret = NewPack();
OutRpcEnumNat(ret, &t);
FreeRpcEnumNat(&t);
return ret;
}
// Receive a session enumeration directive
PACK *SiCalledEnumSession(SERVER *s, PACK *p)
{
char hubname[MAX_HUBNAME_LEN + 1];
RPC_ENUM_SESSION t;
PACK *ret;
// Validate arguments
if (s == NULL || p == NULL)
{
return NewPack();
}
if (PackGetStr(p, "HubName", hubname, sizeof(hubname)) == false)
{
return NewPack();
}
Zero(&t, sizeof(t));
SiEnumLocalSession(s, hubname, &t);
ret = NewPack();
OutRpcEnumSession(ret, &t);
FreeRpcEnumSession(&t);
return ret;
}
// Receive a ticket creation directive
PACK *SiCalledCreateTicket(SERVER *s, PACK *p)
{
char username[MAX_SIZE];
char hubname[MAX_SIZE];
char groupname[MAX_SIZE];
char realusername[MAX_SIZE];
char sessionname[MAX_SESSION_NAME_LEN + 1];
POLICY policy;
UCHAR ticket[SHA1_SIZE];
char ticket_str[MAX_SIZE];
HUB *h;
UINT i;
PACK *ret;
TICKET *t;
// Validate arguments
if (s == NULL || p == NULL)
{
return NewPack();
}
PackGetStr(p, "UserName", username, sizeof(username));
PackGetStr(p, "GroupName", groupname, sizeof(groupname));
PackGetStr(p, "HubName", hubname, sizeof(hubname));
PackGetStr(p, "RealUserName", realusername, sizeof(realusername));
PackGetStr(p, "SessionName", sessionname, sizeof(sessionname));
InRpcPolicy(&policy, p);
if (PackGetDataSize(p, "Ticket") == SHA1_SIZE)
{
PackGetData(p, "Ticket", ticket);
}
BinToStr(ticket_str, sizeof(ticket_str), ticket, SHA1_SIZE);
SLog(s->Cedar, "LS_TICKET_2", hubname, username, realusername, sessionname,
ticket_str, TICKET_EXPIRES / 1000);
// Get the HUB
h = GetHub(s->Cedar, hubname);
if (h == NULL)
{
return NewPack();
}
LockList(h->TicketList);
{
LIST *o = NewListFast(NULL);
// Discard old tickets
for (i = 0;i < LIST_NUM(h->TicketList);i++)
{
TICKET *t = LIST_DATA(h->TicketList, i);
if ((t->CreatedTick + TICKET_EXPIRES) < Tick64())
{
Add(o, t);
}
}
for (i = 0;i < LIST_NUM(o);i++)
{
TICKET *t = LIST_DATA(o, i);
Delete(h->TicketList, t);
Free(t);
}
ReleaseList(o);
// Create a ticket
t = ZeroMalloc(sizeof(TICKET));
t->CreatedTick = Tick64();
Copy(&t->Policy, &policy, sizeof(POLICY));
Copy(t->Ticket, ticket, SHA1_SIZE);
StrCpy(t->Username, sizeof(t->Username), username);
StrCpy(t->UsernameReal, sizeof(t->UsernameReal), realusername);
StrCpy(t->GroupName, sizeof(t->GroupName), groupname);
StrCpy(t->SessionName, sizeof(t->SessionName), sessionname);
Add(h->TicketList, t);
}
UnlockList(h->TicketList);
ReleaseHub(h);
ret = NewPack();
PackAddInt(ret, "Point", SiGetPoint(s));
return ret;
}
// Receive a HUB creation directive
void SiCalledCreateHub(SERVER *s, PACK *p)
{
char name[MAX_SIZE];
UINT type;
HUB_OPTION o;
HUB_LOG log;
bool save_packet_log;
UINT packet_log_switch_type;
UINT packet_log_config[NUM_PACKET_LOG];
bool save_security_log;
UINT security_log_switch_type;
UINT i;
HUB *h;
// Validate arguments
if (s == NULL || p == NULL)
{
return;
}
PackGetStr(p, "HubName", name, sizeof(name));
type = PackGetInt(p, "HubType");
Zero(&o, sizeof(o));
o.MaxSession = PackGetInt(p, "MaxSession");
save_packet_log = PackGetInt(p, "SavePacketLog");
packet_log_switch_type = PackGetInt(p, "PacketLogSwitchType");
for (i = 0;i < NUM_PACKET_LOG;i++)
{
packet_log_config[i] = PackGetIntEx(p, "PacketLogConfig", i);
}
save_security_log = PackGetInt(p, "SaveSecurityLog");
security_log_switch_type = PackGetInt(p, "SecurityLogSwitchType");
Zero(&log, sizeof(log));
log.SavePacketLog = save_packet_log;
log.PacketLogSwitchType = packet_log_switch_type;
Copy(log.PacketLogConfig, packet_log_config, sizeof(log.PacketLogConfig));
log.SaveSecurityLog = save_security_log;
log.SecurityLogSwitchType = security_log_switch_type;
h = NewHub(s->Cedar, name, &o);
h->LastCommTime = h->LastLoginTime = h->CreatedTime = 0;
SetHubLogSetting(h, &log);
h->Type = type;
h->FarmMember_MaxSessionClient = PackGetInt(p, "MaxSessionClient");
h->FarmMember_MaxSessionBridge = PackGetInt(p, "MaxSessionBridge");
h->FarmMember_MaxSessionClientBridgeApply = PackGetBool(p, "MaxSessionClientBridgeApply");
if (h->FarmMember_MaxSessionClientBridgeApply == false)
{
h->FarmMember_MaxSessionClient = INFINITE;
h->FarmMember_MaxSessionBridge = INFINITE;
}
PackGetData2(p, "SecurePassword", h->SecurePassword, SHA1_SIZE);
PackGetData2(p, "HashedPassword", h->HashedPassword, SHA1_SIZE);
for (i = 0;i < SiNumAccessFromPack(p);i++)
{
ACCESS *a = SiPackToAccess(p, i);
AddAccessList(h, a);
Free(a);
}
if (PackGetBool(p, "EnableSecureNAT"))
{
VH_OPTION t;
InVhOption(&t, p);
Copy(h->SecureNATOption, &t, sizeof(VH_OPTION));
EnableSecureNAT(h, true);
Debug("SiCalledCreateHub: SecureNAT Created.\n");
}
AddHub(s->Cedar, h);
h->Offline = true;
SetHubOnline(h);
ReleaseHub(h);
}
// Farm control thread
void SiFarmControlThread(THREAD *thread, void *param)
{
SERVER *s;
CEDAR *c;
EVENT *e;
LIST *o;
UINT i;
char tmp[MAX_PATH];
// Validate arguments
if (thread == NULL || param == NULL)
{
return;
}
s = (SERVER *)param;
c = s->Cedar;
e = s->FarmControlThreadHaltEvent;
while (true)
{
Lock(c->CedarSuperLock);
// Enumerate HUB list which is hosted by each farm member
Format(tmp, sizeof(tmp), "CONTROLLER: %s %u", __FILE__, __LINE__);
SiDebugLog(s, tmp);
LockList(s->FarmMemberList);
{
UINT i;
UINT num;
UINT assigned_client_license = 0;
UINT assigned_bridge_license = 0;
LIST *fm_list = NewListFast(NULL);
Format(tmp, sizeof(tmp), "CONTROLLER: %s %u", __FILE__, __LINE__);
SiDebugLog(s, tmp);
num = 0;
while (true)
{
bool escape = true;
for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
{
FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
if (IsInList(fm_list, f) == false)
{
SiCallEnumHub(s, f);
// Get the total number of sessions across the server farm
num += f->NumSessions;
assigned_client_license += f->AssignedClientLicense;
assigned_bridge_license += f->AssignedBridgeLicense;
escape = false;
Add(fm_list, f);
break;
}
}
if (escape)
{
break;
}
UnlockList(s->FarmMemberList);
LockList(s->FarmMemberList);
}
ReleaseList(fm_list);
s->CurrentTotalNumSessionsOnFarm = num;
// Update the number of assigned licenses
s->CurrentAssignedBridgeLicense = assigned_bridge_license;
s->CurrentAssignedClientLicense = assigned_client_license;
Format(tmp, sizeof(tmp), "CONTROLLER: %s %u", __FILE__, __LINE__);
SiDebugLog(s, tmp);
}
UnlockList(s->FarmMemberList);
Format(tmp, sizeof(tmp), "CONTROLLER: %s %u", __FILE__, __LINE__);
SiDebugLog(s, tmp);
o = NewListFast(NULL);
Format(tmp, sizeof(tmp), "CONTROLLER: %s %u", __FILE__, __LINE__);
SiDebugLog(s, tmp);
// Emit an update notification for each HUB
LockList(c->HubList);
{
UINT i;
for (i = 0;i < LIST_NUM(c->HubList);i++)
{
HUB *h = LIST_DATA(c->HubList, i);
AddRef(h->ref);
Add(o, h);
}
}
UnlockList(c->HubList);
Format(tmp, sizeof(tmp), "CONTROLLER: %s %u", __FILE__, __LINE__);
SiDebugLog(s, tmp);
for (i = 0;i < LIST_NUM(o);i++)
{
HUB *h = LIST_DATA(o, i);
SiHubUpdateProc(h);
ReleaseHub(h);
}
Format(tmp, sizeof(tmp), "CONTROLLER: %s %u", __FILE__, __LINE__);
SiDebugLog(s, tmp);
ReleaseList(o);
Unlock(c->CedarSuperLock);
Wait(e, SERVER_FARM_CONTROL_INTERVAL);
if (s->Halt)
{
break;
}
}
}
// Start the farm controling
void SiStartFarmControl(SERVER *s)
{
// Validate arguments
if (s == NULL || s->ServerType != SERVER_TYPE_FARM_CONTROLLER)
{
return;
}
s->FarmControlThreadHaltEvent = NewEvent();
s->FarmControlThread = NewThread(SiFarmControlThread, s);
}
// Stop the farm controling
void SiStopFarmControl(SERVER *s)
{
// Validate arguments
if (s == NULL || s->ServerType != SERVER_TYPE_FARM_CONTROLLER)
{
return;
}
Set(s->FarmControlThreadHaltEvent);
WaitThread(s->FarmControlThread, INFINITE);
ReleaseEvent(s->FarmControlThreadHaltEvent);
ReleaseThread(s->FarmControlThread);
}
// HUB enumeration directive
void SiCallEnumHub(SERVER *s, FARM_MEMBER *f)
{
CEDAR *c;
// Validate arguments
if (s == NULL || f == NULL)
{
return;
}
c = s->Cedar;
if (f->Me)
{
// Enumerate local HUBs
LockList(f->HubList);
{
// For a local HUB, re-enumerate by erasing all STATIC HUB list once first
UINT i;
LIST *o = NewListFast(NULL);
for (i = 0;i < LIST_NUM(f->HubList);i++)
{
HUB_LIST *h = LIST_DATA(f->HubList, i);
if (h->DynamicHub == false)
{
Add(o, h);
}
}
// Clear all the STATIC HUB
for (i = 0;i < LIST_NUM(o);i++)
{
HUB_LIST *h = LIST_DATA(o, i);
Free(h);
Delete(f->HubList, h);
}
ReleaseList(o);
// Second, stop DYNAMIC HUBs without user
o = NewListFast(NULL);
for (i = 0;i < LIST_NUM(f->HubList);i++)
{
HUB_LIST *h = LIST_DATA(f->HubList, i);
if (h->DynamicHub == true)
{
LockList(c->HubList);
{
HUB *hub = GetHub(s->Cedar, h->Name);
if (hub != NULL)
{
if (Count(hub->NumSessions) == 0 || hub->Type != HUB_TYPE_FARM_DYNAMIC)
{
Add(o, h);
}
ReleaseHub(hub);
}
}
UnlockList(c->HubList);
}
}
for (i = 0;i < LIST_NUM(o);i++)
{
HUB_LIST *h = LIST_DATA(o, i);
Debug("Delete HUB: %s\n", h->Name);
Free(h);
Delete(f->HubList, h);
}
ReleaseList(o);
// Set the enumeration results
LockList(c->HubList);
{
for (i = 0;i < LIST_NUM(c->HubList);i++)
{
HUB *h = LIST_DATA(c->HubList, i);
if (h->Offline == false)
{
if (h->Type == HUB_TYPE_FARM_STATIC)
{
HUB_LIST *hh = ZeroMalloc(sizeof(HUB_LIST));
hh->FarmMember = f;
hh->DynamicHub = false;
StrCpy(hh->Name, sizeof(hh->Name), h->Name);
Add(f->HubList, hh);
LockList(h->SessionList);
{
hh->NumSessions = LIST_NUM(h->SessionList);
hh->NumSessionsBridge = Count(h->NumSessionsBridge);
hh->NumSessionsClient = Count(h->NumSessionsClient);
}
UnlockList(h->SessionList);
LockHashList(h->MacHashTable);
{
hh->NumMacTables = HASH_LIST_NUM(h->MacHashTable);
}
UnlockHashList(h->MacHashTable);
LockList(h->IpTable);
{
hh->NumIpTables = LIST_NUM(h->IpTable);
}
UnlockList(h->IpTable);
}
}
}
}
UnlockList(c->HubList);
}
UnlockList(f->HubList);
// Point
f->Point = SiGetPoint(s);
f->NumSessions = Count(s->Cedar->CurrentSessions);
f->MaxSessions = GetServerCapsInt(s, "i_max_sessions");
f->NumTcpConnections = Count(s->Cedar->CurrentTcpConnections);
Lock(s->Cedar->TrafficLock);
{
Copy(&f->Traffic, s->Cedar->Traffic, sizeof(TRAFFIC));
}
Unlock(s->Cedar->TrafficLock);
f->AssignedBridgeLicense = Count(s->Cedar->AssignedBridgeLicense);
f->AssignedClientLicense = Count(s->Cedar->AssignedClientLicense);
Copy(f->RandomKey, s->MyRandomKey, SHA1_SIZE);
Debug("Server %s: Point %u\n", f->hostname, f->Point);
}
else
{
// Enumerate HUBs which are remote member
PACK *p = NewPack();
UINT i, num, j;
LIST *o = NewListFast(NULL);
num = 0;
for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
{
FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
if (IsZero(f->RandomKey, SHA1_SIZE) == false && f->SystemId != 0)
{
num++;
}
}
j = 0;
for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
{
FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
if (IsZero(f->RandomKey, SHA1_SIZE) == false && f->SystemId != 0)
{
PackAddDataEx(p, "MemberRandomKey", f->RandomKey, SHA1_SIZE, j, num);
PackAddInt64Ex(p, "MemberSystemId", f->SystemId, j, num);
j++;
}
}
PackAddInt(p, "MemberSystemIdNum", num);
p = SiCallTask(f, p, "enumhub");
if (p != NULL)
{
LockList(f->HubList);
{
UINT i;
// Erase the list
for (i = 0;i < LIST_NUM(f->HubList);i++)
{
HUB_LIST *hh = LIST_DATA(f->HubList, i);
Free(hh);
}
DeleteAll(f->HubList);
for (i = 0;i < PackGetIndexCount(p, "HubName");i++)
{
HUB_LIST *hh = ZeroMalloc(sizeof(HUB_LIST));
UINT num;
UINT64 LastCommTime;
PackGetStrEx(p, "HubName", hh->Name, sizeof(hh->Name), i);
num = PackGetIntEx(p, "NumSession", i);
hh->DynamicHub = ((PackGetIntEx(p, "HubType", i) == HUB_TYPE_FARM_DYNAMIC) ? true : false);
hh->FarmMember = f;
hh->NumSessions = PackGetIntEx(p, "NumSessions", i);
hh->NumSessionsClient = PackGetIntEx(p, "NumSessionsClient", i);
hh->NumSessionsBridge = PackGetIntEx(p, "NumSessionsBridge", i);
hh->NumIpTables = PackGetIntEx(p, "NumIpTables", i);
hh->NumMacTables = PackGetIntEx(p, "NumMacTables", i);
LastCommTime = PackGetInt64Ex(p, "LastCommTime", i);
Add(f->HubList, hh);
//Debug("%s\n", hh->Name);
LockList(c->HubList);
{
HUB *h = GetHub(c, hh->Name);
if (h != NULL)
{
// Update the LastCommTime of the Virtual HUB
Lock(h->lock);
{
if (h->LastCommTime < LastCommTime)
{
h->LastCommTime = LastCommTime;
}
}
Unlock(h->lock);
ReleaseHub(h);
}
}
UnlockList(c->HubList);
if (hh->DynamicHub && num >= 1)
{
// It is not necessary to be registered in the virtual HUB creation
// history list because user session is already connected.
// Remove from the Virtual HUB creation history list
SiDelHubCreateHistory(s, hh->Name);
}
if (hh->DynamicHub && num == 0)
{
// Check the Virtual HUB creation history list.
// If it is created within 60 seconds of the most recent
// in the case of Virtual HUB which the first user is not
// connected yet, not to remove because there is no user
if (SiIsHubRegistedOnCreateHistory(s, hh->Name) == false)
{
// Stop because all uses have gone in the dynamic HUB
HUB *h;
LockList(c->HubList);
{
h = GetHub(c, hh->Name);
}
UnlockList(c->HubList);
if (h != NULL)
{
Add(o, h);
}
}
}
}
}
UnlockList(f->HubList);
f->Point = PackGetInt(p, "Point");
Debug("Server %s: Point %u\n", f->hostname, f->Point);
f->NumSessions = PackGetInt(p, "NumTotalSessions");
if (f->NumSessions == 0)
{
f->NumSessions = PackGetInt(p, "NumSessions");
}
f->MaxSessions = PackGetInt(p, "MaxSessions");
f->NumTcpConnections = PackGetInt(p, "NumTcpConnections");
InRpcTraffic(&f->Traffic, p);
f->AssignedBridgeLicense = PackGetInt(p, "AssignedBridgeLicense");
f->AssignedClientLicense = PackGetInt(p, "AssignedClientLicense");
if (PackGetDataSize(p, "RandomKey") == SHA1_SIZE)
{
PackGetData(p, "RandomKey", f->RandomKey);
}
f->SystemId = PackGetInt64(p, "SystemId");
// Apply the traffic difference information
num = PackGetIndexCount(p, "TdType");
for (i = 0;i < num;i++)
{
TRAFFIC traffic;
UINT type;
HUB *h;
char name[MAX_SIZE];
char hubname[MAX_SIZE];
type = PackGetIntEx(p, "TdType", i);
PackGetStrEx(p, "TdName", name, sizeof(name), i);
PackGetStrEx(p, "TdHubName", hubname, sizeof(hubname), i);
InRpcTrafficEx(&traffic, p, i);
LockList(c->HubList);
{
h = GetHub(c, hubname);
if (h != NULL)
{
if (type == TRAFFIC_DIFF_HUB)
{
Lock(h->TrafficLock);
{
AddTraffic(h->Traffic, &traffic);
}
Unlock(h->TrafficLock);
}
else
{
AcLock(h);
{
USER *u = AcGetUser(h, name);
if (u != NULL)
{
Lock(u->lock);
{
AddTraffic(u->Traffic, &traffic);
}
Unlock(u->lock);
if (u->Group != NULL)
{
Lock(u->Group->lock);
{
AddTraffic(u->Group->Traffic, &traffic);
}
Unlock(u->Group->lock);
}
ReleaseUser(u);
}
}
AcUnlock(h);
}
ReleaseHub(h);
}
UnlockList(c->HubList);
}
}
FreePack(p);
}
for (i = 0;i < LIST_NUM(o);i++)
{
HUB *h = LIST_DATA(o, i);
SiCallDeleteHub(s, f, h);
Debug("Delete HUB: %s\n", h->Name);
ReleaseHub(h);
}
ReleaseList(o);
}
}
// Send a session information directive
bool SiCallGetSessionStatus(SERVER *s, FARM_MEMBER *f, RPC_SESSION_STATUS *t)
{
PACK *p;
// Validate arguments
if (s == NULL || f == NULL)
{
return false;
}
p = NewPack();
OutRpcSessionStatus(p, t);
FreeRpcSessionStatus(t);
Zero(t, sizeof(RPC_SESSION_STATUS));
p = SiCallTask(f, p, "getsessionstatus");
if (p == NULL)
{
return false;
}
InRpcSessionStatus(t, p);
FreePack(p);
return true;
}
// Log file reading directive
bool SiCallReadLogFile(SERVER *s, FARM_MEMBER *f, RPC_READ_LOG_FILE *t)
{
PACK *p;
// Validate arguments
if (s == NULL || f == NULL)
{
return false;
}
p = NewPack();
OutRpcReadLogFile(p, t);
FreeRpcReadLogFile(t);
Zero(t, sizeof(RPC_READ_LOG_FILE));
p = SiCallTask(f, p, "readlogfile");
if (p == NULL)
{
return false;
}
InRpcReadLogFile(t, p);
FreePack(p);
return true;
}
// Log file enumeration directive
bool SiCallEnumLogFileList(SERVER *s, FARM_MEMBER *f, RPC_ENUM_LOG_FILE *t, char *hubname)
{
PACK *p;
// Validate arguments
if (s == NULL || f == NULL)
{
return false;
}
p = NewPack();
OutRpcEnumLogFile(p, t);
FreeRpcEnumLogFile(t);
Zero(t, sizeof(RPC_ENUM_LOG_FILE));
PackAddStr(p, "HubName", hubname);
p = SiCallTask(f, p, "enumlogfilelist");
if (p == NULL)
{
return false;
}
InRpcEnumLogFile(t, p);
FreePack(p);
return true;
}
// HUB delete directive
void SiCallDeleteHub(SERVER *s, FARM_MEMBER *f, HUB *h)
{
PACK *p;
UINT i;
// Validate arguments
if (s == NULL || f == NULL)
{
return;
}
if (f->Me == false)
{
p = NewPack();
PackAddStr(p, "HubName", h->Name);
p = SiCallTask(f, p, "deletehub");
FreePack(p);
}
LockList(f->HubList);
{
for (i = 0;i < LIST_NUM(f->HubList);i++)
{
HUB_LIST *hh = LIST_DATA(f->HubList, i);
if (StrCmpi(hh->Name, h->Name) == 0)
{
Free(hh);
Delete(f->HubList, hh);
}
}
}
UnlockList(f->HubList);
}
// Submit a HUB update directive
void SiCallUpdateHub(SERVER *s, FARM_MEMBER *f, HUB *h)
{
PACK *p;
// Validate arguments
if (s == NULL || f == NULL)
{
return;
}
if (f->Me == false)
{
p = NewPack();
SiPackAddCreateHub(p, h);
p = SiCallTask(f, p, "updatehub");
FreePack(p);
}
}
// Send a ticket creation directive
void SiCallCreateTicket(SERVER *s, FARM_MEMBER *f, char *hubname, char *username, char *realusername, POLICY *policy, UCHAR *ticket, UINT counter, char *groupname)
{
PACK *p;
char name[MAX_SESSION_NAME_LEN + 1];
char hub_name_upper[MAX_SIZE];
char user_name_upper[MAX_USERNAME_LEN + 1];
char ticket_str[MAX_SIZE];
UINT point;
// Validate arguments
if (s == NULL || f == NULL || realusername == NULL || hubname == NULL || username == NULL || policy == NULL || ticket == NULL)
{
return;
}
if (groupname == NULL)
{
groupname = "";
}
p = NewPack();
PackAddStr(p, "HubName", hubname);
PackAddStr(p, "UserName", username);
PackAddStr(p, "groupname", groupname);
PackAddStr(p, "RealUserName", realusername);
OutRpcPolicy(p, policy);
PackAddData(p, "Ticket", ticket, SHA1_SIZE);
BinToStr(ticket_str, sizeof(ticket_str), ticket, SHA1_SIZE);
StrCpy(hub_name_upper, sizeof(hub_name_upper), hubname);
StrUpper(hub_name_upper);
StrCpy(user_name_upper, sizeof(user_name_upper), username);
StrUpper(user_name_upper);
Format(name, sizeof(name), "SID-%s-%u", user_name_upper,
counter);
PackAddStr(p, "SessionName", name);
p = SiCallTask(f, p, "createticket");
SLog(s->Cedar, "LS_TICKET_1", f->hostname, hubname, username, realusername, name, ticket_str);
point = PackGetInt(p, "Point");
if (point != 0)
{
f->Point = point;
f->NumSessions++;
}
FreePack(p);
}
// Send a MAC address deletion directive
void SiCallDeleteMacTable(SERVER *s, FARM_MEMBER *f, char *hubname, UINT key)
{
PACK *p;
// Validate arguments
if (s == NULL || f == NULL || hubname == NULL)
{
return;
}
p = NewPack();
PackAddStr(p, "HubName", hubname);
PackAddInt(p, "Key", key);
p = SiCallTask(f, p, "deletemactable");
FreePack(p);
}
// Send an IP address delete directive
void SiCallDeleteIpTable(SERVER *s, FARM_MEMBER *f, char *hubname, UINT key)
{
PACK *p;
// Validate arguments
if (s == NULL || f == NULL || hubname == NULL)
{
return;
}
p = NewPack();
PackAddStr(p, "HubName", hubname);
PackAddInt(p, "Key", key);
p = SiCallTask(f, p, "deleteiptable");
FreePack(p);
}
// Send a session deletion directive
void SiCallDeleteSession(SERVER *s, FARM_MEMBER *f, char *hubname, char *session_name)
{
PACK *p;
// Validate arguments
if (s == NULL || f == NULL || hubname == NULL || session_name == NULL)
{
return;
}
p = NewPack();
PackAddStr(p, "HubName", hubname);
PackAddStr(p, "SessionName", session_name);
p = SiCallTask(f, p, "deletesession");
FreePack(p);
}
// Send an IP table enumeration directive
void SiCallEnumIpTable(SERVER *s, FARM_MEMBER *f, char *hubname, RPC_ENUM_IP_TABLE *t)
{
PACK *p;
UINT i;
// Validate arguments
if (s == NULL || f == NULL || hubname == NULL || t == NULL)
{
return;
}
p = NewPack();
PackAddStr(p, "HubName", hubname);
p = SiCallTask(f, p, "enumiptable");
Zero(t, sizeof(RPC_ENUM_IP_TABLE));
InRpcEnumIpTable(t, p);
for (i = 0;i < t->NumIpTable;i++)
{
t->IpTables[i].RemoteItem = true;
StrCpy(t->IpTables[i].RemoteHostname, sizeof(t->IpTables[i].RemoteHostname),
f->hostname);
}
FreePack(p);
}
// Submit a MAC table enumeration directive
void SiCallEnumMacTable(SERVER *s, FARM_MEMBER *f, char *hubname, RPC_ENUM_MAC_TABLE *t)
{
PACK *p;
UINT i;
// Validate arguments
if (s == NULL || f == NULL || hubname == NULL || t == NULL)
{
return;
}
p = NewPack();
PackAddStr(p, "HubName", hubname);
p = SiCallTask(f, p, "enummactable");
Zero(t, sizeof(RPC_ENUM_MAC_TABLE));
InRpcEnumMacTable(t, p);
for (i = 0;i < t->NumMacTable;i++)
{
t->MacTables[i].RemoteItem = true;
StrCpy(t->MacTables[i].RemoteHostname, sizeof(t->MacTables[i].RemoteHostname),
f->hostname);
}
FreePack(p);
}
// Send a SecureNAT status acquisition directive
void SiCallGetNatStatus(SERVER *s, FARM_MEMBER *f, char *hubname, RPC_NAT_STATUS *t)
{
PACK *p;
// Validate arguments
if (s == NULL || f == NULL || hubname == NULL || t == NULL)
{
return;
}
p = NewPack();
PackAddStr(p, "HubName", hubname);
p = SiCallTask(f, p, "getnatstatus");
Zero(t, sizeof(RPC_NAT_STATUS));
InRpcNatStatus(t, p);
FreePack(p);
}
// Submit a DHCP entry enumeration directive
void SiCallEnumDhcp(SERVER *s, FARM_MEMBER *f, char *hubname, RPC_ENUM_DHCP *t)
{
PACK *p;
// Validate arguments
if (s == NULL || f == NULL || hubname == NULL || t == NULL)
{
return;
}
p = NewPack();
PackAddStr(p, "HubName", hubname);
p = SiCallTask(f, p, "enumdhcp");
Zero(t, sizeof(RPC_ENUM_DHCP));
InRpcEnumDhcp(t, p);
FreePack(p);
}
// Submit a NAT entry enumeration directive
void SiCallEnumNat(SERVER *s, FARM_MEMBER *f, char *hubname, RPC_ENUM_NAT *t)
{
PACK *p;
// Validate arguments
if (s == NULL || f == NULL || hubname == NULL || t == NULL)
{
return;
}
p = NewPack();
PackAddStr(p, "HubName", hubname);
p = SiCallTask(f, p, "enumnat");
Zero(t, sizeof(RPC_ENUM_NAT));
InRpcEnumNat(t, p);
FreePack(p);
}
// Send a session enumeration directive
void SiCallEnumSession(SERVER *s, FARM_MEMBER *f, char *hubname, RPC_ENUM_SESSION *t)
{
PACK *p;
UINT i;
// Validate arguments
if (s == NULL || f == NULL || hubname == NULL || t == NULL)
{
return;
}
p = NewPack();
PackAddStr(p, "HubName", hubname);
p = SiCallTask(f, p, "enumsession");
Zero(t, sizeof(RPC_ENUM_SESSION));
InRpcEnumSession(t, p);
for (i = 0;i < t->NumSession;i++)
{
t->Sessions[i].RemoteSession = true;
StrCpy(t->Sessions[i].RemoteHostname, sizeof(t->Sessions[i].RemoteHostname),
f->hostname);
}
FreePack(p);
}
// Send a HUB creation directive
void SiCallCreateHub(SERVER *s, FARM_MEMBER *f, HUB *h)
{
PACK *p;
HUB_LIST *hh;
// Validate arguments
if (s == NULL || f == NULL)
{
return;
}
if (f->Me == false)
{
p = NewPack();
SiPackAddCreateHub(p, h);
p = SiCallTask(f, p, "createhub");
FreePack(p);
}
hh = ZeroMalloc(sizeof(HUB_LIST));
hh->DynamicHub = (h->Type == HUB_TYPE_FARM_DYNAMIC ? true : false);
StrCpy(hh->Name, sizeof(hh->Name), h->Name);
hh->FarmMember = f;
LockList(f->HubList);
{
bool exists = false;
UINT i;
for (i = 0;i < LIST_NUM(f->HubList);i++)
{
HUB_LIST *t = LIST_DATA(f->HubList, i);
if (StrCmpi(t->Name, hh->Name) == 0)
{
exists = true;
}
}
if (exists == false)
{
Add(f->HubList, hh);
}
else
{
Free(hh);
}
}
UnlockList(f->HubList);
}
// Write the PACK for creating HUB
void SiPackAddCreateHub(PACK *p, HUB *h)
{
UINT i;
UINT max_session;
SERVER *s;
// Validate arguments
if (p == NULL || h == NULL)
{
return;
}
s = h->Cedar->Server;
if (s != NULL)
{
}
PackAddStr(p, "HubName", h->Name);
PackAddInt(p, "HubType", h->Type);
max_session = h->Option->MaxSession;
if (GetHubAdminOption(h, "max_sessions") != 0)
{
if (max_session == 0)
{
max_session = GetHubAdminOption(h, "max_sessions");
}
else
{
UINT r = GetHubAdminOption(h, "max_sessions");
max_session = MIN(max_session, r);
}
}
PackAddInt(p, "MaxSession", max_session);
if (GetHubAdminOption(h, "max_sessions_client_bridge_apply") != 0
)
{
PackAddInt(p, "MaxSessionClient", GetHubAdminOption(h, "max_sessions_client"));
PackAddInt(p, "MaxSessionBridge", GetHubAdminOption(h, "max_sessions_bridge"));
PackAddBool(p, "MaxSessionClientBridgeApply", true);
}
else
{
PackAddInt(p, "MaxSessionClient", INFINITE);
PackAddInt(p, "MaxSessionBridge", INFINITE);
}
PackAddBool(p, "NoArpPolling", h->Option->NoArpPolling);
PackAddBool(p, "NoIPv6AddrPolling", h->Option->NoIPv6AddrPolling);
PackAddBool(p, "NoIpTable", h->Option->NoIpTable);
PackAddBool(p, "NoEnum", h->Option->NoEnum);
PackAddBool(p, "FilterPPPoE", h->Option->FilterPPPoE);
PackAddBool(p, "YieldAfterStorePacket", h->Option->YieldAfterStorePacket);
PackAddBool(p, "NoSpinLockForPacketDelay", h->Option->NoSpinLockForPacketDelay);
PackAddInt(p, "BroadcastStormDetectionThreshold", h->Option->BroadcastStormDetectionThreshold);
PackAddInt(p, "MaxLoggedPacketsPerMinute", h->Option->MaxLoggedPacketsPerMinute);
PackAddInt(p, "FloodingSendQueueBufferQuota", h->Option->FloodingSendQueueBufferQuota);
PackAddBool(p, "DoNotSaveHeavySecurityLogs", h->Option->DoNotSaveHeavySecurityLogs);
PackAddBool(p, "DropBroadcastsInPrivacyFilterMode", h->Option->DropBroadcastsInPrivacyFilterMode);
PackAddBool(p, "DropArpInPrivacyFilterMode", h->Option->DropArpInPrivacyFilterMode);
PackAddBool(p, "AllowSameUserInPrivacyFilterMode", h->Option->AllowSameUserInPrivacyFilterMode);
PackAddBool(p, "SuppressClientUpdateNotification", h->Option->SuppressClientUpdateNotification);
PackAddBool(p, "AssignVLanIdByRadiusAttribute", h->Option->AssignVLanIdByRadiusAttribute);
PackAddBool(p, "DenyAllRadiusLoginWithNoVlanAssign", h->Option->DenyAllRadiusLoginWithNoVlanAssign);
PackAddInt(p, "ClientMinimumRequiredBuild", h->Option->ClientMinimumRequiredBuild);
PackAddBool(p, "SecureNAT_RandomizeAssignIp", h->Option->SecureNAT_RandomizeAssignIp);
PackAddBool(p, "NoPhysicalIPOnPacketLog", h->Option->NoPhysicalIPOnPacketLog);
PackAddInt(p, "DetectDormantSessionInterval", h->Option->DetectDormantSessionInterval);
PackAddBool(p, "FixForDLinkBPDU", h->Option->FixForDLinkBPDU);
PackAddBool(p, "BroadcastLimiterStrictMode", h->Option->BroadcastLimiterStrictMode);
PackAddBool(p, "NoLookBPDUBridgeId", h->Option->NoLookBPDUBridgeId);
PackAddBool(p, "NoManageVlanId", h->Option->NoManageVlanId);
PackAddInt(p, "VlanTypeId", h->Option->VlanTypeId);
PackAddBool(p, "FilterOSPF", h->Option->FilterOSPF);
PackAddBool(p, "FilterIPv4", h->Option->FilterIPv4);
PackAddBool(p, "FilterIPv6", h->Option->FilterIPv6);
PackAddBool(p, "FilterNonIP", h->Option->FilterNonIP);
PackAddBool(p, "NoIPv4PacketLog", h->Option->NoIPv4PacketLog);
PackAddBool(p, "NoIPv6PacketLog", h->Option->NoIPv6PacketLog);
PackAddBool(p, "FilterBPDU", h->Option->FilterBPDU);
PackAddBool(p, "NoIPv6DefaultRouterInRAWhenIPv6", h->Option->NoIPv6DefaultRouterInRAWhenIPv6);
PackAddBool(p, "NoMacAddressLog", h->Option->NoMacAddressLog);
PackAddBool(p, "ManageOnlyPrivateIP", h->Option->ManageOnlyPrivateIP);
PackAddBool(p, "ManageOnlyLocalUnicastIPv6", h->Option->ManageOnlyLocalUnicastIPv6);
PackAddBool(p, "DisableIPParsing", h->Option->DisableIPParsing);
PackAddInt(p, "AdjustTcpMssValue", h->Option->AdjustTcpMssValue);
PackAddBool(p, "DisableAdjustTcpMss", h->Option->DisableAdjustTcpMss);
PackAddBool(p, "NoDhcpPacketLogOutsideHub", h->Option->NoDhcpPacketLogOutsideHub);
PackAddBool(p, "DisableHttpParsing", h->Option->DisableHttpParsing);
PackAddBool(p, "DisableUdpAcceleration", h->Option->DisableUdpAcceleration);
PackAddBool(p, "DisableUdpFilterForLocalBridgeNic", h->Option->DisableUdpFilterForLocalBridgeNic);
PackAddBool(p, "ApplyIPv4AccessListOnArpPacket", h->Option->ApplyIPv4AccessListOnArpPacket);
PackAddBool(p, "RemoveDefGwOnDhcpForLocalhost", h->Option->RemoveDefGwOnDhcpForLocalhost);
PackAddInt(p, "SecureNAT_MaxTcpSessionsPerIp", h->Option->SecureNAT_MaxTcpSessionsPerIp);
PackAddInt(p, "SecureNAT_MaxTcpSynSentPerIp", h->Option->SecureNAT_MaxTcpSynSentPerIp);
PackAddInt(p, "SecureNAT_MaxUdpSessionsPerIp", h->Option->SecureNAT_MaxUdpSessionsPerIp);
PackAddInt(p, "SecureNAT_MaxDnsSessionsPerIp", h->Option->SecureNAT_MaxDnsSessionsPerIp);
PackAddInt(p, "SecureNAT_MaxIcmpSessionsPerIp", h->Option->SecureNAT_MaxIcmpSessionsPerIp);
PackAddInt(p, "AccessListIncludeFileCacheLifetime", h->Option->AccessListIncludeFileCacheLifetime);
PackAddBool(p, "DisableKernelModeSecureNAT", h->Option->DisableKernelModeSecureNAT);
PackAddBool(p, "DisableIpRawModeSecureNAT", h->Option->DisableIpRawModeSecureNAT);
PackAddBool(p, "DisableUserModeSecureNAT", h->Option->DisableUserModeSecureNAT);
PackAddBool(p, "DisableCheckMacOnLocalBridge", h->Option->DisableCheckMacOnLocalBridge);
PackAddBool(p, "DisableCorrectIpOffloadChecksum", h->Option->DisableCorrectIpOffloadChecksum);
PackAddInt(p, "SavePacketLog", h->LogSetting.SavePacketLog);
PackAddInt(p, "PacketLogSwitchType", h->LogSetting.PacketLogSwitchType);
for (i = 0;i < NUM_PACKET_LOG;i++)
{
PackAddIntEx(p, "PacketLogConfig", h->LogSetting.PacketLogConfig[i], i, NUM_PACKET_LOG);
}
PackAddInt(p, "SaveSecurityLog", h->LogSetting.SaveSecurityLog);
PackAddInt(p, "SecurityLogSwitchType", h->LogSetting.SecurityLogSwitchType);
PackAddData(p, "HashedPassword", h->HashedPassword, SHA1_SIZE);
PackAddData(p, "SecurePassword", h->SecurePassword, SHA1_SIZE);
PackAddBool(p, "UseHubNameAsDhcpUserClassOption", h->Option->UseHubNameAsDhcpUserClassOption);
PackAddBool(p, "UseHubNameAsRadiusNasId", h->Option->UseHubNameAsRadiusNasId);
PackAddBool(p, "AllowEapMatchUserByCert", h->Option->AllowEapMatchUserByCert);
SiAccessListToPack(p, h->AccessList);
if (h->EnableSecureNAT)
{
PackAddBool(p, "EnableSecureNAT", h->EnableSecureNAT);
OutVhOption(p, h->SecureNATOption);
}
}
// Setting of the HUB has been updated
void SiHubUpdateProc(HUB *h)
{
SERVER *s;
UINT i;
// Validate arguments
if (h == NULL || h->Cedar == NULL || h->Cedar->Server == NULL || h->Cedar->Server->ServerType != SERVER_TYPE_FARM_CONTROLLER)
{
return;
}
s = h->Cedar->Server;
if (s->FarmMemberList == NULL)
{
return;
}
if (h->LastVersion != h->CurrentVersion || h->CurrentVersion == 0)
{
LIST *fm_list;
if (h->CurrentVersion == 0)
{
h->CurrentVersion = 1;
}
h->LastVersion = h->CurrentVersion;
Debug("SiHubUpdateProc HUB=%s, Ver=%u, Type=%u, Offline=%u\n", h->Name, h->CurrentVersion,
h->Type, h->Offline);
fm_list = NewListFast(NULL);
LockList(s->FarmMemberList);
{
while (true)
{
bool escape = true;
// Update the HUB on all members
for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
{
FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
if (IsInList(fm_list, f) == false)
{
Add(fm_list, f);
escape = false;
if (f->Me == false)
{
SiCallUpdateHub(s, f, h);
}
break;
}
}
if (escape)
{
break;
}
UnlockList(s->FarmMemberList);
LockList(s->FarmMemberList);
}
}
UnlockList(s->FarmMemberList);
ReleaseList(fm_list);
}
if (h->Offline == false)
{
SiHubOnlineProc(h);
}
}
// HUB turns to online
void SiHubOnlineProc(HUB *h)
{
SERVER *s;
UINT i;
// Validate arguments
if (h == NULL || h->Cedar->Server == NULL || h->Cedar->Server->ServerType != SERVER_TYPE_FARM_CONTROLLER)
{
// Process only on the farm controller
return;
}
s = h->Cedar->Server;
if (s->FarmMemberList == NULL)
{
return;
}
LockList(s->FarmMemberList);
{
if (h->Type == HUB_TYPE_FARM_STATIC)
{
// Static HUB
// Create the HUB on all members
for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
{
UINT j;
bool exists = false;
FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
LockList(f->HubList);
{
for (j = 0;j < LIST_NUM(f->HubList);j++)
{
HUB_LIST *hh = LIST_DATA(f->HubList, j);
if (StrCmpi(hh->Name, h->Name) == 0)
{
exists = true;
}
}
}
UnlockList(f->HubList);
if (exists == false)
{
SiCallCreateHub(s, f, h);
}
}
}
}
UnlockList(s->FarmMemberList);
}
// HUB turns to offline
void SiHubOfflineProc(HUB *h)
{
SERVER *s;
char hubname[MAX_HUBNAME_LEN + 1];
UINT i;
LIST *fm_list;
// Validate arguments
if (h == NULL || h->Cedar->Server == NULL || h->Cedar->Server->ServerType != SERVER_TYPE_FARM_CONTROLLER)
{
// Process only on the farm controller
return;
}
s = h->Cedar->Server;
if (s->FarmMemberList == NULL)
{
return;
}
StrCpy(hubname, sizeof(hubname), h->Name);
fm_list = NewListFast(NULL);
LockList(s->FarmMemberList);
{
while (true)
{
bool escape = true;
// Stop the HUB on all members
for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
{
FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
if (IsInList(fm_list, f) == false)
{
Add(fm_list, f);
escape = false;
SiCallDeleteHub(s, f, h);
break;
}
}
if (escape)
{
break;
}
UnlockList(s->FarmMemberList);
LockList(s->FarmMemberList);
}
}
UnlockList(s->FarmMemberList);
ReleaseList(fm_list);
}
// Convert an access to PACK
void SiAccessToPack(PACK *p, ACCESS *a, UINT i, UINT total)
{
// Validate arguments
if (p == NULL || a == NULL)
{
return;
}
PackAddUniStrEx(p, "Note", a->Note, i, total);
PackAddIntEx(p, "Active", a->Active, i, total);
PackAddIntEx(p, "Priority", a->Priority, i, total);
PackAddIntEx(p, "Discard", a->Discard, i, total);
if (a->IsIPv6)
{
PackAddIp32Ex(p, "SrcIpAddress", 0xFDFFFFDF, i, total);
PackAddIp32Ex(p, "SrcSubnetMask", 0xFFFFFFFF, i, total);
PackAddIp32Ex(p, "DestIpAddress", 0xFDFFFFDF, i, total);
PackAddIp32Ex(p, "DestSubnetMask", 0xFFFFFFFF, i, total);
}
else
{
PackAddIp32Ex(p, "SrcIpAddress", a->SrcIpAddress, i, total);
PackAddIp32Ex(p, "SrcSubnetMask", a->SrcSubnetMask, i, total);
PackAddIp32Ex(p, "DestIpAddress", a->DestIpAddress, i, total);
PackAddIp32Ex(p, "DestSubnetMask", a->DestSubnetMask, i, total);
}
PackAddIntEx(p, "Protocol", a->Protocol, i, total);
PackAddIntEx(p, "SrcPortStart", a->SrcPortStart, i, total);
PackAddIntEx(p, "SrcPortEnd", a->SrcPortEnd, i, total);
PackAddIntEx(p, "DestPortStart", a->DestPortStart, i, total);
PackAddIntEx(p, "DestPortEnd", a->DestPortEnd, i, total);
PackAddStrEx(p, "SrcUsername", a->SrcUsername, i, total);
PackAddStrEx(p, "DestUsername", a->DestUsername, i, total);
PackAddBoolEx(p, "CheckSrcMac", a->CheckSrcMac, i, total);
PackAddDataEx(p, "SrcMacAddress", a->SrcMacAddress, sizeof(a->SrcMacAddress), i, total);
PackAddDataEx(p, "SrcMacMask", a->SrcMacMask, sizeof(a->SrcMacMask), i, total);
PackAddBoolEx(p, "CheckDstMac", a->CheckDstMac, i, total);
PackAddDataEx(p, "DstMacAddress", a->DstMacAddress, sizeof(a->DstMacAddress), i, total);
PackAddDataEx(p, "DstMacMask", a->DstMacMask, sizeof(a->DstMacMask), i, total);
PackAddBoolEx(p, "CheckTcpState", a->CheckTcpState, i, total);
PackAddBoolEx(p, "Established", a->Established, i, total);
PackAddIntEx(p, "Delay", a->Delay, i, total);
PackAddIntEx(p, "Jitter", a->Jitter, i, total);
PackAddIntEx(p, "Loss", a->Loss, i, total);
PackAddStrEx(p, "RedirectUrl", a->RedirectUrl, i, total);
PackAddBoolEx(p, "IsIPv6", a->IsIPv6, i, total);
if (a->IsIPv6)
{
PackAddIp6AddrEx(p, "SrcIpAddress6", &a->SrcIpAddress6, i, total);
PackAddIp6AddrEx(p, "SrcSubnetMask6", &a->SrcSubnetMask6, i, total);
PackAddIp6AddrEx(p, "DestIpAddress6", &a->DestIpAddress6, i, total);
PackAddIp6AddrEx(p, "DestSubnetMask6", &a->DestSubnetMask6, i, total);
}
else
{
IPV6_ADDR zero;
Zero(&zero, sizeof(zero));
PackAddIp6AddrEx(p, "SrcIpAddress6", &zero, i, total);
PackAddIp6AddrEx(p, "SrcSubnetMask6", &zero, i, total);
PackAddIp6AddrEx(p, "DestIpAddress6", &zero, i, total);
PackAddIp6AddrEx(p, "DestSubnetMask6", &zero, i, total);
}
}
// Get number of access contained in the PACK
UINT SiNumAccessFromPack(PACK *p)
{
// Validate arguments
if (p == NULL)
{
return 0;
}
return PackGetIndexCount(p, "Active");
}
// Convert the PACK to access
ACCESS *SiPackToAccess(PACK *p, UINT i)
{
ACCESS *a;
// Validate arguments
if (p == NULL)
{
return NULL;
}
a = ZeroMalloc(sizeof(ACCESS));
PackGetUniStrEx(p, "Note", a->Note, sizeof(a->Note), i);
a->Active = PackGetIntEx(p, "Active", i);
a->Priority = PackGetIntEx(p, "Priority", i);
a->Discard = PackGetIntEx(p, "Discard", i);
a->SrcIpAddress = PackGetIp32Ex(p, "SrcIpAddress", i);
a->SrcSubnetMask = PackGetIp32Ex(p, "SrcSubnetMask", i);
a->DestIpAddress = PackGetIp32Ex(p, "DestIpAddress", i);
a->DestSubnetMask = PackGetIp32Ex(p, "DestSubnetMask", i);
a->Protocol = PackGetIntEx(p, "Protocol", i);
a->SrcPortStart = PackGetIntEx(p, "SrcPortStart", i);
a->SrcPortEnd = PackGetIntEx(p, "SrcPortEnd", i);
a->DestPortStart = PackGetIntEx(p, "DestPortStart", i);
a->DestPortEnd = PackGetIntEx(p, "DestPortEnd", i);
PackGetStrEx(p, "SrcUsername", a->SrcUsername, sizeof(a->SrcUsername), i);
PackGetStrEx(p, "DestUsername", a->DestUsername, sizeof(a->DestUsername), i);
a->CheckSrcMac = PackGetBoolEx(p, "CheckSrcMac", i);
PackGetDataEx2(p, "SrcMacAddress", a->SrcMacAddress, sizeof(a->SrcMacAddress), i);
PackGetDataEx2(p, "SrcMacMask", a->SrcMacMask, sizeof(a->SrcMacMask), i);
a->CheckDstMac = PackGetBoolEx(p, "CheckDstMac", i);
PackGetDataEx2(p, "DstMacAddress", a->DstMacAddress, sizeof(a->DstMacAddress), i);
PackGetDataEx2(p, "DstMacMask", a->DstMacMask, sizeof(a->DstMacMask), i);
a->CheckTcpState = PackGetBoolEx(p, "CheckTcpState", i);
a->Established = PackGetBoolEx(p, "Established", i);
a->Delay = PackGetIntEx(p, "Delay", i);
a->Jitter = PackGetIntEx(p, "Jitter", i);
a->Loss = PackGetIntEx(p, "Loss", i);
a->IsIPv6 = PackGetBoolEx(p, "IsIPv6", i);
PackGetStrEx(p, "RedirectUrl", a->RedirectUrl, sizeof(a->RedirectUrl), i);
if (a->IsIPv6)
{
PackGetIp6AddrEx(p, "SrcIpAddress6", &a->SrcIpAddress6, i);
PackGetIp6AddrEx(p, "SrcSubnetMask6", &a->SrcSubnetMask6, i);
PackGetIp6AddrEx(p, "DestIpAddress6", &a->DestIpAddress6, i);
PackGetIp6AddrEx(p, "DestSubnetMask6", &a->DestSubnetMask6, i);
}
return a;
}
// Convert the PACK to an access list
void SiAccessListToPack(PACK *p, LIST *o)
{
// Validate arguments
if (p == NULL || o == NULL)
{
return;
}
LockList(o);
{
UINT i;
for (i = 0;i < LIST_NUM(o);i++)
{
ACCESS *a = LIST_DATA(o, i);
SiAccessToPack(p, a, i, LIST_NUM(o));
}
}
UnlockList(o);
}
// Get the member that is hosting the specified HUB
FARM_MEMBER *SiGetHubHostingMember(SERVER *s, HUB *h, bool admin_mode, CONNECTION *c)
{
FARM_MEMBER *ret = NULL;
char name[MAX_SIZE];
UINT i;
// Validate arguments
if (s == NULL || h == NULL || c == NULL)
{
return NULL;
}
StrCpy(name, sizeof(name), h->Name);
if (h->Type == HUB_TYPE_FARM_STATIC)
{
// It is good to select any member in the case of static HUB
if (admin_mode == false)
{
ret = SiGetNextFarmMember(s, c, h);
}
else
{
UINT i;
ret = NULL;
for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
{
FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
if (f->Me)
{
ret = f;
break;
}
}
}
}
else
{
// Examine whether there is a member that is hosting the HUB already in the case of dynamic HUB
for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
{
FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
HUB_LIST *hh, t;
StrCpy(t.Name, sizeof(t.Name), name);
LockList(f->HubList);
{
hh = Search(f->HubList, &t);
if (hh != NULL)
{
// Found
ret = f;
}
}
UnlockList(f->HubList);
}
if (ret == NULL)
{
// Let host the new HUB
FARM_MEMBER *f;
// Select the member to host
ret = SiGetNextFarmMember(s, c, h);
f = ret;
if (f != NULL)
{
// HUB creation directive
SiAddHubCreateHistory(s, name);
SiCallCreateHub(s, f, h);
SiCallUpdateHub(s, f, h);
}
}
}
return ret;
}
// Task is called
PACK *SiCalledTask(FARM_CONTROLLER *f, PACK *p, char *taskname)
{
PACK *ret;
SERVER *s;
// Validate arguments
if (f == NULL || p == NULL || taskname == NULL)
{
return NULL;
}
ret = NULL;
s = f->Server;
if (StrCmpi(taskname, "noop") == 0)
{
// NO OPERATION
ret = NewPack();
}
else
{
Debug("Task Called: [%s].\n", taskname);
if (StrCmpi(taskname, "createhub") == 0)
{
SiCalledCreateHub(s, p);
ret = NewPack();
}
else if (StrCmpi(taskname, "deletehub") == 0)
{
SiCalledDeleteHub(s, p);
ret = NewPack();
}
else if (StrCmpi(taskname, "enumhub") == 0)
{
ret = NewPack();
SiCalledEnumHub(s, ret, p);
}
else if (StrCmpi(taskname, "updatehub") == 0)
{
SiCalledUpdateHub(s, p);
ret = NewPack();
}
else if (StrCmpi(taskname, "createticket") == 0)
{
ret = SiCalledCreateTicket(s, p);
}
else if (StrCmpi(taskname, "enumnat") == 0)
{
ret = SiCalledEnumNat(s, p);
}
else if (StrCmpi(taskname, "enumdhcp") == 0)
{
ret = SiCalledEnumDhcp(s, p);
}
else if (StrCmpi(taskname, "getnatstatus") == 0)
{
ret = SiCalledGetNatStatus(s, p);
}
else if (StrCmpi(taskname, "enumsession") == 0)
{
ret = SiCalledEnumSession(s, p);
}
else if (StrCmpi(taskname, "deletesession") == 0)
{
SiCalledDeleteSession(s, p);
ret = NewPack();
}
else if (StrCmpi(taskname, "deletemactable") == 0)
{
SiCalledDeleteMacTable(s, p);
ret = NewPack();
}
else if (StrCmpi(taskname, "deleteiptable") == 0)
{
SiCalledDeleteIpTable(s, p);
ret = NewPack();
}
else if (StrCmpi(taskname, "enummactable") == 0)
{
ret = SiCalledEnumMacTable(s, p);
}
else if (StrCmpi(taskname, "enumiptable") == 0)
{
ret = SiCalledEnumIpTable(s, p);
}
else if (StrCmpi(taskname, "getsessionstatus") == 0)
{
ret = SiCalledGetSessionStatus(s, p);
}
else if (StrCmpi(taskname, "enumlogfilelist") == 0)
{
ret = SiCalledEnumLogFileList(s, p);
}
else if (StrCmpi(taskname, "readlogfile") == 0)
{
ret = SiCalledReadLogFile(s, p);
}
}
return ret;
}
// Call the task
PACK *SiCallTask(FARM_MEMBER *f, PACK *p, char *taskname)
{
PACK *ret;
char tmp[MAX_PATH];
// Validate arguments
if (f == NULL || p == NULL || taskname == NULL)
{
return NULL;
}
PackAddStr(p, "taskname", taskname);
Debug("Call Task [%s] (%s)\n", taskname, f->hostname);
Format(tmp, sizeof(tmp), "CLUSTER_CALL: Entering Call [%s] to %s", taskname, f->hostname);
SiDebugLog(f->Cedar->Server, tmp);
ret = SiExecTask(f, p);
Format(tmp, sizeof(tmp), "CLUSTER_CALL: Leaving Call [%s] to %s", taskname, f->hostname);
SiDebugLog(f->Cedar->Server, tmp);
return ret;
}
// Task listening procedure (Main Process)
void SiAcceptTasksFromControllerMain(FARM_CONTROLLER *f, SOCK *sock)
{
PACK *request;
PACK *response;
char taskname[MAX_SIZE];
// Validate arguments
if (f == NULL || sock == NULL)
{
return;
}
f->IsConnected = true;
while (true)
{
bool ret;
// Receive the PACK
request = HttpClientRecv(sock);
if (request == NULL)
{
// Disconnect
break;
}
response = NULL;
// Get the name
if (PackGetStr(request, "taskname", taskname, sizeof(taskname)))
{
Lock(f->Server->TasksFromFarmControllerLock);
{
response = SiCalledTask(f, request, taskname);
}
Unlock(f->Server->TasksFromFarmControllerLock);
}
FreePack(request);
// Return a response
if (response == NULL)
{
response = NewPack();
}
else
{
PackAddInt(response, "succeed", 1);
}
ret = HttpClientSend(sock, response);
FreePack(response);
if (ret == false)
{
// Disconnect
break;
}
}
f->IsConnected = false;
}
// Task waiting procedure
void SiAcceptTasksFromController(FARM_CONTROLLER *f, SOCK *sock)
{
UINT i;
HUB **hubs;
UINT num_hubs;
CEDAR *c;
SERVER *s;
// Validate arguments
if (f == NULL || sock == NULL)
{
return;
}
s = f->Server;
c = s->Cedar;
// Main process
SiAcceptTasksFromControllerMain(f, sock);
// Stop all Virtual HUBs since the connection to the controller is disconnected
LockList(c->HubList);
{
hubs = ToArray(c->HubList);
num_hubs = LIST_NUM(c->HubList);
for (i = 0;i < num_hubs;i++)
{
AddRef(hubs[i]->ref);
}
}
UnlockList(c->HubList);
for (i = 0;i < num_hubs;i++)
{
SetHubOffline(hubs[i]);
DelHub(c, hubs[i]);
ReleaseHub(hubs[i]);
}
Free(hubs);
}
// Execute the task
PACK *SiExecTask(FARM_MEMBER *f, PACK *p)
{
FARM_TASK *t;
// Validate arguments
if (f == NULL || p == NULL)
{
return NULL;
}
t = SiFarmServPostTask(f, p);
if (t == NULL)
{
return NULL;
}
return SiFarmServWaitTask(t);
}
// Task queuing
FARM_TASK *SiFarmServPostTask(FARM_MEMBER *f, PACK *request)
{
FARM_TASK *t;
// Validate arguments
if (f == NULL || request == NULL)
{
return NULL;
}
t = ZeroMalloc(sizeof(FARM_TASK));
t->CompleteEvent = NewEvent();
t->Request = request;
LockQueue(f->TaskQueue);
{
if (f->Halting)
{
// Halting (failure)
UnlockQueue(f->TaskQueue);
ReleaseEvent(t->CompleteEvent);
Free(t);
return NULL;
}
InsertQueue(f->TaskQueue, t);
}
UnlockQueue(f->TaskQueue);
Set(f->TaskPostEvent);
return t;
}
// Wait for task results
PACK *SiFarmServWaitTask(FARM_TASK *t)
{
PACK *response;
// Validate arguments
if (t == NULL)
{
return NULL;
}
Wait(t->CompleteEvent, INFINITE);
ReleaseEvent(t->CompleteEvent);
FreePack(t->Request);
response = t->Response;
Free(t);
if (PackGetInt(response, "succeed") == 0)
{
// Task calling fails for any reason
FreePack(response);
return NULL;
}
return response;
}
// Server farm processing main
void SiFarmServMain(SERVER *server, SOCK *sock, FARM_MEMBER *f)
{
UINT wait_time = SERVER_CONTROL_TCP_TIMEOUT / 2;
bool send_noop = false;
UINT i;
CEDAR *c;
// Validate arguments
if (server == NULL || sock == NULL || f == NULL)
{
Debug("SiFarmServMain Failed.\n");
return;
}
Debug("SiFarmServMain Started.\n");
c = server->Cedar;
// Send a directive to create all static HUBs at the stage
// where the members have been connected to the controller
LockList(c->HubList);
{
for (i = 0;i < LIST_NUM(c->HubList);i++)
{
HUB *h = LIST_DATA(c->HubList, i);
if (h->Offline == false)
{
if (h->Type == HUB_TYPE_FARM_STATIC)
{
PACK *p;
HUB_LIST *hh;
p = NewPack();
SiPackAddCreateHub(p, h);
PackAddStr(p, "taskname", "createhub");
HttpServerSend(sock, p);
FreePack(p);
p = HttpServerRecv(sock);
FreePack(p);
p = NewPack();
SiPackAddCreateHub(p, h);
PackAddStr(p, "taskname", "updatehub");
HttpServerSend(sock, p);
FreePack(p);
p = HttpServerRecv(sock);
FreePack(p);
hh = ZeroMalloc(sizeof(HUB_LIST));
hh->DynamicHub = false;
hh->FarmMember = f;
StrCpy(hh->Name, sizeof(hh->Name), h->Name);
LockList(f->HubList);
{
Add(f->HubList, hh);
}
UnlockList(f->HubList);
}
}
}
}
UnlockList(c->HubList);
Debug("SiFarmServMain: while (true)\n");
while (true)
{
FARM_TASK *t;
UINT64 tick;
do
{
// Check whether a new task arrived
LockQueue(f->TaskQueue);
{
t = GetNext(f->TaskQueue);
}
UnlockQueue(f->TaskQueue);
if (t != NULL)
{
// Handle this task
PACK *p = t->Request;
bool ret;
// Transmission
ret = HttpServerSend(sock, p);
send_noop = false;
if (ret == false)
{
// Disconnected
// Cancel this task
Set(t->CompleteEvent);
goto DISCONNECTED;
}
// Receive
p = HttpServerRecvEx(sock, FIRM_SERV_RECV_PACK_MAX_SIZE);
t->Response = p;
Set(t->CompleteEvent);
if (p == NULL)
{
// Avoid infinite loop
Disconnect(sock);
goto DISCONNECTED;
}
}
}
while (t != NULL);
if (send_noop)
{
// Send a NOOP
PACK *p;
bool ret;
p = NewPack();
PackAddStr(p, "taskname", "noop");
ret = HttpServerSend(sock, p);
FreePack(p);
if (ret == false)
{
goto DISCONNECTED;
}
p = HttpServerRecv(sock);
if (p == NULL)
{
goto DISCONNECTED;
}
FreePack(p);
}
tick = Tick64();
while (true)
{
bool break_flag;
if ((tick + wait_time) <= Tick64())
{
break;
}
Wait(f->TaskPostEvent, 250);
break_flag = false;
LockQueue(f->TaskQueue);
{
if (f->TaskQueue->num_item != 0)
{
break_flag = true;
}
}
UnlockQueue(f->TaskQueue);
if (break_flag || f->Halting || server->Halt)
{
break;
}
}
send_noop = true;
}
DISCONNECTED:
Debug("SiFarmServMain: DISCONNECTED\n");
f->Halting = true;
// Cancel all outstanding tasks
LockQueue(f->TaskQueue);
{
FARM_TASK *t;
while (t = GetNext(f->TaskQueue))
{
Set(t->CompleteEvent);
}
}
UnlockQueue(f->TaskQueue);
}
// Farm server function that handles the connection from farm members
void SiFarmServ(SERVER *server, SOCK *sock, X *cert, UINT ip, UINT num_port, UINT *ports, char *hostname, UINT point, UINT weight, UINT max_sessions)
{
PACK *p;
FARM_MEMBER *f;
UINT i;
char tmp[MAX_SIZE];
// Validate arguments
if (server == NULL || sock == NULL || cert == NULL || num_port == 0 || ports == NULL || hostname == NULL)
{
return;
}
if (weight == 0)
{
weight = FARM_DEFAULT_WEIGHT;
}
if (max_sessions == 0)
{
max_sessions = SERVER_MAX_SESSIONS;
}
if (ip == 0)
{
// If the public IP address is not specified, specify the connection
// source IP address of this farm member server
ip = IPToUINT(&sock->RemoteIP);
}
IPToStr32(tmp, sizeof(tmp), ip);
SLog(server->Cedar, "LS_FARM_SERV_START", tmp, hostname);
// Inform the success
p = NewPack();
HttpServerSend(sock, p);
FreePack(p);
IPToStr32(tmp, sizeof(tmp), ip);
Debug("Farm Member %s Connected. IP: %s\n", hostname, tmp);
SetTimeout(sock, SERVER_CONTROL_TCP_TIMEOUT);
f = ZeroMalloc(sizeof(FARM_MEMBER));
f->Cedar = server->Cedar;
f->Ip = ip;
f->NumPort = num_port;
f->Ports = ports;
StrCpy(f->hostname, sizeof(f->hostname), hostname);
f->ServerCert = cert;
f->ConnectedTime = SystemTime64();
f->Weight = weight;
f->MaxSessions = max_sessions;
f->HubList = NewList(CompareHubList);
f->Point = point;
f->TaskQueue = NewQueue();
f->TaskPostEvent = NewEvent();
// Add to the list
LockList(server->FarmMemberList);
{
Add(server->FarmMemberList, f);
}
UnlockList(server->FarmMemberList);
// Main process
SiFarmServMain(server, sock, f);
// Remove from the list
LockList(server->FarmMemberList);
{
Delete(server->FarmMemberList, f);
}
UnlockList(server->FarmMemberList);
ReleaseQueue(f->TaskQueue);
ReleaseEvent(f->TaskPostEvent);
for (i = 0;i < LIST_NUM(f->HubList);i++)
{
HUB_LIST *hh = LIST_DATA(f->HubList, i);
Free(hh);
}
ReleaseList(f->HubList);
Free(f);
SLog(server->Cedar, "LS_FARM_SERV_END", hostname);
}
// Search in HUB list
int CompareHubList(void *p1, void *p2)
{
HUB_LIST *h1, *h2;
if (p1 == NULL || p2 == NULL)
{
return 0;
}
h1 = *(HUB_LIST **)p1;
h2 = *(HUB_LIST **)p2;
if (h1 == NULL || h2 == NULL)
{
return 0;
}
return StrCmpi(h1->Name, h2->Name);
}
// Search in WireGuard key list
int CompareWgk(void *p1, void *p2)
{
WGK *wgk_1, *wgk_2;
if (p1 == NULL || p2 == NULL)
{
return (p1 == NULL && p2 == NULL ? 0 : (p1 == NULL ? -1 : 1));
}
wgk_1 = *(WGK **)p1;
wgk_2 = *(WGK **)p2;
if (wgk_1 == NULL || wgk_2 == NULL)
{
return (wgk_1 == NULL && wgk_2 == NULL ? 0 : (wgk_1 == NULL ? -1 : 1));
}
return StrCmp(wgk_1->Key, wgk_2->Key);
}
// Connection thread to the controller
void SiConnectToControllerThread(THREAD *thread, void *param)
{
FARM_CONTROLLER *f;
SESSION *s;
CONNECTION *c;
SERVER *server;
bool first_failed;
// Validate arguments
if (thread == NULL || param == NULL)
{
return;
}
#ifdef OS_WIN32
MsSetThreadPriorityRealtime();
#endif // OS_WIN32
f = (FARM_CONTROLLER *)param;
f->Thread = thread;
AddRef(f->Thread->ref);
NoticeThreadInit(thread);
f->StartedTime = SystemTime64();
server = f->Server;
SLog(server->Cedar, "LS_FARM_CONNECT_1", server->ControllerName);
first_failed = true;
while (true)
{
// Attempt to connect
CLIENT_OPTION o;
f->LastError = ERR_TRYING_TO_CONNECT;
Zero(&o, sizeof(CLIENT_OPTION));
StrCpy(o.Hostname, sizeof(o.Hostname), server->ControllerName);
o.Port = server->ControllerPort;
f->NumTry++;
Debug("Try to Connect %s (Controller).\n", server->ControllerName);
s = NewRpcSessionEx(server->Cedar, &o, NULL, CEDAR_SERVER_FARM_STR);
if (s != NULL)
{
// Connection success: send the authentication data
PACK *p = NewPack();
UCHAR secure_password[SHA1_SIZE];
BUF *b;
c = s->Connection;
Lock(f->lock);
{
f->Sock = c->FirstSock;
AddRef(f->Sock->ref);
SetTimeout(f->Sock, SERVER_CONTROL_TCP_TIMEOUT);
}
Unlock(f->lock);
// Method
PackAddStr(p, "method", "farm_connect");
PackAddClientVersion(p, s->Connection);
// Password
SecurePassword(secure_password, server->MemberPassword, s->Connection->Random);
PackAddData(p, "SecurePassword", secure_password, sizeof(secure_password));
Lock(server->Cedar->lock);
{
b = XToBuf(server->Cedar->ServerX, false);
}
Unlock(server->Cedar->lock);
if (b != NULL)
{
char tmp[MAX_SIZE];
bool ret;
UINT i;
// Server certificate
PackAddBuf(p, "ServerCert", b);
FreeBuf(b);
// Maximum number of sessions
PackAddInt(p, "MaxSessions", GetServerCapsInt(server, "i_max_sessions"));
// Point
PackAddInt(p, "Point", SiGetPoint(server));
PackAddInt(p, "Weight", server->Weight);
// Host name
GetMachineName(tmp, sizeof(tmp));
PackAddStr(p, "HostName", tmp);
// Public IP
PackAddIp32(p, "PublicIp", server->PublicIp);
// Public port
for (i = 0;i < server->NumPublicPort;i++)
{
PackAddIntEx(p, "PublicPort", server->PublicPorts[i], i, server->NumPublicPort);
}
ret = HttpClientSend(c->FirstSock, p);
if (ret)
{
PACK *p;
UINT err = ERR_PROTOCOL_ERROR;
first_failed = true;
p = HttpClientRecv(c->FirstSock);
if (p != NULL && (err = GetErrorFromPack(p)) == 0)
{
// Successful connection
SLog(server->Cedar, "LS_FARM_START");
f->CurrentConnectedTime = SystemTime64();
if (f->FirstConnectedTime == 0)
{
f->FirstConnectedTime = SystemTime64();
}
f->NumConnected++;
Debug("Connect Succeed.\n");
f->Online = true;
// Main process
SiAcceptTasksFromController(f, c->FirstSock);
f->Online = false;
}
else
{
// Error
f->LastError = err;
SLog(server->Cedar, "LS_FARM_CONNECT_2", server->ControllerName,
GetUniErrorStr(err), err);
}
FreePack(p);
}
else
{
f->LastError = ERR_DISCONNECTED;
if (first_failed)
{
SLog(server->Cedar, "LS_FARM_CONNECT_3", server->ControllerName, RETRY_CONNECT_TO_CONTROLLER_INTERVAL / 1000);
first_failed = false;
}
}
}
FreePack(p);
// Disconnect
Lock(f->lock);
{
if (f->Sock != NULL)
{
ReleaseSock(f->Sock);
f->Sock = NULL;
}
}
Unlock(f->lock);
ReleaseSession(s);
s = NULL;
if (f->LastError == ERR_TRYING_TO_CONNECT)
{
f->LastError = ERR_DISCONNECTED;
}
}
else
{
// Connection failure
f->LastError = ERR_CONNECT_TO_FARM_CONTROLLER;
if (first_failed)
{
SLog(server->Cedar, "LS_FARM_CONNECT_3", server->ControllerName, RETRY_CONNECT_TO_CONTROLLER_INTERVAL / 1000);
first_failed = false;
}
}
Debug("Controller Disconnected. ERROR = %S\n", _E(f->LastError));
f->NumFailed = f->NumTry - f->NumConnected;
// Wait for event
Wait(f->HaltEvent, RETRY_CONNECT_TO_CONTROLLER_INTERVAL);
if (f->Halt)
{
// Halting flag
break;
}
}
SLog(server->Cedar, "LS_FARM_DISCONNECT");
}
// Disconnect the connection to the controller
void SiStopConnectToController(FARM_CONTROLLER *f)
{
// Validate arguments
if (f == NULL)
{
return;
}
f->Halt = true;
// Stop the connection
Lock(f->lock);
{
Disconnect(f->Sock);
}
Unlock(f->lock);
Set(f->HaltEvent);
// Wait for the thread termination
WaitThread(f->Thread, INFINITE);
ReleaseThread(f->Thread);
DeleteLock(f->lock);
ReleaseEvent(f->HaltEvent);
Free(f);
}
// Start a connection to the controller
FARM_CONTROLLER *SiStartConnectToController(SERVER *s)
{
FARM_CONTROLLER *f;
THREAD *t;
// Validate arguments
if (s == NULL)
{
return NULL;
}
f = ZeroMalloc(sizeof(FARM_CONTROLLER));
f->Server = s;
f->LastError = ERR_TRYING_TO_CONNECT;
f->HaltEvent = NewEvent();
f->lock = NewLock();
t = NewThread(SiConnectToControllerThread, f);
WaitThreadInit(t);
ReleaseThread(t);
return f;
}
// Get the current version
void SiGetCurrentRegion(CEDAR *c, char *region, UINT region_size)
{
ClearStr(region, region_size);
// Validate arguments
if (c == NULL || region == NULL)
{
return;
}
Lock(c->CurrentRegionLock);
{
StrCpy(region, region_size, c->CurrentRegion);
}
Unlock(c->CurrentRegionLock);
if (IsEmptyStr(region))
{
if (GetCurrentLangId() == SE_LANG_JAPANESE)
{
StrCpy(region, region_size, "JP");
}
else if (GetCurrentLangId() == SE_LANG_CHINESE_ZH)
{
StrCpy(region, region_size, "CN");
}
}
}
// Check whether some enterprise functions are restricted
//
// ** Hints by Daiyuu Nobori, written on March 19, 2014 **
//
// The following 'enterprise functions' are implemented on SoftEther VPN Server
// since March 19, 2014. However, these functions are disabled on
// SoftEther VPN Servers which run in Japan and China.
//
// - RADIUS / NT Domain user authentication
// - RSA certificate authentication
// - Deep-inspect packet logging
// - Source IP address control list
// - syslog transfer
//
// The SoftEther VPN Project intentionally disables these functions for users
// in Japan and China. The reason is: Daiyuu Nobori, the chief author of
// SoftEther VPN, has been liable to observe the existing agreements and
// restrictions between him and some companies. The agreements have regulated
// the region-limited restriction to implement and distribute the above
// enterprise functions on the SoftEther VPN open-source program.
//
// Therefore, the SoftEther VPN Project distributes the binary program and
// the source code with the "SiIsEnterpriseFunctionsRestrictedOnOpenSource"
// function. This function identifies whether the SoftEther VPN Server
// program is running in either Japan or China. If the restricted region is
// detected, then the above enterprise functions will be disabled.
//
// Please note that the above restriction has been imposed only on the
// original binaries and source codes from the SoftEther VPN Project.
// Anyone, except Daiyuu Nobori, who understands and writes the C language
// program can remove this restriction at his own risk.
//
bool SiIsEnterpriseFunctionsRestrictedOnOpenSource(CEDAR *c)
{
char region[128];
bool ret = false;
// Validate arguments
if (c == NULL)
{
return false;
}
SiGetCurrentRegion(c, region, sizeof(region));
if (StrCmpi(region, "JP") == 0 || StrCmpi(region, "CN") == 0)
{
ret = true;
}
return ret;
}
// Update the current region
void SiUpdateCurrentRegion(CEDAR *c, char *region, bool force_update)
{
bool changed = false;
// Validate arguments
if (c == NULL)
{
return;
}
if (IsEmptyStr(region) == false)
{
Lock(c->CurrentRegionLock);
{
if (StrCmpi(c->CurrentRegion, region) != 0)
{
StrCpy(c->CurrentRegion, sizeof(c->CurrentRegion), region);
changed = true;
}
}
Unlock(c->CurrentRegionLock);
}
if (force_update)
{
changed = true;
}
if (changed)
{
FlushServerCaps(c->Server);
}
}
// Create a server
SERVER *SiNewServer(bool bridge)
{
return SiNewServerEx(bridge, false, false);
}
SERVER *SiNewServerEx(bool bridge, bool in_client_inner_server, bool relay_server)
{
SERVER *s;
LISTENER *inproc;
LISTENER *azure;
LISTENER *rudp;
DnsThreadNumMaxSet(DNS_THREAD_DEFAULT_NUM_MAX);
s = ZeroMalloc(sizeof(SERVER));
SetEraserCheckInterval(0);
SiInitHubCreateHistory(s);
InitServerCapsCache(s);
Rand(s->MyRandomKey, sizeof(s->MyRandomKey));
s->lock = NewLock();
s->OpenVpnSstpConfigLock = NewLock();
s->SaveCfgLock = NewLock();
s->ref = NewRef();
s->Cedar = NewCedar(NULL, NULL);
s->Cedar->Server = s;
#ifdef OS_WIN32
s->IsInVm = MsIsInVm();
#else // OS_WIN32
s->IsInVm = UnixIsInVm();
#endif // OS_WIN32
#ifdef ENABLE_AZURE_SERVER
if (IsFileExists("@azureserver.config"))
{
DisableRDUPServerGlobally();
s->AzureServer = NewAzureServer(s->Cedar);
SleepThread(500);
}
#endif // ENABLE_AZURE_SERVER
s->Cedar->CheckExpires = true;
s->ServerListenerList = NewList(CompareServerListener);
s->PortsUDP = NewIntList(true);
s->StartTime = SystemTime64();
s->TasksFromFarmControllerLock = NewLock();
if (bridge)
{
SetCedarVpnBridge(s->Cedar);
}
#ifdef OS_WIN32
if (IsHamMode() == false)
{
RegistWindowsFirewallAll();
}
#endif
s->Keep = StartKeep();
// Log related
MakeDir(bridge == false ? SERVER_LOG_DIR_NAME : BRIDGE_LOG_DIR_NAME);
s->Logger = NewLog(bridge == false ? SERVER_LOG_DIR_NAME : BRIDGE_LOG_DIR_NAME, SERVER_LOG_PERFIX, LOG_SWITCH_DAY);
SLog(s->Cedar, "L_LINE");
SLog(s->Cedar, "LS_START_2", s->Cedar->ServerStr, s->Cedar->VerString);
SLog(s->Cedar, "LS_START_3", s->Cedar->BuildInfo);
SLog(s->Cedar, "LS_START_UTF8");
SLog(s->Cedar, "LS_START_1");
// Initialize the configuration
SiInitConfiguration(s);
s->Syslog = NewSysLog(NULL, 0, &s->Cedar->Server->ListenIP);
s->SyslogLock = NewLock();
SetFifoCurrentReallocMemSize(MEM_FIFO_REALLOC_MEM_SIZE);
// Raise the priority
if (s->NoHighPriorityProcess == false)
{
OSSetHighPriority();
}
#ifdef OS_UNIX
UnixSetHighOomScore();
#endif // OS_UNIX
if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
{
// Start a connection to the controller
s->FarmController = SiStartConnectToController(s);
}
else if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
{
FARM_MEMBER *f;
// Start operating as a controller
s->FarmMemberList = NewList(NULL);
f = ZeroMalloc(sizeof(FARM_MEMBER));
f->Cedar = s->Cedar;
GetMachineName(f->hostname, sizeof(f->hostname));
f->Me = true;
f->HubList = NewList(CompareHubList);
f->Weight = s->Weight;
s->Me = f;
Add(s->FarmMemberList, f);
SiStartFarmControl(s);
s->FarmControllerInited = true;
}
// Start a in-processlistener
inproc = NewListener(s->Cedar, LISTENER_INPROC, 0);
ReleaseListener(inproc);
// Start a listener for Azure
if (s->AzureClient != NULL)
{
azure = NewListener(s->Cedar, LISTENER_REVERSE, 0);
ReleaseListener(azure);
}
// Start a R-UDP listener
if (s->DisableNatTraversal == false && s->Cedar->Bridge == false)
{
rudp = NewListenerEx4(s->Cedar, LISTENER_RUDP, 0, TCPAcceptedThread, NULL, false, false,
&s->NatTGlobalUdpPort, RAND_PORT_ID_SERVER_LISTEN);
ReleaseListener(rudp);
}
// Start a VPN-over-ICMP listener
s->DynListenerIcmp = NewDynamicListener(s->Cedar, &s->EnableVpnOverIcmp, LISTENER_ICMP, 0);
// Start a VPN-over-DNS listener
s->DynListenerDns = NewDynamicListener(s->Cedar, &s->EnableVpnOverDns, LISTENER_DNS, 53);
SiInitDeadLockCheck(s);
SiUpdateCurrentRegion(s->Cedar, "", true);
return s;
}