// 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", "", 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; }