diff --git a/src/Cedar/Admin.c b/src/Cedar/Admin.c index 85f9bd9b..b79a5cea 100644 --- a/src/Cedar/Admin.c +++ b/src/Cedar/Admin.c @@ -726,9 +726,8 @@ void AdminWebProcPost(CONNECTION *c, SOCK *s, HTTP_HEADER *h, UINT post_data_siz if (RecvAll(s, data, post_data_size, s->SecureMode)) { c->JsonRpcAuthed = true; -#ifndef GC_SOFTETHER_OSS + RemoveDosEntry(c->Listener, s); -#endif // GC_SOFTETHER_OSS // Divide url_target into URL and query string StrCpy(url, sizeof(url), url_target); @@ -767,9 +766,8 @@ void AdminWebProcGet(CONNECTION *c, SOCK *s, HTTP_HEADER *h, char *url_target) } c->JsonRpcAuthed = true; -#ifndef GC_SOFTETHER_OSS + RemoveDosEntry(c->Listener, s); -#endif // GC_SOFTETHER_OSS // Divide url_target into URL and query string StrCpy(url, sizeof(url), url_target); @@ -1199,9 +1197,7 @@ void JsonRpcProcOptions(CONNECTION *c, SOCK *s, HTTP_HEADER *h, char *url_target c->JsonRpcAuthed = true; -#ifndef GC_SOFTETHER_OSS RemoveDosEntry(c->Listener, s); -#endif // GC_SOFTETHER_OSS AdminWebSendBody(s, 200, "OK", NULL, 0, NULL, NULL, NULL, h); } @@ -1228,9 +1224,7 @@ void JsonRpcProcGet(CONNECTION *c, SOCK *s, HTTP_HEADER *h, char *url_target) c->JsonRpcAuthed = true; -#ifndef GC_SOFTETHER_OSS RemoveDosEntry(c->Listener, s); -#endif // GC_SOFTETHER_OSS // Divide url_target into URL and query string StrCpy(url, sizeof(url), url_target); @@ -1357,9 +1351,7 @@ void JsonRpcProcPost(CONNECTION *c, SOCK *s, HTTP_HEADER *h, UINT post_data_size c->JsonRpcAuthed = true; -#ifndef GC_SOFTETHER_OSS RemoveDosEntry(c->Listener, s); -#endif // GC_SOFTETHER_OSS if (json_req == NULL || json_req_object == NULL) { diff --git a/src/Cedar/Cedar.c b/src/Cedar/Cedar.c index 02b4ee2b..6f3e32c2 100644 --- a/src/Cedar/Cedar.c +++ b/src/Cedar/Cedar.c @@ -322,6 +322,34 @@ void DecrementNoSsl(CEDAR *c, IP *ip, UINT num_dec) UnlockList(c->NonSslList); } +// Check whether the specified IP address is in Non-SSL connection list +bool IsInNoSsl(CEDAR *c, IP *ip) +{ + bool ret = false; + // Validate arguments + if (c == NULL || ip == NULL) + { + return false; + } + + LockList(c->NonSslList); + { + NON_SSL *n = SearchNoSslList(c, ip); + + if (n != NULL) + { + if (n->EntryExpires > Tick64() && n->Count > NON_SSL_MIN_COUNT) + { + n->EntryExpires = Tick64() + (UINT64)NON_SSL_ENTRY_EXPIRES; + ret = true; + } + } + } + UnlockList(c->NonSslList); + + return ret; +} + // Add new entry to Non-SSL connection list bool AddNoSsl(CEDAR *c, IP *ip) { @@ -704,6 +732,47 @@ void DelConnection(CEDAR *cedar, CONNECTION *c) UnlockList(cedar->ConnectionList); } +// Get the number of unestablished connections +UINT GetUnestablishedConnections(CEDAR *cedar) +{ + UINT i, ret; + // Validate arguments + if (cedar == NULL) + { + return 0; + } + + ret = 0; + + LockList(cedar->ConnectionList); + { + for (i = 0;i < LIST_NUM(cedar->ConnectionList);i++) + { + CONNECTION *c = LIST_DATA(cedar->ConnectionList, i); + + switch (c->Type) + { + case CONNECTION_TYPE_CLIENT: + case CONNECTION_TYPE_INIT: + case CONNECTION_TYPE_LOGIN: + case CONNECTION_TYPE_ADDITIONAL: + switch (c->Status) + { + case CONNECTION_STATUS_ACCEPTED: + case CONNECTION_STATUS_NEGOTIATION: + case CONNECTION_STATUS_USERAUTH: + ret++; + break; + } + break; + } + } + } + UnlockList(cedar->ConnectionList); + + return ret + Count(cedar->AcceptingSockets); +} + // Add connection to Cedar void AddConnection(CEDAR *cedar, CONNECTION *c) { diff --git a/src/Cedar/Cedar.h b/src/Cedar/Cedar.h index ec1b18b9..699263a9 100644 --- a/src/Cedar/Cedar.h +++ b/src/Cedar/Cedar.h @@ -1022,6 +1022,7 @@ void DelHubEx(CEDAR *c, HUB *h, bool no_lock); void StopAllHub(CEDAR *c); void StopAllConnection(CEDAR *c); void AddConnection(CEDAR *cedar, CONNECTION *c); +UINT GetUnestablishedConnections(CEDAR *cedar); void DelConnection(CEDAR *cedar, CONNECTION *c); void SetCedarCipherList(CEDAR *cedar, char *name); void InitCedar(); @@ -1046,6 +1047,7 @@ bool AddNoSsl(CEDAR *c, IP *ip); void DecrementNoSsl(CEDAR *c, IP *ip, UINT num_dec); void DeleteOldNoSsl(CEDAR *c); NON_SSL *SearchNoSslList(CEDAR *c, IP *ip); +bool IsInNoSsl(CEDAR *c, IP *ip); void FreeTinyLog(TINY_LOG *t); void WriteTinyLog(TINY_LOG *t, char *str); TINY_LOG *NewTinyLog(); diff --git a/src/Cedar/Client.c b/src/Cedar/Client.c index 1432228e..fd0496e8 100644 --- a/src/Cedar/Client.c +++ b/src/Cedar/Client.c @@ -5155,6 +5155,22 @@ void CiRpcAccepted(CLIENT *c, SOCK *s) retcode = 0; } + if (retcode == 0) + { + if (IsLocalHostIP(&s->RemoteIP) == false) + { + // If the RPC client is from network check whether the password is empty + UCHAR empty_password_hash[20]; + Sha0(empty_password_hash, "", 0); + if (Cmp(empty_password_hash, hashed_password, SHA1_SIZE) == 0 || + IsZero(hashed_password, SHA1_SIZE)) + { + // Regard it as incorrect password + retcode = 1; + } + } + } + Lock(c->lock); { if (c->Config.AllowRemoteConfig == false) @@ -5258,14 +5274,21 @@ void CiRpcServerThread(THREAD *thread, void *param) // Open the port listener = NULL; - for (i = CLIENT_CONFIG_PORT;i < (CLIENT_CONFIG_PORT + 5);i++) + if (c->Config.DisableRpcDynamicPortListener == false) { - listener = Listen(i); - if (listener != NULL) + for (i = CLIENT_CONFIG_PORT;i < (CLIENT_CONFIG_PORT + 5);i++) { - break; + listener = ListenEx(i, !c->Config.AllowRemoteConfig); + if (listener != NULL) + { + break; + } } } + else + { + listener = ListenEx(CLIENT_CONFIG_PORT, !c->Config.AllowRemoteConfig); + } if (listener == NULL) { @@ -9028,6 +9051,12 @@ void CiInitConfiguration(CLIENT *c) c->Config.UseKeepConnect = false; // Don't use the connection maintenance function by default in the Client // Eraser c->Eraser = NewEraser(c->Logger, 0); + +#ifdef OS_WIN32 + c->Config.DisableRpcDynamicPortListener = false; +#else // OS_WIN32 + c->Config.DisableRpcDynamicPortListener = true; +#endif // OS_WIN32 } else { @@ -9174,6 +9203,19 @@ void CiLoadClientConfig(CLIENT_CONFIG *c, FOLDER *f) c->AllowRemoteConfig = CfgGetBool(f, "AllowRemoteConfig"); c->KeepConnectInterval = MAKESURE(CfgGetInt(f, "KeepConnectInterval"), KEEP_INTERVAL_MIN, KEEP_INTERVAL_MAX); c->NoChangeWcmNetworkSettingOnWindows8 = CfgGetBool(f, "NoChangeWcmNetworkSettingOnWindows8"); + + if (CfgIsItem(f, "DisableRpcDynamicPortListener")) + { + c->DisableRpcDynamicPortListener = CfgGetBool(f, "DisableRpcDynamicPortListener"); + } + else + { +#ifdef OS_WIN32 + c->DisableRpcDynamicPortListener = false; +#else // OS_WIN32 + c->DisableRpcDynamicPortListener = true; +#endif // OS_WIN32 + } } // Read the client authentication data @@ -9748,6 +9790,7 @@ void CiWriteClientConfig(FOLDER *cc, CLIENT_CONFIG *config) CfgAddBool(cc, "AllowRemoteConfig", config->AllowRemoteConfig); CfgAddInt(cc, "KeepConnectInterval", config->KeepConnectInterval); CfgAddBool(cc, "NoChangeWcmNetworkSettingOnWindows8", config->NoChangeWcmNetworkSettingOnWindows8); + CfgAddBool(cc, "DisableRpcDynamicPortListener", config->DisableRpcDynamicPortListener); } // Write the client authentication data diff --git a/src/Cedar/Client.h b/src/Cedar/Client.h index 533996d9..13e44d32 100644 --- a/src/Cedar/Client.h +++ b/src/Cedar/Client.h @@ -87,6 +87,7 @@ struct CLIENT_CONFIG UINT KeepConnectProtocol; // Protocol UINT KeepConnectInterval; // Interval bool NoChangeWcmNetworkSettingOnWindows8; // Don't change the WCM network settings on Windows 8 + bool DisableRpcDynamicPortListener; }; // Version acquisition diff --git a/src/Cedar/Command.c b/src/Cedar/Command.c index 8969ee7b..dce502bb 100644 --- a/src/Cedar/Command.c +++ b/src/Cedar/Command.c @@ -24496,6 +24496,34 @@ void CmdPrintAbout(CONSOLE *c) c->Write(c, tmp); + // Showing an explanation of the purpose of the Developer Edition and the difference from the Stable Editon by Daiyuu Nobori + /* + * Welcome to the Developer Edition of SoftEther VPN. + + Please note: SoftEther VPN Developer Edition (Version 5.x) has accepted + great code contributions on GitHub from many excellent open source + developers. This edition contains some very bright experimental code. + The experimental code in this Developer Edition has *NOT* been fully + reviewed by Daiyuu Nobori (the first original author of SoftEther VPN) + and has not been endorsed by him for stability and quality. It is his + policy to encourage many developers to contribute code with their + creative minds and ambitions. The succession of low-level system + software and network developers is of critical importance worldwide, + and SoftEther VPN Developer Edition is very important to increase + the number of such great developers. + - If you are a programmer of VPN software, or if you want a variety of + experimental code, this edition is very suitable for you. + - On the other hand, if you are building VPNs for mission-critical + business systems that require stability and security, + Stable Edition (Version 4.x) is highly recommended. + - All code in Stable Edition is reviewed by Daiyuu Nobori. He is also + responsible for porting features from the Developer Edition + to the Stable Edition. + - SoftEther VPN Stable Edition can be downloaded at: + https://github.com/SoftEtherVPN/SoftEtherVPN_Stable/ +*/ + c->Write(c, L"\nWelcome to the Developer Edition of SoftEther VPN.\n\nPlease note: SoftEther VPN Developer Edition (Version 5.x) has accepted\ngreat code contributions on GitHub from many excellent open source\ndevelopers. This edition contains some very bright experimental code.\n The experimental code in this Developer Edition has *NOT* been fully\nreviewed by Daiyuu Nobori (the first original author of SoftEther VPN)\nand has not been endorsed by him for stability and quality. It is his\npolicy to encourage many developers to contribute code with their\ncreative minds and ambitions. The succession of low-level system\nsoftware and network developers is of critical importance worldwide,\nand SoftEther VPN Developer Edition is very important to increase\nthe number of such great developers.\n- If you are a programmer of VPN software, or if you want a variety of\n experimental code, this edition is very suitable for you.\n- On the other hand, if you are building VPNs for mission-critical\n business systems that require stability and security,\n Stable Edition (Version 4.x) is highly recommended.\n- All code in Stable Edition is reviewed by Daiyuu Nobori. He is also\n responsible for porting features from the Developer Edition\n to the Stable Edition.\n- SoftEther VPN Stable Edition can be downloaded at:\n https://github.com/SoftEtherVPN/SoftEtherVPN_Stable/\n\n"); + ReleaseCedar(cedar); } diff --git a/src/Cedar/DDNS.c b/src/Cedar/DDNS.c index 87cd49f1..486c3bfe 100644 --- a/src/Cedar/DDNS.c +++ b/src/Cedar/DDNS.c @@ -541,13 +541,9 @@ UINT DCRegister(DDNS_CLIENT *c, bool ipv6, DDNS_REGISTER_PARAM *p, char *replace } } - - Format(url2, sizeof(url2), "%s?v=%I64u", url, Rand64()); Format(url3, sizeof(url3), url2, key_hash_str[2], key_hash_str[3]); - ReplaceStr(url3, sizeof(url3), url3, "https://", "http://"); - ReplaceStr(url3, sizeof(url3), url3, ".servers", ".open.servers"); cert_hash = StrToBin(DDNS_CERT_HASH); diff --git a/src/Cedar/DDNS.h b/src/Cedar/DDNS.h index 0775766f..75546109 100644 --- a/src/Cedar/DDNS.h +++ b/src/Cedar/DDNS.h @@ -18,7 +18,11 @@ "439BAFA75A6EE5671FC9F9A02D34FF29881761A0" \ "EFAC5FA0CDD14E0F864EED58A73C35D7E33B62F3" \ "74DF99D4B1B5F0488A388B50D347D26013DC67A5" \ - "6EBB39AFCA8C900635CFC11218CF293A612457E4" + "6EBB39AFCA8C900635CFC11218CF293A612457E4" \ + "05A9386C5E2B233F7BAB2479620EAAA2793709ED" \ + "A811C64BB715351E36B6C1E022648D8BE0ACD128" \ + "BD264DB3B0B1B3ABA0AF3074AA574ED1EF3B42D7" \ + "9AB61D691536645DD55A8730FC6D2CDF33C8C73F" #define DDNS_SNI_VER_STRING "DDNS" @@ -43,7 +47,7 @@ #define DDNS_URL2_V4_ALT "http://get-my-ip.ddns.uxcom.jp/ddns/getmyip.ashx" #define DDNS_URL2_V6_ALT "http://get-my-ip-v6.ddns.uxcom.jp/ddns/getmyip.ashx" -#define DDNS_RPC_MAX_RECV_SIZE DYN32(DDNS_RPC_MAX_RECV_SIZE, (128 * 1024 * 1024)) +#define DDNS_RPC_MAX_RECV_SIZE DYN32(DDNS_RPC_MAX_RECV_SIZE, (38 * 1024 * 1024)) // Connection Timeout #define DDNS_CONNECT_TIMEOUT DYN32(DDNS_CONNECT_TIMEOUT, (15 * 1000)) diff --git a/src/Cedar/Listener.c b/src/Cedar/Listener.c index 6ea0d5cc..ec295403 100644 --- a/src/Cedar/Listener.c +++ b/src/Cedar/Listener.c @@ -17,6 +17,7 @@ #include "Mayaqua/Memory.h" #include "Mayaqua/Object.h" #include "Mayaqua/Str.h" +#include "Mayaqua/Tick64.h" static bool disable_dos = false; static UINT max_connections_per_ip = DEFAULT_MAX_CONNECTIONS_PER_IP; @@ -181,6 +182,11 @@ void TCPAcceptedThread(THREAD *t, void *param) ConnectionAccept(c); flag1 = c->flag1; + if (c->JsonRpcAuthed) + { + RemoveDosEntry(r, s); + } + // Release SLog(r->Cedar, "LS_CONNECTION_END_1", c->Name); ReleaseListener(c->Listener); @@ -221,6 +227,46 @@ void TCPAccepted(LISTENER *r, SOCK *s) num_clients_from_this_ip = GetNumIpClient(&s->RemoteIP); +#ifdef USE_DOS_ATTACK_DETECTION + if (disable_dos == false && r->DisableDos == false && r->Protocol != LISTENER_INPROC) + { + UINT max_uec, now_uec; + // DOS attack check + if (CheckDosAttack(r, s) == false) + { + Debug("DOS Attack 1 !!\n"); + IPToStr(tmp, sizeof(tmp), &s->RemoteIP); + SLog(r->Cedar, "LS_LISTENER_DOS", r->Port, tmp, s->RemotePort); + return; + } + if (StrCmpi(s->UnderlayProtocol, SOCK_UNDERLAY_NATIVE_V6) == 0 || + StrCmpi(s->UnderlayProtocol, SOCK_UNDERLAY_NATIVE_V4) == 0) + { + if (IsInNoSsl(r->Cedar, &s->RemoteIP)) + { + Debug("DOS Attack 2 !!\n"); + IPToStr(tmp, sizeof(tmp), &s->RemoteIP); + SLog(r->Cedar, "LS_LISTENER_DOS", r->Port, tmp, s->RemotePort); + return; + } + } + if (num_clients_from_this_ip > GetMaxConnectionsPerIp()) + { + Debug("DOS Attack 3 !!\n"); + IPToStr(tmp, sizeof(tmp), &s->RemoteIP); + SLog(r->Cedar, "LS_LISTENER_DOS", r->Port, tmp, s->RemotePort); + return; + } + max_uec = GetMaxUnestablishedConnections(); + now_uec = GetUnestablishedConnections(cedar); + if (now_uec > max_uec) + { + Debug("DOS Attack 4 !!\n"); + SLog(r->Cedar, "LS_LISTENER_MAXUEC", max_uec, now_uec); + return; + } + } +#endif // USE_DOS_ATTACK_DETECTION IPToStr(tmp, sizeof(tmp), &s->RemoteIP); @@ -239,6 +285,169 @@ void TCPAccepted(LISTENER *r, SOCK *s) ReleaseThread(t); } +// Remove a DOS entry +bool RemoveDosEntry(LISTENER *r, SOCK *s) +{ + DOS *d; + bool ok = false; + // Validate arguments + if (r == NULL || s == NULL) + { + return false; + } + + LockList(r->DosList); + { + // Delete old entries from the DOS attack list + RefreshDosList(r); + + // Search the table + d = SearchDosList(r, &s->RemoteIP); + + if (d != NULL) + { + Delete(r->DosList, d); + Free(d); + ok = true; + } + } + UnlockList(r->DosList); + + return ok; +} + +// Check whether this is a DOS attack +bool CheckDosAttack(LISTENER *r, SOCK *s) +{ + DOS *d; + bool ok = true; + // Validate arguments + if (r == NULL || s == NULL) + { + return false; + } + + LockList(r->DosList); + { + // Delete old entries from the DOS attack list + RefreshDosList(r); + + // Search the table + d = SearchDosList(r, &s->RemoteIP); + + if (d != NULL) + { + // There is a entry already + // This should mean being under a DOS attack + d->LastConnectedTick = Tick64(); + d->CurrentExpireSpan = MIN(d->CurrentExpireSpan * (UINT64)2, DOS_TABLE_EXPIRES_MAX); + d->AccessCount++; + if (d->AccessCount > DOS_TABLE_MAX_LIMIT_PER_IP) + { + ok = false; + } + } + else + { + // Create a new entry + d = ZeroMalloc(sizeof(DOS)); + d->CurrentExpireSpan = (UINT64)DOS_TABLE_EXPIRES_FIRST; + d->FirstConnectedTick = d->LastConnectedTick = Tick64(); + d->AccessCount = 1; + d->DeleteEntryTick = d->FirstConnectedTick + (UINT64)DOS_TABLE_EXPIRES_TOTAL; + Copy(&d->IpAddress, &s->RemoteIP, sizeof(IP)); + Add(r->DosList, d); + } + } + UnlockList(r->DosList); + + return ok; +} + +// Delete old entries from the DOS attack list +void RefreshDosList(LISTENER *r) +{ + // Validate arguments + if (r == NULL) + { + return; + } + + if (r->DosListLastRefreshTime == 0 || + (r->DosListLastRefreshTime + (UINT64)DOS_TABLE_REFRESH_INTERVAL) <= Tick64()) + { + UINT i; + LIST *o; + r->DosListLastRefreshTime = Tick64(); + + o = NewListFast(NULL); + for (i = 0;i < LIST_NUM(r->DosList);i++) + { + DOS *d = LIST_DATA(r->DosList, i); + if ((d->LastConnectedTick + d->CurrentExpireSpan) <= Tick64() || + (d->DeleteEntryTick <= Tick64())) + { + Add(o, d); + } + } + + for (i = 0;i < LIST_NUM(o);i++) + { + DOS *d = LIST_DATA(o, i); + Delete(r->DosList, d); + Free(d); + } + + ReleaseList(o); + } +} + +// Search the DOS attack list by the IP address +DOS *SearchDosList(LISTENER *r, IP *ip) +{ + DOS *d, t; + // Validate arguments + if (r == NULL || ip == NULL) + { + return NULL; + } + + Copy(&t.IpAddress, ip, sizeof(IP)); + + d = Search(r->DosList, &t); + + if (d != NULL) + { + if ((d->LastConnectedTick + d->CurrentExpireSpan) <= Tick64() || + (d->DeleteEntryTick <= Tick64())) + { + // Delete old entries + Delete(r->DosList, d); + Free(d); + return NULL; + } + } + + return d; +} + +// Comparison of DOS attack list entries +int CompareDos(void *p1, void *p2) +{ + DOS *d1, *d2; + if (p1 == NULL || p2 == NULL) + { + return 0; + } + d1 = *(DOS **)p1; + d2 = *(DOS **)p2; + if (d1 == NULL || d2 == NULL) + { + return 0; + } + + return CmpIpAddr(&d1->IpAddress, &d2->IpAddress); +} // UDP listener main loop void ListenerUDPMainLoop(LISTENER *r) @@ -653,6 +862,13 @@ void CleanupListener(LISTENER *r) return; } + // Release the DOS attack list + for (i = 0;i < LIST_NUM(r->DosList);i++) + { + DOS *d = LIST_DATA(r->DosList, i); + Free(d); + } + ReleaseList(r->DosList); if (r->Sock != NULL) { @@ -802,6 +1018,7 @@ LISTENER *NewListenerEx5(CEDAR *cedar, UINT proto, UINT port, THREAD_PROC *proc, r->Port = port; r->Event = NewEvent(); + r->DosList = NewList(CompareDos); r->LocalOnly = local_only; r->ShadowIPv6 = shadow_ipv6; diff --git a/src/Cedar/Listener.h b/src/Cedar/Listener.h index 40b816f1..e3609df5 100644 --- a/src/Cedar/Listener.h +++ b/src/Cedar/Listener.h @@ -10,12 +10,24 @@ #include "CedarType.h" +#include "Mayaqua/MayaType.h" #include "Mayaqua/Kernel.h" +#include "Mayaqua/Network.h" // Function to call when receiving a new connection typedef void (NEW_CONNECTION_PROC)(CONNECTION *c); +// DOS attack list +struct DOS +{ + IP IpAddress; // IP address + UINT64 FirstConnectedTick; // Time which a client connects at the first time + UINT64 LastConnectedTick; // Time which a client connected at the last time + UINT64 CurrentExpireSpan; // Current time-out period of this record + UINT64 DeleteEntryTick; // Time planned to delete this entry + UINT AccessCount; // The number of accesses +}; // Listener structure struct LISTENER @@ -31,6 +43,8 @@ struct LISTENER volatile bool Halt; // Halting flag UINT Status; // State + LIST *DosList; // DOS attack list + UINT64 DosListLastRefreshTime; // Time that the DOS list is refreshed at the last THREAD_PROC *ThreadProc; // Thread procedure void *ThreadParam; // Thread parameters @@ -105,6 +119,11 @@ void FreeDynamicListener(DYNAMIC_LISTENER *d); bool ListenerRUDPRpcRecvProc(RUDP_STACK *r, UDPPACKET *p); void ListenerSetProcRecvRpcEnable(bool b); +int CompareDos(void *p1, void *p2); +DOS *SearchDosList(LISTENER *r, IP *ip); +void RefreshDosList(LISTENER *r); +bool CheckDosAttack(LISTENER *r, SOCK *s); +bool RemoveDosEntry(LISTENER *r, SOCK *s); #endif // LISTENER_H diff --git a/src/Cedar/Wpc.c b/src/Cedar/Wpc.c index 64e8a952..c53a32aa 100644 --- a/src/Cedar/Wpc.c +++ b/src/Cedar/Wpc.c @@ -313,8 +313,16 @@ BUF *WpcDataEntryToBuf(WPC_ENTRY *e) } data_size = e->Size + 4096; - data = Malloc(data_size); - size = DecodeSafe64(data, e->Data, e->Size); + data = ZeroMalloc(data_size); + + if (e->Size >= 1) + { + size = DecodeSafe64(data, e->Data, e->Size); + } + else + { + size = 0; + } b = NewBuf(); WriteBuf(b, data, size); diff --git a/src/Mayaqua/Encrypt.c b/src/Mayaqua/Encrypt.c index b0535fc3..fed18bdb 100644 --- a/src/Mayaqua/Encrypt.c +++ b/src/Mayaqua/Encrypt.c @@ -712,7 +712,8 @@ UINT RsaPublicSize(K *k) // Hash a pointer to a 32-bit UINT HashPtrToUINT(void *p) { - UCHAR hash_data[MD5_SIZE]; + UCHAR hash_data[SHA256_SIZE]; + UCHAR hash_src[CANARY_RAND_SIZE + sizeof(void *)]; UINT ret; // Validate arguments if (p == NULL) @@ -720,7 +721,11 @@ UINT HashPtrToUINT(void *p) return 0; } - Md5(hash_data, &p, sizeof(p)); + Zero(hash_src, sizeof(hash_src)); + Copy(hash_src + 0, GetCanaryRand(CANARY_RAND_ID_PTR_KEY_HASH), CANARY_RAND_SIZE); + Copy(hash_src + CANARY_RAND_SIZE, p, sizeof(void *)); + + Sha2_256(hash_data, hash_src, sizeof(hash_src)); Copy(&ret, hash_data, sizeof(ret)); diff --git a/src/Mayaqua/Kernel.c b/src/Mayaqua/Kernel.c index 99890a08..ec4621f7 100644 --- a/src/Mayaqua/Kernel.c +++ b/src/Mayaqua/Kernel.c @@ -2100,7 +2100,31 @@ void AbortExitEx(char *msg) f = fopen("abort_error_log.txt", "w"); if (f != NULL) { + SYSTEMTIME time = { 0 }; + char time_str[128] = { 0 }; + char *crlf = "\r\n"; + char *tag = "---------"; + + LocalTime(&time); + + sprintf(time_str, "%04u-%02u-%02u %02u:%02u:%02u", + time.wYear, time.wMonth, time.wDay, + time.wHour, time.wMinute, time.wSecond); + + fwrite(tag, 1, strlen(tag), f); + + fwrite(crlf, 1, strlen(crlf), f); + + fwrite(time_str, 1, strlen(time_str), f); + + fwrite(crlf, 1, strlen(crlf), f); + fwrite(msg, 1, strlen(msg), f); + + fwrite(crlf, 1, strlen(crlf), f); + + fwrite(crlf, 1, strlen(crlf), f); + fclose(f); } diff --git a/src/Mayaqua/MayaType.h b/src/Mayaqua/MayaType.h index efdfaa59..73307cba 100644 --- a/src/Mayaqua/MayaType.h +++ b/src/Mayaqua/MayaType.h @@ -123,11 +123,7 @@ typedef int (COMPARE)(void *p1, void *p2); #define GET_ABS(a) ((a) >= 0 ? (a) : -(a)) // Convert the pointer to UINT -#ifdef CPU_64 -#define POINTER_TO_KEY(p) HashPtrToUINT(p) -#else -#define POINTER_TO_KEY(p) (UINT)(p) -#endif +#define POINTER_TO_KEY(p) (HashPtrToUINT(p)) // Compare the pointer and UINT #define COMPARE_POINTER_AND_KEY(p, i) (POINTER_TO_KEY(p) == (i)) @@ -282,7 +278,8 @@ typedef struct TRACKING_LIST TRACKING_LIST; typedef struct IO IO; // Memory.h -typedef struct MEMTAG MEMTAG; +typedef struct MEMTAG1 MEMTAG1; +typedef struct MEMTAG2 MEMTAG2; typedef struct BUF BUF; typedef struct FIFO FIFO; typedef struct LIST LIST; diff --git a/src/Mayaqua/Mayaqua.c b/src/Mayaqua/Mayaqua.c index 88f03684..86492751 100644 --- a/src/Mayaqua/Mayaqua.c +++ b/src/Mayaqua/Mayaqua.c @@ -65,6 +65,8 @@ void InitProcessCallOnce() { init_proc_once_flag = true; + InitCanaryRand(); + #ifdef OS_WIN32 MsInitProcessCallOnce(); #endif // OS_WIN32 diff --git a/src/Mayaqua/Memory.c b/src/Mayaqua/Memory.c index 96ff994a..67929483 100644 --- a/src/Mayaqua/Memory.c +++ b/src/Mayaqua/Memory.c @@ -16,10 +16,16 @@ #include "Object.h" #include "OS.h" #include "Str.h" +#include "Tick64.h" #include "Tracking.h" #include #include +#include + +#ifdef OS_UNIX +#include +#endif #include @@ -34,6 +40,105 @@ static UINT fifo_current_realloc_mem_size = FIFO_REALLOC_MEM_SIZE; +static bool canary_inited = false; +typedef struct CANARY_RAND_DATA +{ + UCHAR Data[CANARY_RAND_SIZE + 4]; +} CANARY_RAND_DATA; + +static CANARY_RAND_DATA canary_rand_data[NUM_CANARY_RAND] = { 0 }; + +static UINT64 canary_memtag_magic1 = 0; +static UINT64 canary_memtag_magic2 = 0; + +UCHAR *GetCanaryRand(UINT id) +{ + if (id >= NUM_CANARY_RAND) + { + id = NUM_CANARY_RAND - 1; + } + + return &((canary_rand_data[id].Data)[0]); +} + +void InitCanaryRand() +{ + SYSTEMTIME st = { 0 }; + char random_seed[1024] = { 0 }; + UINT64 t1 = 0, t2 = 0; + if (canary_inited) + { + return; + } + +#ifdef OS_WIN32 + Win32GetSystemTime(&st); + memcpy(&t1, ((UCHAR *)&st) + 0, 8); + memcpy(&t2, ((UCHAR *)&st) + 8, 8); +#else // OS_WIN32 + struct timeval tv = { 0 }; + struct timezone tz = { 0 }; + gettimeofday(&tv, &tz); + t1 = (UINT64)tv.tv_sec; + t2 = (UINT64)tv.tv_usec; +#endif // OS_WIN32 + + { + UINT64 dos_rand = (UINT64)rand(); + UINT64 tick1 = TickHighresNano64(true); + UINT64 tick2 = TickHighresNano64(true); + + UINT i; + + void *p1 = malloc(1); + void *p2 = malloc(1); + + for (i = 0;i < NUM_CANARY_RAND;i++) + { + // using sprintf() here is safe. + sprintf(random_seed, + "%u " + "%llu " + "%llu " + "%llu " + "%llu " + "%llu " + "%llu " + "%llu " + "%llu " + "%llu " + "%llu " + "%llu " + "%u " + , + i, + (UINT64)InitCanaryRand, + (UINT64)&canary_inited, + (UINT64) & ((canary_rand_data[0].Data)[0]), + (UINT64)&random_seed[0], + tick1, + tick2, + dos_rand, + (UINT64)p1, + (UINT64)p2, + t1, + t2, + ~i + ); + + Sha0(canary_rand_data[i].Data, random_seed, (UINT)strlen(random_seed)); + } + + free(p1); + free(p2); + + canary_memtag_magic1 = *((UINT64 *)(GetCanaryRand(CANARY_RAND_ID_MEMTAG_MAGIC) + 0)); + canary_memtag_magic2 = *((UINT64 *)(GetCanaryRand(CANARY_RAND_ID_MEMTAG_MAGIC) + 8)); + + canary_inited = true; + } +} + // New PRand PRAND *NewPRand(void *key, UINT key_size) { @@ -3114,6 +3219,10 @@ void AdjustBufSize(BUF *b, UINT new_size) while (b->SizeReserved < new_size) { + if (b->SizeReserved > 0x7FFFFFFF) + { + AbortExitEx("AdjustBufSize(): too large buffer size"); + } b->SizeReserved = b->SizeReserved * 2; } b->Buf = ReAlloc(b->Buf, b->SizeReserved); @@ -3515,33 +3624,52 @@ void *Malloc(UINT size) } void *MallocEx(UINT size, bool zero_clear_when_free) { - MEMTAG *tag; + MEMTAG1 *tag1; + MEMTAG2 *tag2; UINT real_size; + if (canary_inited == false) + { + InitCanaryRand(); + } + + if (size > MAX_MALLOC_MEM_SIZE) + { + AbortExitEx("MallocEx() error: too large size"); + } + real_size = CALC_MALLOCSIZE(size); - tag = InternalMalloc(real_size); + tag1 = InternalMalloc(real_size); - Zero(tag, sizeof(MEMTAG)); - tag->Magic = MEMTAG_MAGIC; - tag->Size = size; - tag->ZeroFree = zero_clear_when_free; + tag1->Magic = canary_memtag_magic1 ^ ((UINT64)tag1 * GOLDEN_RATION_PRIME_U64); + tag1->Size = size; + tag1->ZeroFree = zero_clear_when_free; - return MEMTAG_TO_POINTER(tag); + tag2 = (MEMTAG2 *)(((UCHAR *)tag1) + CALC_MALLOCSIZE(tag1->Size) - sizeof(MEMTAG2)); + tag2->Magic = canary_memtag_magic2 ^ ((UINT64)tag2 * GOLDEN_RATION_PRIME_U64); + + return MEMTAG1_TO_POINTER(tag1); } // Get memory size UINT GetMemSize(void *addr) { - MEMTAG *tag; + MEMTAG1 *tag; + + if (canary_inited == false) + { + InitCanaryRand(); + } + // Validate arguments if (IS_NULL_POINTER(addr)) { return 0; } - tag = POINTER_TO_MEMTAG(addr); - CheckMemTag(tag); + tag = POINTER_TO_MEMTAG1(addr); + CheckMemTag1(tag); return tag->Size; } @@ -3549,20 +3677,35 @@ UINT GetMemSize(void *addr) // ReAlloc void *ReAlloc(void *addr, UINT size) { - MEMTAG *tag; + MEMTAG1 *tag1; + MEMTAG2 *tag2; bool zerofree; + + if (canary_inited == false) + { + InitCanaryRand(); + } + + if (size > MAX_MALLOC_MEM_SIZE) + { + AbortExitEx("ReAlloc() error: too large size"); + } + // Validate arguments if (IS_NULL_POINTER(addr)) { return NULL; } - tag = POINTER_TO_MEMTAG(addr); - CheckMemTag(tag); + tag1 = POINTER_TO_MEMTAG1(addr); + CheckMemTag1(tag1); - zerofree = tag->ZeroFree; + tag2 = (MEMTAG2 *)(((UCHAR *)tag1) + CALC_MALLOCSIZE(tag1->Size) - sizeof(MEMTAG2)); + CheckMemTag2(tag2); - if (tag->Size == size) + zerofree = tag1->ZeroFree; + + if (tag1->Size == size) { // No size change return addr; @@ -3574,10 +3717,10 @@ void *ReAlloc(void *addr, UINT size) // Size changed (zero clearing required) void *new_p = MallocEx(size, true); - if (tag->Size <= size) + if (tag1->Size <= size) { // Size expansion - Copy(new_p, addr, tag->Size); + Copy(new_p, addr, tag1->Size); } else { @@ -3593,13 +3736,22 @@ void *ReAlloc(void *addr, UINT size) else { // Size changed - MEMTAG *tag2 = InternalReAlloc(tag, CALC_MALLOCSIZE(size)); + MEMTAG1 *tag1_new; + MEMTAG2 *tag2_new; - Zero(tag2, sizeof(MEMTAG)); - tag2->Magic = MEMTAG_MAGIC; - tag2->Size = size; + tag1->Magic = 0; + tag2->Magic = 0; - return MEMTAG_TO_POINTER(tag2); + tag1_new = InternalReAlloc(tag1, CALC_MALLOCSIZE(size)); + + tag1_new->Magic = canary_memtag_magic1 ^ ((UINT64)tag1_new * GOLDEN_RATION_PRIME_U64); + tag1_new->Size = size; + tag1_new->ZeroFree = 0; + + tag2_new = (MEMTAG2 *)(((UCHAR *)tag1_new) + CALC_MALLOCSIZE(size) - sizeof(MEMTAG2)); + tag2_new->Magic = canary_memtag_magic2 ^ ((UINT64)tag2_new * GOLDEN_RATION_PRIME_U64); + + return MEMTAG1_TO_POINTER(tag1_new); } } } @@ -3607,25 +3759,35 @@ void *ReAlloc(void *addr, UINT size) // Free void Free(void *addr) { - MEMTAG *tag; + MEMTAG1 *tag1; + MEMTAG2 *tag2; // Validate arguments if (IS_NULL_POINTER(addr)) { return; } - tag = POINTER_TO_MEMTAG(addr); - CheckMemTag(tag); + if (canary_inited == false) + { + InitCanaryRand(); + } - if (tag->ZeroFree) + tag1 = POINTER_TO_MEMTAG1(addr); + CheckMemTag1(tag1); + + tag2 = (MEMTAG2 *)(((UCHAR *)tag1) + CALC_MALLOCSIZE(tag1->Size) - sizeof(MEMTAG2)); + CheckMemTag2(tag2); + + if (tag1->ZeroFree) { // Zero clear - Zero(addr, tag->Size); + Zero(addr, tag1->Size); } // Memory release - tag->Magic = 0; - InternalFree(tag); + tag1->Magic = 0; + tag2->Magic = 0; + InternalFree(tag1); } // Free and set pointer's value to NULL @@ -3635,24 +3797,36 @@ void FreeSafe(void **addr) *addr = NULL; } -// Check the memtag -void CheckMemTag(MEMTAG *tag) +// Check the memtag1 +void CheckMemTag1(MEMTAG1 *tag) { - if (IsTrackingEnabled() == false) - { - return; - } - // Validate arguments if (tag == NULL) { - AbortExitEx("CheckMemTag: tag == NULL"); + AbortExitEx("CheckMemTag1: tag1 == NULL"); return; } - if (tag->Magic != MEMTAG_MAGIC) + if (tag->Magic != (canary_memtag_magic1 ^ ((UINT64)tag * GOLDEN_RATION_PRIME_U64))) { - AbortExitEx("CheckMemTag: tag->Magic != MEMTAG_MAGIC"); + AbortExitEx("CheckMemTag1: tag1->Magic != canary_memtag_magic1"); + return; + } +} + +// Check the memtag2 +void CheckMemTag2(MEMTAG2 *tag) +{ + // Validate arguments + if (tag == NULL) + { + AbortExitEx("CheckMemTag2: tag2 == NULL"); + return; + } + + if (tag->Magic != (canary_memtag_magic2 ^ ((UINT64)tag * GOLDEN_RATION_PRIME_U64))) + { + AbortExitEx("CheckMemTag2: tag2->Magic != canary_memtag_magic2"); return; } } diff --git a/src/Mayaqua/Memory.h b/src/Mayaqua/Memory.h index 8b39cd9d..49c9c5cd 100644 --- a/src/Mayaqua/Memory.h +++ b/src/Mayaqua/Memory.h @@ -14,29 +14,38 @@ #define MallocFast Malloc #define ZeroMallocFast ZeroMalloc +#define MAX_MALLOC_MEM_SIZE (0xffffffff - 64) + // Memory size that can be passed to the kernel at a time #define MAX_SEND_BUF_MEM_SIZE (10 * 1024 * 1024) -// The magic number for memory tag -#define MEMTAG_MAGIC 0x49414449 - -#define CALC_MALLOCSIZE(size) ((MAX(size, 1)) + sizeof(MEMTAG)) -#define MEMTAG_TO_POINTER(p) ((void *)(((UCHAR *)(p)) + sizeof(MEMTAG))) -#define POINTER_TO_MEMTAG(p) ((MEMTAG *)(((UCHAR *)(p)) - sizeof(MEMTAG))) -#define IS_NULL_POINTER(p) (((p) == NULL) || ((POINTER_TO_UINT64(p) == (UINT64)sizeof(MEMTAG)))) +#define CALC_MALLOCSIZE(size) (((MAX(size, 1) + 7) / 8) * 8 + sizeof(MEMTAG1) + sizeof(MEMTAG2)) +#define MEMTAG1_TO_POINTER(p) ((void *)(((UCHAR *)(p)) + sizeof(MEMTAG1))) +#define POINTER_TO_MEMTAG1(p) ((MEMTAG1 *)(((UCHAR *)(p)) - sizeof(MEMTAG1))) +#define IS_NULL_POINTER(p) (((p) == NULL) || ((POINTER_TO_UINT64(p) == (UINT64)sizeof(MEMTAG1)))) #define PTR_TO_PTR(p) ((void **)(&p)) +// Golden Ratio Prime +// From https://github.com/torvalds/linux/blob/88c5083442454e5e8a505b11fa16f32d2879651e/include/linux/hash.h +#define GOLDEN_RATION_PRIME_U32 ((UINT32)0x61C88647) +#define GOLDEN_RATION_PRIME_U64 ((UINT64)7046029254386353131ULL) // 0x61C8864680B583EB + // Fixed size of a block of memory pool #define MEMPOOL_MAX_SIZE 3000 -// Memory tag -struct MEMTAG +// Memory tag 1 +struct MEMTAG1 { - UINT Magic; + UINT64 Magic; UINT Size; bool ZeroFree; - UINT Padding; +}; + +// Memory tag 2 +struct MEMTAG2 +{ + UINT64 Magic; }; // Buffer @@ -174,7 +183,8 @@ void *ZeroMallocEx(UINT size, bool zero_clear_when_free); void *ReAlloc(void *addr, UINT size); void Free(void *addr); void FreeSafe(void **addr); -void CheckMemTag(MEMTAG *tag); +void CheckMemTag1(MEMTAG1 *tag); +void CheckMemTag2(MEMTAG2 *tag); UINT GetMemSize(void *addr); void *InternalMalloc(UINT size); @@ -364,5 +374,14 @@ LIST *NewStrList(); void ReleaseStrList(LIST *o); bool AddStrToStrListDistinct(LIST *o, char *str); +#define NUM_CANARY_RAND 32 +#define CANARY_RAND_ID_MEMTAG_MAGIC 0 +#define CANARY_RAND_SIZE 20 + +#define CANARY_RAND_ID_PTR_KEY_HASH 1 + +void InitCanaryRand(); +UCHAR *GetCanaryRand(UINT id); + #endif // MEMORY_H diff --git a/src/Mayaqua/Network.c b/src/Mayaqua/Network.c index 04aebdea..b170d130 100644 --- a/src/Mayaqua/Network.c +++ b/src/Mayaqua/Network.c @@ -1191,7 +1191,9 @@ void RUDPProcess_NatT_Recv(RUDP_STACK *r, UDPPACKET *udp) bool is_ok = PackGetBool(p, "ok"); UINT64 tran_id = PackGetInt64(p, "tran_id"); - ExtractAndApplyDynList(p); + // This ExtractAndApplyDynList() calling was removed because it is not actually used and could be abused by + // illegal UDP packets that spoof the source IP address. 2023-6-14 Daiyuu Nobori + // ExtractAndApplyDynList(p); if (r->ServerMode) { diff --git a/src/Mayaqua/Tick64.c b/src/Mayaqua/Tick64.c index f99a623f..02932677 100644 --- a/src/Mayaqua/Tick64.c +++ b/src/Mayaqua/Tick64.c @@ -34,6 +34,23 @@ UINT64 TickHighres64() } +UINT64 TickHighresNano64(bool raw) +{ + UINT64 ret = 0; + +#ifdef OS_WIN32 + + ret = (UINT64)(MsGetHiResTimeSpan(MsGetHiResCounter()) * 1000000000.0f); + +#else // OS_WIN32 + + ret = UnixGetHighresTickNano64(raw); + +#endif // OS_WIN32 + + return ret; +} + // Convert the Tick value to time UINT64 Tick64ToTime64(UINT64 tick) { diff --git a/src/Mayaqua/Tick64.h b/src/Mayaqua/Tick64.h index 1791c517..bde8517d 100644 --- a/src/Mayaqua/Tick64.h +++ b/src/Mayaqua/Tick64.h @@ -49,6 +49,7 @@ UINT64 Diff64(UINT64 a, UINT64 b); UINT64 Tick64ToTime64(UINT64 tick); UINT64 TickToTime(UINT64 tick); UINT64 TickHighres64(); +UINT64 TickHighresNano64(bool raw); #endif // TICK64_H diff --git a/src/Mayaqua/Unix.c b/src/Mayaqua/Unix.c index bd1263c9..0c3778df 100755 --- a/src/Mayaqua/Unix.c +++ b/src/Mayaqua/Unix.c @@ -2008,6 +2008,68 @@ void UnixGetSystemTime(SYSTEMTIME *system_time) pthread_mutex_unlock(&get_time_lock); } +UINT64 UnixGetHighresTickNano64(bool raw) +{ +#if defined(OS_WIN32) || defined(CLOCK_REALTIME) || defined(CLOCK_MONOTONIC) || defined(CLOCK_HIGHRES) + struct timespec t; + UINT64 ret; + static bool akirame = false; + + if (akirame) + { + return UnixGetTick64() * 1000000ULL; + } + + Zero(&t, sizeof(t)); + + if (raw == false) + { + // Function to get the boot time of the system + // Be careful. The Implementation is depend on the system. +#ifdef CLOCK_HIGHRES + clock_gettime(CLOCK_HIGHRES, &t); +#else // CLOCK_HIGHRES +#ifdef CLOCK_MONOTONIC + clock_gettime(CLOCK_MONOTONIC, &t); +#else // CLOCK_MONOTONIC + clock_gettime(CLOCK_REALTIME, &t); +#endif // CLOCK_MONOTONIC +#endif // CLOCK_HIGHRES + } + else + { + // Function to get the boot time of the system + // Be careful. The Implementation is depend on the system. +#ifdef CLOCK_HIGHRES + clock_gettime(CLOCK_HIGHRES, &t); +#else // CLOCK_HIGHRES +#ifdef CLOCK_MONOTONIC_RAW + clock_gettime(CLOCK_MONOTONIC_RAW, &t); +#else // CLOCK_MONOTONIC_RAW +#ifdef CLOCK_MONOTONIC + clock_gettime(CLOCK_MONOTONIC, &t); +#else // CLOCK_MONOTONIC + clock_gettime(CLOCK_REALTIME, &t); +#endif // CLOCK_MONOTONIC +#endif // CLOCK_MONOTONIC_RAW +#endif // CLOCK_HIGHRES + } + + ret = ((UINT64)((UINT)t.tv_sec)) * 1000000000LL + (UINT64)t.tv_nsec; + + if (akirame == false && ret == 0) + { + ret = UnixGetTick64() * 1000000ULL; + akirame = true; + } + + return ret; + +#else + return UnixGetTick64() * 1000000ULL; +#endif +} + // Get the system timer (64bit) UINT64 UnixGetTick64() { diff --git a/src/Mayaqua/Unix.h b/src/Mayaqua/Unix.h index e382d686..9777564f 100644 --- a/src/Mayaqua/Unix.h +++ b/src/Mayaqua/Unix.h @@ -117,6 +117,7 @@ void UnixSetThreadPriorityRealtime(); void UnixSetResourceLimit(UINT id, UINT64 value); bool UnixIs64BitRlimSupported(); UINT64 UnixGetTick64(); +UINT64 UnixGetHighresTickNano64(bool raw); void UnixSigChldHandler(int sig); void UnixCloseIO(); void UnixGetCurrentDir(char *dir, UINT size); diff --git a/src/bin/hamcore/strtable_cn.stb b/src/bin/hamcore/strtable_cn.stb index fa462554..14486000 100644 --- a/src/bin/hamcore/strtable_cn.stb +++ b/src/bin/hamcore/strtable_cn.stb @@ -2482,7 +2482,7 @@ STATIC1 您可以更改 VPN Client 的设置 STATIC2 远程管理(&E) STATIC3 您可以通过使用 VPN Client 管理器远程模式从另一台计算机上远程管理 VPN Client 服务程序。 R_ALLOW_REMOTE_CONFIG 允许 VPN Client 服务的远程管理(&R) -S_WARNING 建议您在允许远程管理时设置密码。在菜单里选择“工具” >“设置密码”来设置密码。 +S_WARNING 如果你允许远程管理,你必须设置一个密码。在菜单里选择“工具” >“设置密码”来设置密码。必须重新启动 VPN Client 服务,以应用远程管理可用性的配置变化。 STATIC4 在通讯闲置一段时间后自动断开互联网连接的环境下,可以通过向互联网上任意主机发送假数据包的方式来保持互联网连接。 R_USE_KEEP_CONNECT 使用保持 Internet 连接功能(&K) S_HOSTNAME 主机名(&H): @@ -7028,13 +7028,13 @@ CMD_AccountImport_OK 连接设置 "%s" 已导入。 # RemoteEnable 命令 CMD_RemoteEnable 允许 VPN 客户服务的远程管理 -CMD_RemoteEnable_Help 对 VPN Client 服务,从本地主机以外的远程计算机上,允许通过命令行管理设施或 VPN Client 管理器员进行连接和管理。 +CMD_RemoteEnable_Help 对 VPN Client 服务,从本地主机以外的远程计算机上,允许通过命令行管理设施或 VPN Client 管理器员进行连接和管理。必须重新启动 VPN Client 服务,以应用远程管理可用性的配置变化。如果你允许远程管理,你必须设置一个密码。 CMD_RemoteEnable_Args RemoteEnable # RemoteDisable 命令 CMD_RemoteDisable 禁止 VPN 客户服务的远程管理 -CMD_RemoteDisable_Help 对 VPN Client 服务,从本地主机以外的远程计算机上,禁止通过命令行管理设施或 VPN Client 管理器员进行连接和管理。 +CMD_RemoteDisable_Help 对 VPN Client 服务,从本地主机以外的远程计算机上,禁止通过命令行管理设施或 VPN Client 管理器员进行连接和管理。必须重新启动 VPN 客户端服务,以应用远程管理可用性的配置变化。 CMD_RemoteDisable_Args RemoteDisable diff --git a/src/bin/hamcore/strtable_en.stb b/src/bin/hamcore/strtable_en.stb index 5634379f..be3f9aa5 100644 --- a/src/bin/hamcore/strtable_en.stb +++ b/src/bin/hamcore/strtable_en.stb @@ -2466,7 +2466,7 @@ STATIC1 You can modify the settings for VPN Client. STATIC2 R&emote Management: STATIC3 You can remotely manage the VPN Client Service Program from another computer by using VPN Client Manager Remote Mode. R_ALLOW_REMOTE_CONFIG Allow &Remote Management of VPN Client Service -S_WARNING It is recommended to set a password if you allow remote management. From the menu bar, choose Tools -> Set Password to set the password. +S_WARNING You must set a password if you allow remote management. From the menu bar, choose Tools -> Set Password to set the password. The VPN Client service must be restarted to apply the change of remote management availability. STATIC4 For environments where Internet connections will automatically be disconnected when idle, you can keep alive the Internet connection by sending dummy packets to any host on the Internet. R_USE_KEEP_CONNECT Use &Keep Alive Internet Connection Function S_HOSTNAME &Host Name: @@ -7016,13 +7016,13 @@ CMD_AccountImport_OK The VPN Connection Setting "%s" has been imported. # RemoteEnable command CMD_RemoteEnable Allow Remote Management of VPN Client Service -CMD_RemoteEnable_Help Use this to allow management of a VPN Client service from a remote computer that is not localhost, via a remote connection by Command Line Management Utility or VPN Client Manager. +CMD_RemoteEnable_Help Use this to allow management of a VPN Client service from a remote computer that is not localhost, via a remote connection by Command Line Management Utility or VPN Client Manager. The VPN Client service must be restarted to apply the change of remote management availability. You must set a password if you allow remote management. CMD_RemoteEnable_Args RemoteEnable # RemoteDisable command CMD_RemoteDisable Deny Remote Management of VPN Client Service -CMD_RemoteDisable_Help Use this to deny management of a VPN Client service from a remote computer that is not localhost, via a remote connection by Command Line Management Utility or VPN Client Manager. +CMD_RemoteDisable_Help Use this to deny management of a VPN Client service from a remote computer that is not localhost, via a remote connection by Command Line Management Utility or VPN Client Manager. The VPN Client service must be restarted to apply the change of remote management availability. CMD_RemoteDisable_Args RemoteDisable diff --git a/src/bin/hamcore/strtable_ja.stb b/src/bin/hamcore/strtable_ja.stb index 3e195742..12021c36 100644 --- a/src/bin/hamcore/strtable_ja.stb +++ b/src/bin/hamcore/strtable_ja.stb @@ -2469,7 +2469,7 @@ STATIC1 VPN Client の動作に関する設定を変更できます。 STATIC2 リモート管理の設定(&E) STATIC3 VPN Client サービスプログラムを別のコンピュータ上から VPN クライアント接続マネージャによってリモート管理することが可能です。 R_ALLOW_REMOTE_CONFIG VPN Client サービスのリモート管理を許可する(&R) -S_WARNING リモート管理を許可する場合、パスワードを設定しておくことを強くお勧めします。パスワードは [ツール] メニューの [パスワードの設定] をクリックして設定することができます。 +S_WARNING リモート管理を許可する場合、パスワードを設定する必要があります。パスワードは [ツール] メニューの [パスワードの設定] をクリックして設定することができます。リモート管理の可否の変更の設定適用には、VPN Client サービスを再起動する必要があります。 STATIC4 一定期間無通信状態が続くと接続が自動的に切断されるようなネットワーク接続環境の場合、インターネット上の任意のサーバーに対して一定間隔ごとにパケットを送信することにより、インターネット接続を維持することができます。 R_USE_KEEP_CONNECT インターネット接続の維持機能を使用する(&K) S_HOSTNAME ホスト名(&H): @@ -7022,13 +7022,13 @@ CMD_AccountImport_OK 接続設定 "%s" としてインポートしました。 # RemoteEnable コマンド CMD_RemoteEnable VPN Client サービスのリモート管理の許可 -CMD_RemoteEnable_Help VPN Client サービスに、localhost 以外のリモートコンピュータから、コマンドライン管理ユーティリティまたは VPN クライアント接続マネージャでリモート接続して管理することを許可します。 +CMD_RemoteEnable_Help VPN Client サービスに、localhost 以外のリモートコンピュータから、コマンドライン管理ユーティリティまたは VPN クライアント接続マネージャでリモート接続して管理することを許可します。注意: リモート管理の可否の変更の設定適用には、VPN Client サービスを再起動する必要があります。リモート管理を許可する場合、パスワードを設定する必要があります。 CMD_RemoteEnable_Args RemoteEnable # RemoteDisable コマンド CMD_RemoteDisable VPN Client サービスのリモート管理の禁止 -CMD_RemoteDisable_Help VPN Client サービスに、localhost 以外のリモートコンピュータからコマンドライン管理ユーティリティまたは VPN クライアント接続マネージャでリモート接続して管理することを禁止します。 +CMD_RemoteDisable_Help VPN Client サービスに、localhost 以外のリモートコンピュータからコマンドライン管理ユーティリティまたは VPN クライアント接続マネージャでリモート接続して管理することを禁止します。注意: リモート管理の可否の変更の設定適用には、VPN Client サービスを再起動する必要があります。 CMD_RemoteDisable_Args RemoteDisable