From 4b05de1a9342e59c78d9d4698397990f4476413f Mon Sep 17 00:00:00 2001 From: Davide Beatrici Date: Wed, 21 Apr 2021 08:12:45 +0200 Subject: [PATCH 1/2] Cedar: Add support for 32 bit unsigned integer Proto options This commit also fixes a bug which caused the server to initialize all boolean options to false. It was caused by SiLoadProtoCfg() not checking whether the item exists in the configuration file. CfgGetBool() always returns false if the item doesn't exist. --- src/Cedar/Admin.c | 12 ++++++++++++ src/Cedar/Command.c | 17 +++++++++++++---- src/Cedar/Proto.c | 3 +++ src/Cedar/Proto.h | 4 +++- src/Cedar/Server.c | 15 +++++++++++++-- 5 files changed, 44 insertions(+), 7 deletions(-) diff --git a/src/Cedar/Admin.c b/src/Cedar/Admin.c index 298a9881..667e9344 100644 --- a/src/Cedar/Admin.c +++ b/src/Cedar/Admin.c @@ -10239,6 +10239,9 @@ UINT StGetProtoOptions(ADMIN *a, RPC_PROTO_OPTIONS *t) case PROTO_OPTION_BOOL: rpc_option->Bool = option->Bool; break; + case PROTO_OPTION_UINT32: + rpc_option->UInt32 = option->UInt32; + break; case PROTO_OPTION_STRING: rpc_option->String = CopyStr(option->String); break; @@ -10305,6 +10308,9 @@ UINT StSetProtoOptions(ADMIN *a, RPC_PROTO_OPTIONS *t) case PROTO_OPTION_BOOL: option->Bool = rpc_option->Bool; break; + case PROTO_OPTION_UINT32: + option->UInt32 = rpc_option->UInt32; + break; case PROTO_OPTION_STRING: Free(option->String); option->String = CopyStr(rpc_option->String); @@ -12700,6 +12706,9 @@ void InRpcProtoOptions(RPC_PROTO_OPTIONS *t, PACK *p) case PROTO_OPTION_BOOL: PackGetDataEx2(p, "Value", &option->Bool, sizeof(option->Bool), i); break; + case PROTO_OPTION_UINT32: + PackGetDataEx2(p, "Value", &option->UInt32, sizeof(option->UInt32), i); + break; default: Debug("InRpcProtoOptions(): unhandled type %u!\n", option->Type); } @@ -12731,6 +12740,9 @@ void OutRpcProtoOptions(PACK *p, RPC_PROTO_OPTIONS *t) case PROTO_OPTION_BOOL: PackAddDataEx(p, "Value", &option->Bool, sizeof(option->Bool), i, t->Num); break; + case PROTO_OPTION_UINT32: + PackAddDataEx(p, "Value", &option->UInt32, sizeof(option->UInt32), i, t->Num); + break; default: Debug("OutRpcProtoOptions(): unhandled type %u!\n", option->Type); } diff --git a/src/Cedar/Command.c b/src/Cedar/Command.c index a4e1c429..bab09bf6 100644 --- a/src/Cedar/Command.c +++ b/src/Cedar/Command.c @@ -22909,6 +22909,9 @@ UINT PsProtoOptionsSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param) case PROTO_OPTION_BOOL: option->Bool = GetParamYes(o, "VALUE"); break; + case PROTO_OPTION_UINT32: + option->UInt32 = GetParamInt(o, "VALUE"); + break; default: ret = ERR_INTERNAL_ERROR; } @@ -22979,13 +22982,19 @@ UINT PsProtoOptionsGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param) switch (option->Type) { + case PROTO_OPTION_STRING: + type = L"String"; + value = CopyStrToUni(option->String); + break; case PROTO_OPTION_BOOL: type = L"Boolean"; value = option->Bool ? L"True" : L"False"; break; - case PROTO_OPTION_STRING: - type = L"String"; - value = CopyStrToUni(option->String); + case PROTO_OPTION_UINT32: + type = L"32 bit unsigned integer"; + char tmp[MAX_SIZE]; + Format(tmp, sizeof(tmp), "%u", option->UInt32); + value = CopyStrToUni(tmp); break; default: Debug("StGetProtoOptions(): unhandled option type %u!\n", option->Type); @@ -22997,7 +23006,7 @@ UINT PsProtoOptionsGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param) CtInsert(ct, name, type, value, _UU(description_str_key)); - if (option->Type == PROTO_OPTION_STRING) + if (option->Type != PROTO_OPTION_BOOL) { Free(value); } diff --git a/src/Cedar/Proto.c b/src/Cedar/Proto.c index 182cc183..3af4f386 100644 --- a/src/Cedar/Proto.c +++ b/src/Cedar/Proto.c @@ -278,6 +278,9 @@ PROTO_CONTAINER *ProtoContainerNew(const PROTO_IMPL *impl) case PROTO_OPTION_BOOL: option->Bool = impl_option->Bool; break; + case PROTO_OPTION_UINT32: + option->UInt32 = impl_option->UInt32; + break; case PROTO_OPTION_STRING: option->String = impl_option->String != NULL ? CopyStr(impl_option->String) : impl->OptionStringValue(option->Name); break; diff --git a/src/Cedar/Proto.h b/src/Cedar/Proto.h index 909e3d5a..fbbad098 100644 --- a/src/Cedar/Proto.h +++ b/src/Cedar/Proto.h @@ -25,7 +25,8 @@ typedef enum PROTO_OPTION_VALUE { PROTO_OPTION_UNKNOWN, PROTO_OPTION_STRING, - PROTO_OPTION_BOOL + PROTO_OPTION_BOOL, + PROTO_OPTION_UINT32 } PROTO_OPTION_VALUE; typedef struct PROTO @@ -44,6 +45,7 @@ struct PROTO_OPTION { bool Bool; char *String; + UINT UInt32; }; }; diff --git a/src/Cedar/Server.c b/src/Cedar/Server.c index 3d54a533..38f900e3 100644 --- a/src/Cedar/Server.c +++ b/src/Cedar/Server.c @@ -6362,11 +6362,19 @@ void SiLoadProtoCfg(PROTO *p, FOLDER *f) 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; @@ -6414,11 +6422,14 @@ void SiWriteProtoCfg(FOLDER *f, PROTO *p) 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_STRING: - CfgAddStr(ff, option->Name, option->String); + case PROTO_OPTION_UINT32: + CfgAddInt(ff, option->Name, option->UInt32); break; default: Debug("SiWriteProtoCfg(): unhandled option type %u!\n", option->Type); From 2aaf9012a04eb92875a0ccf3d4ab73eae4a9ef46 Mon Sep 17 00:00:00 2001 From: Davide Beatrici Date: Wed, 21 Apr 2021 08:29:30 +0200 Subject: [PATCH 2/2] Cedar/Proto_OpenVPN: Make timeout and ping transmission interval configurable Also, the default timeout value is set to 30000 (milliseconds) instead of 10000. The change is made because it was reported that some routers failed to connect in time. --- src/Cedar/Proto_OpenVPN.c | 21 +++++++++++++++------ src/Cedar/Proto_OpenVPN.h | 4 ++-- src/bin/hamcore/strtable_cn.stb | 2 ++ src/bin/hamcore/strtable_en.stb | 2 ++ src/bin/hamcore/strtable_ja.stb | 2 ++ src/bin/hamcore/strtable_ko.stb | 2 ++ src/bin/hamcore/strtable_pt_br.stb | 2 ++ src/bin/hamcore/strtable_ru.stb | 2 ++ src/bin/hamcore/strtable_tw.stb | 2 ++ 9 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/Cedar/Proto_OpenVPN.c b/src/Cedar/Proto_OpenVPN.c index a1779710..c97be1c4 100644 --- a/src/Cedar/Proto_OpenVPN.c +++ b/src/Cedar/Proto_OpenVPN.c @@ -57,8 +57,10 @@ const PROTO_OPTION *OvsOptions() { { .Name = "DefaultClientOption", .Type = PROTO_OPTION_STRING, .String = "dev-type tun,link-mtu 1500,tun-mtu 1500,cipher AES-128-CBC,auth SHA1,keysize 128,key-method 2,tls-client" }, { .Name = "Obfuscation", .Type = PROTO_OPTION_BOOL, .Bool = false }, - { .Name = "ObfuscationMask", .Type = PROTO_OPTION_STRING, .String = ""}, + { .Name = "ObfuscationMask", .Type = PROTO_OPTION_STRING, .String = "" }, + { .Name = "PingSendInterval", .Type = PROTO_OPTION_UINT32, .UInt32 = 3000 }, { .Name = "PushDummyIPv4AddressOnL2Mode", .Type = PROTO_OPTION_BOOL, .Bool = true }, + { .Name = "Timeout", .Type = PROTO_OPTION_UINT32, .UInt32 = 30000 }, { .Name = NULL, .Type = PROTO_OPTION_UNKNOWN } }; @@ -2344,8 +2346,8 @@ void OvsRecvPacket(OPENVPN_SERVER *s, LIST *recv_packet_list, UINT protocol) // Return the PUSH_REPLY Format(option_str, sizeof(option_str), "PUSH_REPLY,ping %u,ping-restart %u", - (OPENVPN_PING_SEND_INTERVAL / 1000), - (OPENVPN_RECV_TIMEOUT / 1000)); + s->PingSendInterval / 1000, + s->Timeout / 1000); if (se->Mode == OPENVPN_MODE_L3) { @@ -2752,11 +2754,10 @@ void OvsRecvPacket(OPENVPN_SERVER *s, LIST *recv_packet_list, UINT protocol) { if ((se->NextPingSendTick == 0) || (se->NextPingSendTick <= s->Now)) { - se->NextPingSendTick = s->Now + (UINT64)(OPENVPN_PING_SEND_INTERVAL); + se->NextPingSendTick = s->Now + s->PingSendInterval; OvsSendDataPacket(latest_channel, latest_channel->KeyId, ++latest_channel->LastDataPacketId, ping_signature, sizeof(ping_signature)); - //Debug("."); AddInterrupt(s->Interrupt, se->NextPingSendTick); } @@ -2767,7 +2768,7 @@ void OvsRecvPacket(OPENVPN_SERVER *s, LIST *recv_packet_list, UINT protocol) is_disconnected = true; } - if (se->Established && (s->Now >= (se->LastCommTick + (UINT64)OPENVPN_RECV_TIMEOUT))) + if (se->Established && (s->Now >= (se->LastCommTick + s->Timeout))) { is_disconnected = true; } @@ -2977,10 +2978,18 @@ OPENVPN_SERVER *NewOpenVpnServer(const LIST *options, CEDAR *cedar, INTERRUPT_MA { s->ObfuscationMask = CopyStr(option->String); } + else if (StrCmp(option->Name, "PingSendInterval") == 0) + { + s->PingSendInterval = option->UInt32; + } else if (StrCmp(option->Name, "PushDummyIPv4AddressOnL2Mode") == 0) { s->PushDummyIPv4AddressOnL2Mode = option->Bool; } + else if (StrCmp(option->Name, "Timeout") == 0) + { + s->Timeout = option->UInt32; + } } s->Cedar = cedar; diff --git a/src/Cedar/Proto_OpenVPN.h b/src/Cedar/Proto_OpenVPN.h index dd851cc9..cc723df0 100644 --- a/src/Cedar/Proto_OpenVPN.h +++ b/src/Cedar/Proto_OpenVPN.h @@ -26,8 +26,6 @@ #define OPENVPN_TMP_BUFFER_SIZE (65536 + 256) // Temporary buffer size -#define OPENVPN_PING_SEND_INTERVAL 3000 // Transmission interval of Ping -#define OPENVPN_RECV_TIMEOUT 10000 // Communication time-out #define OPENVPN_NEW_SESSION_DEADLINE_TIMEOUT 30000 // Grace time to complete new VPN session connection since it was created #define OPENVPN_MAX_PACKET_ID_FOR_TRIGGER_REKEY 0xFF000000 // Packet ID that is a trigger to start the re-key @@ -207,7 +205,9 @@ struct OPENVPN_SERVER char *DefaultClientOption; // Default option string to push to client bool Obfuscation; // Obfuscation enabled/disabled char *ObfuscationMask; // String (mask) for XOR obfuscation + UINT PingSendInterval; // Ping transmission interval bool PushDummyIPv4AddressOnL2Mode; // Push a dummy IPv4 address in L2 mode + UINT Timeout; // Communication timeout }; //// Function prototype diff --git a/src/bin/hamcore/strtable_cn.stb b/src/bin/hamcore/strtable_cn.stb index 3d66f5fe..a5da6e85 100644 --- a/src/bin/hamcore/strtable_cn.stb +++ b/src/bin/hamcore/strtable_cn.stb @@ -4626,7 +4626,9 @@ CMD_ProtoOptionsGet_Column_Description Description CMD_ProtoOptions_Description_OpenVPN_DefaultClientOption When OpenVPN is compiled without OCC code, it doesn't send the options string to the server. The original OpenVPN server still works, because the configuration is static. SoftEther VPN is heuristic and wants to support as many different configurations as possible. This option allows to define the string that is sent to clients built without OCC code, so that they can successfully connect. CMD_ProtoOptions_Description_OpenVPN_Obfuscation This may help an OpenVPN client bypass firewalls that are aware of the protocol and block it. The same XOR mask has to be applied client-side, otherwise it will not be able to connect with certain obfuscation methods! CMD_ProtoOptions_Description_OpenVPN_ObfuscationMask Mask used to XOR the bytes in the packet (used for certain obfuscation modes). +CMD_ProtoOptions_Description_OpenVPN_PingSendInterval Interval in milliseconds between each ping packet transmission. CMD_ProtoOptions_Description_OpenVPN_PushDummyIPv4AddressOnL2Mode There's a bug that manifests under certain circumstances on Linux. It causes the OpenVPN client to disconnect unless the TAP device is UP. This option tells the server to push a dummy IPv4 address (RFC7600) to the client, so that the TAP adapter is forced to be UP. +CMD_ProtoOptions_Description_OpenVPN_Timeout Time in milliseconds after which the session is forcifully interrupted if no packets are received from the client in the meantime. # ServerPasswordSet 命令 diff --git a/src/bin/hamcore/strtable_en.stb b/src/bin/hamcore/strtable_en.stb index 46e6f0bf..b641ec23 100644 --- a/src/bin/hamcore/strtable_en.stb +++ b/src/bin/hamcore/strtable_en.stb @@ -4608,7 +4608,9 @@ CMD_ProtoOptionsGet_Column_Description Description CMD_ProtoOptions_Description_OpenVPN_DefaultClientOption When OpenVPN is compiled without OCC code, it doesn't send the options string to the server. The original OpenVPN server still works, because the configuration is static. SoftEther VPN is heuristic and wants to support as many different configurations as possible. This option allows to define the string that is sent to clients built without OCC code, so that they can successfully connect. CMD_ProtoOptions_Description_OpenVPN_Obfuscation This may help an OpenVPN client bypass firewalls that are aware of the protocol and block it. The same XOR mask has to be applied client-side, otherwise it will not be able to connect with certain obfuscation methods! CMD_ProtoOptions_Description_OpenVPN_ObfuscationMask Mask used to XOR the bytes in the packet (used for certain obfuscation modes). +CMD_ProtoOptions_Description_OpenVPN_PingSendInterval Interval in milliseconds between each ping packet transmission. CMD_ProtoOptions_Description_OpenVPN_PushDummyIPv4AddressOnL2Mode There's a bug that manifests under certain circumstances on Linux. It causes the OpenVPN client to disconnect unless the TAP device is UP. This option tells the server to push a dummy IPv4 address (RFC7600) to the client, so that the TAP adapter is forced to be UP. +CMD_ProtoOptions_Description_OpenVPN_Timeout Time in milliseconds after which the session is forcifully interrupted if no packets are received from the client in the meantime. # ServerPasswordSet command CMD_ServerPasswordSet Set VPN Server Administrator Password diff --git a/src/bin/hamcore/strtable_ja.stb b/src/bin/hamcore/strtable_ja.stb index b6496874..dafcf9c9 100644 --- a/src/bin/hamcore/strtable_ja.stb +++ b/src/bin/hamcore/strtable_ja.stb @@ -4612,7 +4612,9 @@ CMD_ProtoOptionsGet_Column_Description 説明 CMD_ProtoOptions_Description_OpenVPN_DefaultClientOption OpenVPN の OCC codeRT 版以外の場合は、OpenVPN はサーバーに対してオプション文字列を送信しません。OpenVPN サーバーのオリジナル版は、オプションを固定で指定する仕組みになっているため、その場合でも動作します。一方、SoftEther VPN は、様々なオプションを動的に設定することができる機能を有しております。そこで、このオプションを使用することにより、OCC code なしでビルドされた OpenVPN に対してデフォルトの静的オプション文字列を送付することができるようになります。これにより、OCC code なしでビルドされた OpenVPN からの接続が成功するようになります。 CMD_ProtoOptions_Description_OpenVPN_Obfuscation OpenVPN クライアントが検閲用ファイアウォールを回避するための難読化コードを設定します。クライアント側とサーバー側では、同一の XOR マスクを設定する必要があります。コードが異なると、接続ができません。 CMD_ProtoOptions_Description_OpenVPN_ObfuscationMask パケットで使用される XOR マスクを指定します。OpenVPN クライアントが検閲用ファイアウォールを回避するための難読化コードとして使用されます。 +CMD_ProtoOptions_Description_OpenVPN_PingSendInterval Interval in milliseconds between each ping packet transmission. CMD_ProtoOptions_Description_OpenVPN_PushDummyIPv4AddressOnL2Mode Linux における特定の状況下では manifests に不具合があります。この不具合により、OpenVPN クライアントは TAP デバイスが UP 状態であるにもかかわらず、切断状態となります。このオプションを使用することにより、VPN サーバーは、ダミーの IPv4 アドレス (RFC7600 で規定) をクライアントに対してプッシュ送信することができるようになります。これにより、TAP アダプタが常に UP 状態になります。 +CMD_ProtoOptions_Description_OpenVPN_Timeout Time in milliseconds after which the session is forcifully interrupted if no packets are received from the client in the meantime. # ServerPasswordSet コマンド diff --git a/src/bin/hamcore/strtable_ko.stb b/src/bin/hamcore/strtable_ko.stb index 1f6e7a39..3a3bc9c9 100644 --- a/src/bin/hamcore/strtable_ko.stb +++ b/src/bin/hamcore/strtable_ko.stb @@ -4589,7 +4589,9 @@ CMD_ProtoOptionsGet_Column_Description Description CMD_ProtoOptions_Description_OpenVPN_DefaultClientOption When OpenVPN is compiled without OCC code, it doesn't send the options string to the server. The original OpenVPN server still works, because the configuration is static. SoftEther VPN is heuristic and wants to support as many different configurations as possible. This option allows to define the string that is sent to clients built without OCC code, so that they can successfully connect. CMD_ProtoOptions_Description_OpenVPN_Obfuscation This may help an OpenVPN client bypass firewalls that are aware of the protocol and block it. The same XOR mask has to be applied client-side, otherwise it will not be able to connect with certain obfuscation methods! CMD_ProtoOptions_Description_OpenVPN_ObfuscationMask Mask used to XOR the bytes in the packet (used for certain obfuscation modes). +CMD_ProtoOptions_Description_OpenVPN_PingSendInterval Interval in milliseconds between each ping packet transmission. CMD_ProtoOptions_Description_OpenVPN_PushDummyIPv4AddressOnL2Mode There's a bug that manifests under certain circumstances on Linux. It causes the OpenVPN client to disconnect unless the TAP device is UP. This option tells the server to push a dummy IPv4 address (RFC7600) to the client, so that the TAP adapter is forced to be UP. +CMD_ProtoOptions_Description_OpenVPN_Timeout Time in milliseconds after which the session is forcifully interrupted if no packets are received from the client in the meantime. # ServerPasswordSet 명령 diff --git a/src/bin/hamcore/strtable_pt_br.stb b/src/bin/hamcore/strtable_pt_br.stb index 5c4a2cd3..8406695c 100644 --- a/src/bin/hamcore/strtable_pt_br.stb +++ b/src/bin/hamcore/strtable_pt_br.stb @@ -4329,7 +4329,9 @@ CMD_ProtoOptionsGet_Column_Description Description CMD_ProtoOptions_Description_OpenVPN_DefaultClientOption When OpenVPN is compiled without OCC code, it doesn't send the options string to the server. The original OpenVPN server still works, because the configuration is static. SoftEther VPN is heuristic and wants to support as many different configurations as possible. This option allows to define the string that is sent to clients built without OCC code, so that they can successfully connect. CMD_ProtoOptions_Description_OpenVPN_Obfuscation This may help an OpenVPN client bypass firewalls that are aware of the protocol and block it. The same XOR mask has to be applied client-side, otherwise it will not be able to connect with certain obfuscation methods! CMD_ProtoOptions_Description_OpenVPN_ObfuscationMask Mask used to XOR the bytes in the packet (used for certain obfuscation modes). +CMD_ProtoOptions_Description_OpenVPN_PingSendInterval Interval in milliseconds between each ping packet transmission. CMD_ProtoOptions_Description_OpenVPN_PushDummyIPv4AddressOnL2Mode There's a bug that manifests under certain circumstances on Linux. It causes the OpenVPN client to disconnect unless the TAP device is UP. This option tells the server to push a dummy IPv4 address (RFC7600) to the client, so that the TAP adapter is forced to be UP. +CMD_ProtoOptions_Description_OpenVPN_Timeout Time in milliseconds after which the session is forcifully interrupted if no packets are received from the client in the meantime. # ServerPasswordSet command diff --git a/src/bin/hamcore/strtable_ru.stb b/src/bin/hamcore/strtable_ru.stb index e4f78107..7b6ba91e 100644 --- a/src/bin/hamcore/strtable_ru.stb +++ b/src/bin/hamcore/strtable_ru.stb @@ -4607,7 +4607,9 @@ CMD_ProtoOptionsGet_Column_Description Description CMD_ProtoOptions_Description_OpenVPN_DefaultClientOption When OpenVPN is compiled without OCC code, it doesn't send the options string to the server. The original OpenVPN server still works, because the configuration is static. SoftEther VPN is heuristic and wants to support as many different configurations as possible. This option allows to define the string that is sent to clients built without OCC code, so that they can successfully connect. CMD_ProtoOptions_Description_OpenVPN_Obfuscation This may help an OpenVPN client bypass firewalls that are aware of the protocol and block it. The same XOR mask has to be applied client-side, otherwise it will not be able to connect with certain obfuscation methods! CMD_ProtoOptions_Description_OpenVPN_ObfuscationMask Mask used to XOR the bytes in the packet (used for certain obfuscation modes). +CMD_ProtoOptions_Description_OpenVPN_PingSendInterval Interval in milliseconds between each ping packet transmission. CMD_ProtoOptions_Description_OpenVPN_PushDummyIPv4AddressOnL2Mode There's a bug that manifests under certain circumstances on Linux. It causes the OpenVPN client to disconnect unless the TAP device is UP. This option tells the server to push a dummy IPv4 address (RFC7600) to the client, so that the TAP adapter is forced to be UP. +CMD_ProtoOptions_Description_OpenVPN_Timeout Time in milliseconds after which the session is forcifully interrupted if no packets are received from the client in the meantime. # ServerPasswordSet command diff --git a/src/bin/hamcore/strtable_tw.stb b/src/bin/hamcore/strtable_tw.stb index 8d3dc154..5c5c3213 100644 --- a/src/bin/hamcore/strtable_tw.stb +++ b/src/bin/hamcore/strtable_tw.stb @@ -4626,7 +4626,9 @@ CMD_ProtoOptionsGet_Column_Description Description CMD_ProtoOptions_Description_OpenVPN_DefaultClientOption When OpenVPN is compiled without OCC code, it doesn't send the options string to the server. The original OpenVPN server still works, because the configuration is static. SoftEther VPN is heuristic and wants to support as many different configurations as possible. This option allows to define the string that is sent to clients built without OCC code, so that they can successfully connect. CMD_ProtoOptions_Description_OpenVPN_Obfuscation This may help an OpenVPN client bypass firewalls that are aware of the protocol and block it. The same XOR mask has to be applied client-side, otherwise it will not be able to connect with certain obfuscation methods! CMD_ProtoOptions_Description_OpenVPN_ObfuscationMask Mask used to XOR the bytes in the packet (used for certain obfuscation modes). +CMD_ProtoOptions_Description_OpenVPN_PingSendInterval Interval in milliseconds between each ping packet transmission. CMD_ProtoOptions_Description_OpenVPN_PushDummyIPv4AddressOnL2Mode There's a bug that manifests under certain circumstances on Linux. It causes the OpenVPN client to disconnect unless the TAP device is UP. This option tells the server to push a dummy IPv4 address (RFC7600) to the client, so that the TAP adapter is forced to be UP. +CMD_ProtoOptions_Description_OpenVPN_Timeout Time in milliseconds after which the session is forcifully interrupted if no packets are received from the client in the meantime. # ServerPasswordSet 命令